From d95b9eefee72a505e42cd0fe85877dc771658065 Mon Sep 17 00:00:00 2001 From: Shu Date: Sun, 4 Oct 2020 15:32:28 +0200 Subject: [PATCH] Render API --- src/client/Client.cpp | 16 +- src/client/config.hpp | 21 +- src/client/contouring/Abstract.hpp | 4 +- src/client/contouring/Dummy.hpp | 22 -- src/client/contouring/FlatDualMC.cpp | 19 +- src/client/contouring/FlatDualMC.hpp | 11 +- src/client/contouring/boxing.hpp | 58 ----- src/client/contouring/index.cpp | 26 --- src/client/contouring/index.hpp | 12 - src/client/contouring/optimizer.hpp | 12 +- src/client/render/Renderer.hpp | 7 +- src/client/render/UI.cpp | 22 +- src/client/render/UI.hpp | 2 +- src/client/render/api/Buffers.cpp | 7 + src/client/render/api/Buffers.hpp | 75 ++++++ src/client/render/api/Images.cpp | 71 ++++++ src/client/render/api/Images.hpp | 105 +++++++++ src/client/render/api/Models.cpp | 63 ++++++ src/client/render/api/Models.hpp | 109 +++++++++ src/client/render/api/common.hpp | 36 +++ src/client/render/buffer/Abstract.hpp | 14 -- src/client/render/gl/Renderer.cpp | 20 +- src/client/render/gl/Renderer.hpp | 8 +- src/client/render/gl/api/Models.cpp | 152 +++++++++++++ src/client/render/gl/api/Models.hpp | 68 ++++++ src/client/render/gl/buffer/Abstract.cpp | 38 ---- src/client/render/gl/buffer/Abstract.hpp | 27 --- src/client/render/gl/buffer/Colored.cpp | 58 ----- src/client/render/gl/buffer/Colored.hpp | 28 --- .../render/gl/buffer/LodShortIndexed.cpp | 33 --- .../render/gl/buffer/LodShortIndexed.hpp | 27 --- src/client/render/gl/buffer/ShortIndexed.cpp | 131 ----------- src/client/render/gl/buffer/ShortIndexed.hpp | 57 ----- src/client/render/gl/buffer/Vertex.cpp | 15 -- src/client/render/gl/buffer/Vertex.hpp | 18 -- src/client/render/gl/buffer/VertexData.hpp | 35 --- src/client/render/gl/buffer/vboindexer.cpp | 59 ----- src/client/render/gl/buffer/vboindexer.hpp | 15 -- src/client/render/gl/pass/ColorProgram.cpp | 3 +- src/client/render/gl/pass/ColorProgram.hpp | 2 +- src/client/render/gl/pass/EntityProgram.cpp | 6 +- src/client/render/gl/pass/EntityProgram.hpp | 2 +- src/client/render/gl/pass/Program.hpp | 1 - src/client/render/gl/pass/SkyProgram.cpp | 81 ++++--- src/client/render/gl/pass/SkyProgram.hpp | 5 +- src/client/render/gl/pass/VoxelProgram.cpp | 3 +- src/client/render/gl/pass/VoxelProgram.hpp | 2 +- src/client/render/gl/pass/WorldProgram.cpp | 4 +- src/client/render/gl/pass/WorldProgram.hpp | 2 +- src/client/render/vk/Allocator.cpp | 213 +++--------------- src/client/render/vk/Allocator.hpp | 105 ++++----- src/client/render/vk/CommandCenter.cpp | 137 ++--------- src/client/render/vk/CommandCenter.hpp | 21 +- src/client/render/vk/Pipeline.hpp | 2 +- src/client/render/vk/Renderer.cpp | 35 ++- src/client/render/vk/Renderer.hpp | 8 +- src/client/render/vk/SwapChain.hpp | 2 +- src/client/render/vk/api/Buffers.cpp | 184 +++++++++++++++ src/client/render/vk/api/Buffers.hpp | 91 ++++++++ src/client/render/vk/api/Images.cpp | 139 ++++++++++++ src/client/render/vk/api/Images.hpp | 42 ++++ src/client/render/vk/api/Memory.hpp | 31 +++ src/client/render/vk/buffer/Buffer.hpp | 27 --- src/client/render/vk/texture.cpp | 75 ------ src/client/render/vk/texture.hpp | 16 -- src/client/state.hpp | 2 +- src/client/world/DistantUniverse.cpp | 2 +- src/client/world/DistantUniverse.hpp | 2 +- src/client/world/LocalUniverse.cpp | 7 +- src/client/world/LocalUniverse.hpp | 4 +- src/client/world/Universe.cpp | 8 +- src/client/world/Universe.hpp | 10 +- src/client/world/index.cpp | 6 +- src/client/world/index.hpp | 2 +- src/server/Server.hpp | 2 +- 75 files changed, 1414 insertions(+), 1371 deletions(-) delete mode 100644 src/client/contouring/Dummy.hpp delete mode 100644 src/client/contouring/boxing.hpp delete mode 100644 src/client/contouring/index.cpp delete mode 100644 src/client/contouring/index.hpp create mode 100644 src/client/render/api/Buffers.cpp create mode 100644 src/client/render/api/Buffers.hpp create mode 100644 src/client/render/api/Images.cpp create mode 100644 src/client/render/api/Images.hpp create mode 100644 src/client/render/api/Models.cpp create mode 100644 src/client/render/api/Models.hpp create mode 100644 src/client/render/api/common.hpp delete mode 100644 src/client/render/buffer/Abstract.hpp create mode 100644 src/client/render/gl/api/Models.cpp create mode 100644 src/client/render/gl/api/Models.hpp delete mode 100644 src/client/render/gl/buffer/Abstract.cpp delete mode 100644 src/client/render/gl/buffer/Abstract.hpp delete mode 100644 src/client/render/gl/buffer/Colored.cpp delete mode 100644 src/client/render/gl/buffer/Colored.hpp delete mode 100644 src/client/render/gl/buffer/LodShortIndexed.cpp delete mode 100644 src/client/render/gl/buffer/LodShortIndexed.hpp delete mode 100644 src/client/render/gl/buffer/ShortIndexed.cpp delete mode 100644 src/client/render/gl/buffer/ShortIndexed.hpp delete mode 100644 src/client/render/gl/buffer/Vertex.cpp delete mode 100644 src/client/render/gl/buffer/Vertex.hpp delete mode 100644 src/client/render/gl/buffer/VertexData.hpp delete mode 100644 src/client/render/gl/buffer/vboindexer.cpp delete mode 100644 src/client/render/gl/buffer/vboindexer.hpp create mode 100644 src/client/render/vk/api/Buffers.cpp create mode 100644 src/client/render/vk/api/Buffers.hpp create mode 100644 src/client/render/vk/api/Images.cpp create mode 100644 src/client/render/vk/api/Images.hpp create mode 100644 src/client/render/vk/api/Memory.hpp delete mode 100644 src/client/render/vk/buffer/Buffer.hpp delete mode 100644 src/client/render/vk/texture.cpp delete mode 100644 src/client/render/vk/texture.hpp diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 7b20a31..5a3b6d4 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -27,9 +27,7 @@ void Client::run(server_handle* const localHandle) { pipeline->LightInvDir = glm::normalize(glm::vec3(-.5f, 2, -2)); render::Renderer::Get()->loadUI(window); - auto world = world::client::Load(options.connection, localHandle, options.world); - - world->setContouring(contouring::load(options.contouring.idx, options.contouring.data)); + auto world = world::client::Load(options.connection, localHandle, options.world, options.contouring); state.contouring = world->getContouring(); //TODO: loop @@ -115,10 +113,8 @@ void Client::run(server_handle* const localHandle) { if(actions && render::UI::Actions::Control) { player.setOptions(options.control); } - if(actions && render::UI::Actions::ChangeContouring) { - state.contouring = NULL; - world->setContouring(contouring::load(options.contouring.idx, options.contouring.data)); - state.contouring = world->getContouring(); + if(actions && render::UI::Actions::FillMode) { + //TODO: pipeline->setFillMode(options.renderer.wireframe); } } { // Rendering @@ -134,10 +130,10 @@ void Client::run(server_handle* const localHandle) { const auto offset = state.position.raw_as_long(); { // Chunks const auto pass = pipeline->beginWorldPass(); - const auto draw = [&](glm::mat4 model, buffer::Abstract *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) { + const auto draw = [&](glm::mat4 model, render::LodModel *const buffer, const contouring::Abstract::area_info &area, const voxel_pos &pos) { pipeline->setCurvature(glm::vec4(pos, std::get<1>(area)), std::get<2>(area)); reports.models_count++; - reports.tris_count += buffer->draw(pass(model)); + reports.tris_count += pass(buffer, model); }; if (options.culling > 0) { std::vector occlusion; @@ -188,5 +184,5 @@ void Client::run(server_handle* const localHandle) { render::Renderer::Unload(); window.destroy(); - contouring::save(options.contouring.idx, state.contouring, options.contouring.data); + options.contouring = state.contouring->getOptions(); } \ No newline at end of file diff --git a/src/client/config.hpp b/src/client/config.hpp index 9fb710f..44ebea9 100644 --- a/src/client/config.hpp +++ b/src/client/config.hpp @@ -6,7 +6,7 @@ #include #include "world/Universe.hpp" #include "render/Renderer.hpp" -#include "contouring/index.hpp" +#include "contouring/Abstract.hpp" #include "control/Camera.hpp" namespace config::client { @@ -50,10 +50,7 @@ public: renderer.voxel.curv_depth = config["render"]["curvature_depth"].value_or(renderer.voxel.curv_depth); culling = config["render"]["culling"].value_or(culling); - contouring.idx = contouring::idxByName(config["contouring"]["mode"].value_or(std::string(""))); - for(const auto& name: contouring::names) { - contouring.data.emplace(name, config["contouring"]["options"][name].value_or(std::string(""))); - } + contouring = config["contouring"].value_or(std::string("")); camera.far = config["camera"]["far"].value_or(camera.far); camera.near = config["camera"]["near"].value_or(camera.near); @@ -120,14 +117,7 @@ public: {"curvature_depth", renderer.voxel.curv_depth}, {"culling", culling} })); - config.insert_or_assign("contouring", toml::table({ - {"mode", contouring::names[contouring.idx]}, - {"options", toml::table()} - })); - for(const auto& [key, val]: contouring.data) { - if(!val.empty()) - config["contouring"]["options"].as_table()->insert_or_assign(key, val); - } + config.insert_or_assign("contouring", contouring); config.insert_or_assign("camera", toml::table({ {"far", camera.far}, {"near", camera.near}, @@ -199,10 +189,7 @@ public: render::renderOptions renderer; int culling = 0; - struct { - int idx; - std::map data; - } contouring; + std::string contouring; Controllable::options control; Camera::options camera; diff --git a/src/client/contouring/Abstract.hpp b/src/client/contouring/Abstract.hpp index 1cb5fb3..de8f776 100644 --- a/src/client/contouring/Abstract.hpp +++ b/src/client/contouring/Abstract.hpp @@ -1,11 +1,11 @@ #pragma once -#include "../render/gl/buffer/Abstract.hpp" #include "../../core/world/forward.h" #include "../../core/geometry/Frustum.hpp" #include "../../core/geometry/Ray.hpp" #include "../../core/geometry/Faces.hpp" +namespace render { class LodModel; } /// Mesh creation (from world to render) namespace contouring { /// Generating mesh from world data @@ -35,7 +35,7 @@ namespace contouring { virtual size_t getQueueSize() = 0; using area_info = std::tuple; - using draw_call = const std::function &; + using draw_call = const std::function &; /// Get buffers in frustum with model matrices /// @note buffers invalidated after update diff --git a/src/client/contouring/Dummy.hpp b/src/client/contouring/Dummy.hpp deleted file mode 100644 index 5c4cf69..0000000 --- a/src/client/contouring/Dummy.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "Abstract.hpp" - -namespace contouring { - /// Useless contouring - class Dummy: public Abstract { - public: - Dummy(): Abstract() { } - virtual ~Dummy() { } - - void update(const voxel_pos &, const world::client::area_map &) override {} - void onUpdate(const area_ &, const chunk_pos &, const world::ChunkContainer &, geometry::Faces) override {} - void onNotify(const area_ &, const chunk_pos &, const world::ChunkContainer &) override {} - void onGui() override { } - std::string getOptions() const override { return ""; } - std::pair getFarRange() const override { return std::make_pair(0, 0); } - size_t getQueueSize() override { return 0; } - void getModels(draw_call, const std::optional &, const glm::llvec3 &, int) override {} - void getModels(draw_call, const glm::ifvec3 &, float, const std::vector &, const glm::llvec3 &, int) override {} - }; -} \ No newline at end of file diff --git a/src/client/contouring/FlatDualMC.cpp b/src/client/contouring/FlatDualMC.cpp index 77e32ee..63b3e43 100644 --- a/src/client/contouring/FlatDualMC.cpp +++ b/src/client/contouring/FlatDualMC.cpp @@ -41,14 +41,15 @@ namespace contouring { #if TRACY_ENABLE tracy::SetThreadName("Contouring"); #endif - std::vector tmp; + std::vector tmp; while (running) { std::pair, surrounding::corners> ctx; loadQueue.wait(); if (loadQueue.pop(ctx)) { ZoneScopedN("ProcessContouring"); - buffer::LodShortIndexed::LodData data; + render::LodModel::LodData data; render(ctx.second, data, tmp); + //TODO: direct upload with vulkan loadedQueue.emplace(ctx.first, data); } } @@ -121,12 +122,12 @@ namespace contouring { void FlatDualMC::update(const voxel_pos& pos, const world::client::area_map& areas) { ZoneScopedN("Ct"); - std::pair, buffer::LodShortIndexed::LodData> out; + std::pair, render::LodModel::LodData> out; TracyPlot("CtLoad", static_cast(loadQueue.size())); //MAYBE: clear out of range loadQueue.trim(keepDistance * keepDistance) TracyPlot("CtLoaded", static_cast(loadedQueue.size())); for(auto handle = loadedQueue.extractor(); handle.first(out);) { - const auto buffer = out.second.first.empty() ? NULL : new buffer::LodShortIndexed(GL_TRIANGLES, out.second); + const auto buffer = out.second.first.empty() ? NULL : render::LodModel::Create(out.second).release(); auto &bfs = buffers[out.first.first].second; //NOTE: buffer.first uninitialized (will be set in clear()) if (const auto it = bfs.find(out.first.second); it != bfs.end()) { if(it->second != NULL) @@ -163,7 +164,7 @@ namespace contouring { it = bfs.erase(it); } else { if(it->second != NULL) { - static_cast(it->second)->setLevel(std::clamp((1+lod_quality-distRatio)*levelMax*(1+lod_strength), 0, levelMax)); + it->second->setLevel(std::clamp((1+lod_quality-distRatio)*levelMax*(1+lod_strength), 0, levelMax)); buffer_count++; } ++it; @@ -212,7 +213,7 @@ namespace contouring { } } - void FlatDualMC::render(const surrounding::corners &surrounding, buffer::LodShortIndexed::LodData &out, std::vector &tmp) const { + void FlatDualMC::render(const surrounding::corners &surrounding, render::LodModel::LodData &out, std::vector &tmp) const { const int SIZE = CHUNK_LENGTH + 3; std::array::Point, SIZE * SIZE * SIZE> grid; { @@ -255,7 +256,7 @@ namespace contouring { tmp.reserve(dmc_vertices.size()); constexpr auto HALF_MANTISSA = 10; std::transform(dmc_vertices.begin(), dmc_vertices.end(), std::back_inserter(tmp), [](const dualmc::Vertex &v) { - return buffer::VertexData(glm::vec3(meshopt_quantizeFloat(v.x, HALF_MANTISSA),meshopt_quantizeFloat(v.y, HALF_MANTISSA), + return render::VertexData(glm::vec3(meshopt_quantizeFloat(v.x, HALF_MANTISSA),meshopt_quantizeFloat(v.y, HALF_MANTISSA), meshopt_quantizeFloat(v.z, HALF_MANTISSA)), v.w, glm::vec3(0)); }); @@ -285,8 +286,8 @@ namespace contouring { } out.second = simplify_lod(data.indices, tmp, loadedLevels); - std::transform(tmp.begin(), tmp.end(), std::back_inserter(data.vertices), [](const buffer::VertexData &v) { - return buffer::PackedVertexData(meshopt_quantizeHalf(v.Position.x), meshopt_quantizeHalf(v.Position.y), + std::transform(tmp.begin(), tmp.end(), std::back_inserter(data.vertices), [](const render::VertexData &v) { + return render::PackedVertexData(meshopt_quantizeHalf(v.Position.x), meshopt_quantizeHalf(v.Position.y), meshopt_quantizeHalf(v.Position.z), v.Material, meshopt_quantizeHalf(v.Normal.x), meshopt_quantizeHalf(v.Normal.y), meshopt_quantizeHalf(v.Normal.z)); diff --git a/src/client/contouring/FlatDualMC.hpp b/src/client/contouring/FlatDualMC.hpp index b65433e..add65f0 100644 --- a/src/client/contouring/FlatDualMC.hpp +++ b/src/client/contouring/FlatDualMC.hpp @@ -5,14 +5,14 @@ #include "../../core/data/safe_queue.hpp" #include "../../core/data/safe_priority_queue.hpp" -#include "../render/gl/buffer/LodShortIndexed.hpp" +#include "../render/api/Models.hpp" #include "../../core/data/math.hpp" #include using namespace data; namespace contouring { /// Dual Marching Cube 1:1 contouring - class FlatDualMC: public Abstract { + class FlatDualMC final: public Abstract { public: FlatDualMC(const std::string&); virtual ~FlatDualMC(); @@ -39,10 +39,11 @@ namespace contouring { void getModels(draw_call draw, const glm::ifvec3 &from, float far, const std::vector &occlusion, const glm::llvec3 &offset, int density) override; protected: - robin_hood::unordered_map>> buffers; + //FIXME: use unique_ptr + robin_hood::unordered_map>> buffers; safe_priority_queue_map, surrounding::corners, int, area_hash> loadQueue; - safe_queue, buffer::LodShortIndexed::LodData>> loadedQueue; + safe_queue, render::LodModel::LodData>> loadedQueue; bool running = true; std::vector workers; @@ -61,6 +62,6 @@ namespace contouring { std::vector> loadedLevels; - void render(const surrounding::corners &surrounding, buffer::LodShortIndexed::LodData& out, std::vector& tmp) const; + void render(const surrounding::corners &surrounding, render::LodModel::LodData& out, std::vector& tmp) const; }; } diff --git a/src/client/contouring/boxing.hpp b/src/client/contouring/boxing.hpp deleted file mode 100644 index 1346535..0000000 --- a/src/client/contouring/boxing.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include -#include -#include "../data/geometry/Faces.hpp" -#include "../render/buffer/VertexData.hpp" - -using namespace geometry; -namespace contouring::box { - static const auto BOX_FACES = 6; - - static const std::vector g_quad_vertices = { - glm::vec3(0.5f, 0.5f, 0.5f), glm::vec3(0.5f, -0.5f, 0.5f), glm::vec3(0.5f, -0.5f, -0.5f), - glm::vec3(0.5f, -0.5f, -0.5f), glm::vec3(0.5f, 0.5f, -0.5f), glm::vec3(0.5f, 0.5f, 0.5f)}; - - static const glm::vec3 g_cube_normals[BOX_FACES] = { - glm::vec3(1, 0, 0), glm::vec3(-1, 0, 0), glm::vec3(0, 1, 0), glm::vec3(0, -1, 0), glm::vec3(0, 0, 1), glm::vec3(0, 0, -1)}; - - static const glm::mat4 g_cube_rotate[BOX_FACES] = { - glm::mat4(1), - glm::rotate(glm::mat4(1), glm::pi(), glm::vec3(0, 1, 0)), - glm::rotate(glm::mat4(1), glm::half_pi(), glm::vec3(0, 0, 1)), - glm::rotate(glm::mat4(1), glm::half_pi(), glm::vec3(0, 0, -1)), - glm::rotate(glm::mat4(1), glm::half_pi(), glm::vec3(0, -1, 0)), - glm::rotate(glm::mat4(1), glm::half_pi(), glm::vec3(0, 1, 0)), - }; - - static void addQuad(std::vector & out, glm::vec3 position, ushort texture, Face face, glm::vec3 size) { - for (auto vertex : g_quad_vertices) { - const auto p = glm::vec3(g_cube_rotate[static_cast(face)] * glm::vec4(vertex, 1)) * size + position; - out.emplace_back(meshopt_quantizeHalf(p.x), meshopt_quantizeHalf(p.y), - meshopt_quantizeHalf(p.z), texture, - meshopt_quantizeHalf(g_cube_normals[static_cast(face)].x), meshopt_quantizeHalf(g_cube_normals[static_cast(face)].y), - meshopt_quantizeHalf(g_cube_normals[static_cast(face)].z)); - } - } - - static void addCube(std::vector& out, glm::vec3 position, uint texture, Faces faces = Faces::All, glm::vec3 size = glm::vec3(1)) { - if (faces && Faces::Right) - addQuad(out, position, texture, Face::Right, size); - - if(faces && Faces::Left) - addQuad(out, position, texture, Face::Left, size); - - if (faces && Faces::Up) - addQuad(out, position, texture, Face::Up, size); - - if (faces && Faces::Down) - addQuad(out, position, texture, Face::Down, size); - - if (faces && Faces::Forward) - addQuad(out, position, texture, Face::Forward, size); - - if (faces && Faces::Backward) - addQuad(out, position, texture, Face::Backward, size); - } -} diff --git a/src/client/contouring/index.cpp b/src/client/contouring/index.cpp deleted file mode 100644 index 4f83368..0000000 --- a/src/client/contouring/index.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "index.hpp" -#include "Dummy.hpp" -#include "FlatDualMC.hpp" - -namespace contouring { - int idxByName(const std::string& name) { - for (size_t i = 0; i < names.size(); i++) { - if(name == names[i]) - return (int)i; - } - return 0; - } - - std::shared_ptr load(int idx, const std::map& data) { - switch (idx) { - case 2: - return std::make_shared(); - - default: - return std::make_shared(data.at(names[0])); - } - } - void save(int idx, std::shared_ptr& ct, std::map& data) { - data.insert_or_assign(names[idx], ct->getOptions()); - } -} \ No newline at end of file diff --git a/src/client/contouring/index.hpp b/src/client/contouring/index.hpp deleted file mode 100644 index f3ab07b..0000000 --- a/src/client/contouring/index.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Abstract.hpp" -#include - -namespace contouring { - static const std::array names = {"FlatDualMC", "Dummy"}; - - int idxByName(const std::string &name); - std::shared_ptr load(int idx, const std::map &data); - void save(int idx, std::shared_ptr &ct, std::map &data); -} \ No newline at end of file diff --git a/src/client/contouring/optimizer.hpp b/src/client/contouring/optimizer.hpp index 80a78ef..21d2a5e 100644 --- a/src/client/contouring/optimizer.hpp +++ b/src/client/contouring/optimizer.hpp @@ -1,23 +1,23 @@ #pragma once #include -inline void optimize_fetch(buffer::ShortIndexed::Data& out) { +inline void optimize_fetch(render::Model::Data& out) { ZoneScopedN("Optimize"); std::vector remap(out.indices.size()); - size_t vertex_count = meshopt_optimizeVertexFetch(out.vertices.data(), out.indices.data(), out.indices.size(), out.vertices.data(), out.vertices.size(), sizeof(buffer::PackedVertexData)); - out.vertices.resize(vertex_count, buffer::PackedVertexData(0, 0, 0, 0, 0, 0, 0)); + size_t vertex_count = meshopt_optimizeVertexFetch(out.vertices.data(), out.indices.data(), out.indices.size(), out.vertices.data(), out.vertices.size(), sizeof(render::PackedVertexData)); + out.vertices.resize(vertex_count, render::PackedVertexData(0, 0, 0, 0, 0, 0, 0)); } //MAYBE: when networking meshopt_encodeVertexBuffer template -inline void simplify_buffer(std::vector &out, const std::vector &indices, const std::vector& vertices, float threshold = .2f, float target_error = 1e-2f) { +inline void simplify_buffer(std::vector &out, const std::vector &indices, const std::vector& vertices, float threshold = .2f, float target_error = 1e-2f) { out.resize(indices.size()); - out.resize(meshopt_simplify(out.data(), indices.data(), indices.size(), &vertices.front().Position.x, vertices.size(), sizeof(buffer::VertexData), indices.size() * threshold, target_error)); + out.resize(meshopt_simplify(out.data(), indices.data(), indices.size(), &vertices.front().Position.x, vertices.size(), sizeof(render::VertexData), indices.size() * threshold, target_error)); } #include template -inline std::vector simplify_lod(std::vector &indices, const std::vector &vertices, const std::vector> &levels) +inline std::vector simplify_lod(std::vector &indices, const std::vector &vertices, const std::vector> &levels) { ZoneScopedN("LOD"); typename std::vector full(indices); diff --git a/src/client/render/Renderer.hpp b/src/client/render/Renderer.hpp index fabf8a1..a6c994a 100644 --- a/src/client/render/Renderer.hpp +++ b/src/client/render/Renderer.hpp @@ -1,7 +1,6 @@ #pragma once #include "../../core/flags.hpp" -#include "buffer/Abstract.hpp" #include #include #include @@ -11,6 +10,8 @@ class Window; class Camera; namespace render { +class Model; +class LodModel; /// Pass options struct passOptions { @@ -63,9 +64,9 @@ public: /// Start new frame and setup virtual void beginFrame() = 0; /// Get started world program - virtual std::function beginWorldPass() = 0; + virtual std::function beginWorldPass() = 0; /// Get started entity program - virtual std::function &)> beginEntityPass() = 0; + virtual std::function &)> beginEntityPass() = 0; /// Draw cube indicator virtual size_t drawIndicatorCube(glm::mat4 model) = 0; /// Apply postprocessing diff --git a/src/client/render/UI.cpp b/src/client/render/UI.cpp index 0c42033..4763be6 100644 --- a/src/client/render/UI.cpp +++ b/src/client/render/UI.cpp @@ -102,8 +102,9 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons if (ImGui::ColorEdit3("Fog color", &options.renderer.clear_color[0])) { actions |= Actions::ClearColor; } - if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe)) - glPolygonMode(GL_FRONT_AND_BACK, options.renderer.wireframe ? GL_LINE : GL_FILL); + if (ImGui::Checkbox("Wireframe", &options.renderer.wireframe)) { + actions |= Actions::FillMode; + } ImGui::Text("Textures '%s'", options.renderer.textures.c_str()); // MAYBE: select if (ImGui::SliderFloat("LOD", &options.renderer.mipMapLOD, -1, 1) | ImGui::SliderInt("Anisotropy", &options.renderer.anisotropy, 0, 8)) { @@ -130,23 +131,6 @@ UI::Actions UI::draw(config::client::options &options, state::state &state, cons if (options.debugMenu.contouring) { ImGui::Begin("Debug: Contouring", &options.debugMenu.contouring, ImGuiWindowFlags_AlwaysAutoResize); - if (ImGui::BeginCombo("Contouring", contouring::names[options.contouring.idx].c_str())) { - for (size_t i = 0; i < contouring::names.size(); i++) { - const bool is_selected = (options.contouring.idx == (int)i); - if (ImGui::Selectable(contouring::names[i].c_str(), is_selected)) { - actions |= Actions::ChangeContouring; - contouring::save(options.contouring.idx, state.contouring, options.contouring.data); - options.contouring.idx = i; - } - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - if(ImGui::Button("Reload")) { - actions |= Actions::ChangeContouring; - contouring::save(options.contouring.idx, state.contouring, options.contouring.data); - } ImGui::SliderInt("Culling", &options.culling, -1, 10, options.culling > 0 ? "Occlusion %d" : (options.culling < 0 ? "None" : "Frustum")); state.contouring->onGui(); ImGui::End(); diff --git a/src/client/render/UI.hpp b/src/client/render/UI.hpp index 6abc6ac..a959656 100644 --- a/src/client/render/UI.hpp +++ b/src/client/render/UI.hpp @@ -31,7 +31,7 @@ public: World = 1 << 5, Camera = 1 << 6, Control = 1 << 7, - ChangeContouring = 1 << 8, + FillMode = 1 << 8, }; friend inline void operator|=(Actions& a, Actions b) { a = static_cast(static_cast(a) | static_cast(b)); diff --git a/src/client/render/api/Buffers.cpp b/src/client/render/api/Buffers.cpp new file mode 100644 index 0000000..69e0494 --- /dev/null +++ b/src/client/render/api/Buffers.cpp @@ -0,0 +1,7 @@ +#include "Buffers.hpp" + +using namespace render; + +std::unique_ptr (*WritableBuffer::createFunc)(size_t, Usage, const data_view) = nullptr; +std::unique_ptr (*FastBuffer::createFunc)(size_t, Usage, const data_view) = nullptr; +std::unique_ptr (*ShortIndexedVertexBuffer::createFunc)(const data_view, const data_view) = nullptr; \ No newline at end of file diff --git a/src/client/render/api/Buffers.hpp b/src/client/render/api/Buffers.hpp new file mode 100644 index 0000000..55b7f9b --- /dev/null +++ b/src/client/render/api/Buffers.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "common.hpp" + +namespace render { + +/// Abstract raw data buffer +class Buffer { +public: + virtual ~Buffer() { } + + // NOTE: matches VkBufferUsageFlags + enum class Usage { + TRANSFER_SRC = 1, + TRANSFER_DST = 2, + UNIFORM = 16, + STORAGE = 32, + INDEX = 64, + VERTEX = 128 + }; + friend inline Usage operator|(Usage a, Usage b) { + return static_cast(static_cast(a) | static_cast(b)); + } + + struct requirement { + requirement(size_t size, Usage usage, const data_view view = data_view()): + size(size), usage(usage), view(view) { } + + size_t size; + Usage usage; + data_view view; + }; +}; + +/// Writable raw data buffer +class WritableBuffer: public Buffer { +public: + static _FORCE_INLINE_ std::unique_ptr Create(size_t size, Usage usage = Usage::TRANSFER_SRC, const data_view write = data_view()) { + assert(createFunc != nullptr && "Uninitialized renderer"); + return createFunc(size, usage, write); + } + + virtual void write(const data_view, size_t offset = 0) = 0; + virtual void read(data_ref, size_t offset = 0) = 0; + +protected: + static std::unique_ptr (*createFunc)(size_t, Usage, const data_view); +}; + +/// Fast raw data buffer +class FastBuffer: public Buffer { +public: + // NOTE: implementation may implicitly add Usage::TRANSFER_DST + static _FORCE_INLINE_ std::unique_ptr Create(size_t size, Usage usage, const data_view write = data_view()) { + assert(createFunc != nullptr && "Uninitialized renderer"); + return createFunc(size, usage, write); + } + +protected: + static std::unique_ptr (*createFunc)(size_t, Usage, const data_view); +}; + +/// Grouped vertex and u16 index buffers +/// NOTE: vertex structure is undefined +class ShortIndexedVertexBuffer: public Buffer { +public: + static _FORCE_INLINE_ std::unique_ptr Create(const data_view vertices, const data_view indices) { + assert(createFunc != nullptr && "Uninitialized renderer"); + return createFunc(vertices, indices); + } + +protected: + static std::unique_ptr (*createFunc)(const data_view, const data_view); +}; +} \ No newline at end of file diff --git a/src/client/render/api/Images.cpp b/src/client/render/api/Images.cpp new file mode 100644 index 0000000..be4e2e9 --- /dev/null +++ b/src/client/render/api/Images.cpp @@ -0,0 +1,71 @@ +#include "Images.hpp" + +using namespace render; + +std::unique_ptr (*Texture::loadFunc)(const std::string&, const sampling&) = nullptr; + +#include +#include +#include + +#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII +#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII +#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII + +std::optional Image::Read(const std::string& imagepath, std::vector& data) { + + unsigned char header[124]; + properties info; + + FILE *fp; + + /* try to open the file */ + fp = fopen(imagepath.c_str(), "rb"); + if (fp == NULL){ + printf("%s could not be opened.\n", imagepath.c_str()); getchar(); + return {}; + } + + /* verify the type of file */ + char filecode[4]; + fread(filecode, 1, 4, fp); + if (strncmp(filecode, "DDS ", 4) != 0) { + fclose(fp); + return {}; + } + + /* get the surface desc */ + fread(&header, 124, 1, fp); + + info.size.height = *(unsigned int*)&(header[8 ]); + info.size.width = *(unsigned int*)&(header[12]); + unsigned int linearSize = *(unsigned int*)&(header[16]); + info.mipMap = *(unsigned int*)&(header[24]); + unsigned int fourCC = *(unsigned int*)&(header[80]); + + + /* how big is it going to be including all mipmaps? */ + unsigned int bufsize = info.mipMap > 1 ? linearSize * 2 : linearSize; + data.resize(bufsize); + fread(data.data(), 1, bufsize, fp); + /* close the file pointer */ + fclose(fp); + + switch(fourCC) + { + case FOURCC_DXT1: + info.format = Format::BC1; + break; + case FOURCC_DXT3: + info.format = Format::BC2; + break; + case FOURCC_DXT5: + info.format = Format::BC3; + break; + //MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK + default: + return {}; + } + + return info; +} \ No newline at end of file diff --git a/src/client/render/api/Images.hpp b/src/client/render/api/Images.hpp new file mode 100644 index 0000000..fdb5a8d --- /dev/null +++ b/src/client/render/api/Images.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include "common.hpp" +#include +#include + +namespace render { + +/// Abstract raw image +class Image { +public: + virtual ~Image() { } + + struct frame { + uint32_t height; + uint32_t width; + }; + // NOTE: matches VkFormat + enum class Format { + /// DXT1 RGBA SRGB + BC1 = 134, + /// DXT3 RGBA SRGB + BC2 = 136, + /// DXT1 RGBA SRGB + BC3 = 138, + // MAYBE: BMP RGBA SRGB ?? + // MAYBE: For HDR BC6H_SFLOAT = 144, + }; + // NOTE: matches VkImageLayout + enum class Layout { + UNDEFINED = 0, + GENERAL = 1, + COLOR_ATTACHMENT = 2, + DEPTH_STENCIL_ATTACHMENT = 3, + DEPTH_STENCIL_READ_ONLY = 4, + SHADER_READ_ONLY = 5, + TRANSFER_SRC = 6, + TRANSFER_DST = 7, + PREINITIALIZED = 8, + DEPTH_READ_ONLY_STENCIL_ATTACHMENT = 1000117000, + DEPTH_ATTACHMENT_STENCIL_READ_ONLY = 1000117001, + DEPTH_ATTACHMENT = 1000241000, + DEPTH_READ_ONLY = 1000241001, + STENCIL_ATTACHMENT = 1000241002, + STENCIL_READ_ONLY = 1000241003 + }; + // NOTE: matches VkImageUsageFlags + enum class Usage { + TRANSFER_SRC = 0x00000001, + TRANSFER_DST = 0x00000002, + SAMPLED = 0x00000004, + STORAGE = 0x00000008, + COLOR_ATTACHMENT = 0x00000010, + DEPTH_STENCIL_ATTACHMENT = 0x00000020, + TRANSIENT_ATTACHMENT = 0x00000040, + INPUT_ATTACHMENT = 0x00000080, + }; + friend inline Usage operator|(Usage a, Usage b) { + return static_cast(static_cast(a) | static_cast(b)); + } + + struct properties { + frame size; + uint32_t mipMap; + Format format; + }; + struct requirement { + properties props; + Layout layout; + Usage usage; + bool linear = false; + }; + + static std::optional Read(const std::string&, std::vector& data); +}; + +/// Const image (single texture2D) with sampler +class Texture: public Image { +public: + // NOTE: matches VkSamplerAddressMode + enum class Wrap { + REPEAT = 0, + MIRRORED_REPEAT = 1, + CLAMP_TO_EDGE = 2, + CLAMP_TO_BORDER = 3, + }; + struct sampling { + bool magLinear = true; + bool minLinear = true; + Wrap wrap = Wrap::MIRRORED_REPEAT; + int anisotropy = 0; + //TODO: mipmap + }; + + /// Only supports dds files + /// DXT1(BC1) DXT3(BC2) DXT5(BC3) + static _FORCE_INLINE_ std::unique_ptr LoadFromFile(const std::string &path, const sampling &props) { + assert(loadFunc != nullptr && "Uninitialized renderer"); + return loadFunc(path, props); + } + +protected: + static std::unique_ptr (*loadFunc)(const std::string&, const sampling&); +}; +} \ No newline at end of file diff --git a/src/client/render/api/Models.cpp b/src/client/render/api/Models.cpp new file mode 100644 index 0000000..d3ae584 --- /dev/null +++ b/src/client/render/api/Models.cpp @@ -0,0 +1,63 @@ +#include "Models.hpp" +#include +#include + +using namespace render; + +std::unique_ptr (*Model::createFunc)(const Data&) = nullptr; +std::unique_ptr (*LodModel::createFunc)(const LodData&) = nullptr; + +void indexVBO(const std::vector &in_vertices, std::vector &out_indices, std::vector &out_vertices); + +Model::Data::Data(const std::vector &vs, const std::vector &indices): indices(indices), vertices(vs) { } +Model::Data::Data(std::ifstream& in) { + { + size_t i_size; + in.read(reinterpret_cast(&i_size), sizeof(i_size)); + indices.resize(i_size); + in.read(reinterpret_cast(indices.data()), sizeof(glm::u16) * i_size); + } + size_t v_size; + in.read(reinterpret_cast(&v_size), sizeof(v_size)); + vertices.resize(v_size, PackedVertexData(0, 0, 0, 0, 0, 0, 0, 0)); + in.read(reinterpret_cast(vertices.data()), sizeof(PackedVertexData) * v_size); +} +void Model::Data::serialize(std::ofstream& out) { + { + size_t i_size = indices.size(); + out.write(reinterpret_cast(&i_size), sizeof(i_size)); + out.write(reinterpret_cast(indices.data()), sizeof(glm::u16) * i_size); + } + size_t v_size = vertices.size(); + out.write(reinterpret_cast(&v_size), sizeof(v_size)); + out.write(reinterpret_cast(vertices.data()), sizeof(PackedVertexData) * v_size); +} +void Model::Data::index(const std::vector& vs) { + indexVBO(vs, indices, vertices); +} + +void indexVBO(const std::vector &in_vertices, std::vector &out_indices, + std::vector &out_vertices) +{ + std::map VertexToOutIndex; + + auto getSimilarVertexIndex_fast = [&] (const PackedVertexData &packed, glm::u16 &out) { + if (auto it = VertexToOutIndex.find(packed); it == VertexToOutIndex.end()) { + return false; + }else{ + out = it->second; + return true; + } + }; + + out_indices.reserve(in_vertices.size()); + for (const auto& vertex: in_vertices) { + if (glm::u16 index; getSimilarVertexIndex_fast(vertex, index)) { + out_indices.push_back(index); + } else { + out_vertices.push_back(vertex); + out_indices.push_back(out_vertices.size() - 1); + VertexToOutIndex[vertex] = out_indices.back(); + } + } +} \ No newline at end of file diff --git a/src/client/render/api/Models.hpp b/src/client/render/api/Models.hpp new file mode 100644 index 0000000..8109ff4 --- /dev/null +++ b/src/client/render/api/Models.hpp @@ -0,0 +1,109 @@ +/** + * Application specific vertex objects. + */ +#pragma once + +#include "common.hpp" +#include +#include +#include +#include + +namespace render { + +/// Vertex properties +struct VertexData { + VertexData(const glm::vec3 &position, glm::u16 material, const glm::vec3 &normal): + Position(position), Material(material), Normal(normal) { } + glm::vec3 Position; + glm::u16 Material; + glm::vec3 Normal; +}; + +/// Quantized vertex properties +struct PackedVertexData { + PackedVertexData(glm::u16 x, glm::u16 y, glm::u16 z, glm::u16 mat, glm::u16 nx, glm::u16 ny, glm::u16 nz, glm::u16 nw = 0) { + PosMat[0] = x; + PosMat[1] = y; + PosMat[2] = z; + PosMat[3] = mat; + Nrm[0] = nx; + Nrm[1] = ny; + Nrm[2] = nz; + Nrm[3] = nw; + } + glm::u16 PosMat[4]; + glm::u16 Nrm[4]; //NOTE: Triplanar does not handle 10_10_10_2_REV + bool operator<(const PackedVertexData that) const { + return memcmp((void *)this, (void *)&that, sizeof(PackedVertexData)) > 0; + }; +}; + +/// Color lines model +class Indicator { +public: + virtual ~Indicator() { } +}; + +/// VertexData model with index +class Model { +public: + virtual ~Model() { } + + /// Preindexed buffer data + struct Data { + std::vector indices; + std::vector vertices; + + Data() { } + Data(const std::vector &vertices, const std::vector &indices); + Data(const std::vector &vertices) { index(vertices); } + Data(std::ifstream &in); + + void index(const std::vector &vertices); + bool empty() const { + return indices.empty(); + } + void clear() { + indices.clear(); + vertices.clear(); + } + + void serialize(std::ofstream &out); + }; + + static _FORCE_INLINE_ std::unique_ptr Create(const Data& data) { + assert(createFunc != nullptr && "Uninitialized renderer"); + return createFunc(data); + } + +protected: + static std::unique_ptr (*createFunc)(const Data&); +}; + +/// VertexData model with Level Of Detail indices +class LodModel { +public: + virtual ~LodModel() { } + + using LodData = std::pair>; + + static _FORCE_INLINE_ std::unique_ptr Create(const LodData& data) { + assert(createFunc != nullptr && "Uninitialized renderer"); + return createFunc(data); + } + + void inline setLevel(size_t l) { level = l; } + +protected: + size_t level = 0; + + size_t indexSize; + std::vector offsets; + constexpr inline size_t getOffset(size_t level) const { + return level <= 0 ? 0 : (level-1 < offsets.size() ? offsets[level-1] : indexSize); + } + + static std::unique_ptr (*createFunc)(const LodData&); +}; +} \ No newline at end of file diff --git a/src/client/render/api/common.hpp b/src/client/render/api/common.hpp new file mode 100644 index 0000000..d0c371c --- /dev/null +++ b/src/client/render/api/common.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "../../../core/flags.hpp" +#include +#include + +namespace render { + +struct data_view { + data_view() { } + data_view(const void *ptr, size_t size): ptr(ptr), size(size) { } + template + data_view(const Container &c): data_view(c.data(), c.size() * sizeof(typename Container::value_type)) {} + + constexpr bool isUsable() const { return ptr != nullptr && size > 0; } + explicit operator bool() const { return isUsable(); } + + const void *ptr = nullptr; + size_t size = 0; +}; +struct data_ref { + data_ref() { } + data_ref(void *ptr, size_t size): ptr(ptr), size(size) { } + template + data_ref(Container &c): + data_ref(c.data(), c.size() * sizeof(typename Container::value_type)) {} + + constexpr bool isUsable() const { return ptr != nullptr && size > 0; } + explicit operator bool() const { return isUsable(); } + + void *ptr = nullptr; + size_t size = 0; +}; + + +} \ No newline at end of file diff --git a/src/client/render/buffer/Abstract.hpp b/src/client/render/buffer/Abstract.hpp deleted file mode 100644 index b719e15..0000000 --- a/src/client/render/buffer/Abstract.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -namespace buffer { - /// Draw options - struct params { - /// Bind only vertices positions - bool vertexOnly; - /// Draw instanced model - size_t instances = 1; - }; -} diff --git a/src/client/render/gl/Renderer.cpp b/src/client/render/gl/Renderer.cpp index a373248..c6bb723 100644 --- a/src/client/render/gl/Renderer.cpp +++ b/src/client/render/gl/Renderer.cpp @@ -15,7 +15,7 @@ constexpr auto GL_MAJOR = 4; constexpr auto GL_MINOR = 6; Renderer::Renderer(const renderOptions& options): - IndicatorCubeBuffer(GL_LINES, 24, { + IndicatorCubeBuffer({ glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), glm::vec3(0, 0, 1), glm::vec3(0, 1, 1), glm::vec3(0, 1, 1), glm::vec3(0, 1, 0), @@ -101,6 +101,7 @@ bool Renderer::Load(Window& window, const renderOptions& opt) { TracyGpuContext; sInstance = new Renderer(opt); + LodModel::MakeDefault(); return true; } @@ -114,25 +115,28 @@ void Renderer::beginFrame() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -std::function Renderer::beginWorldPass() { +std::function Renderer::beginWorldPass() { WorldPass->useIt(); WorldPass->start(this); - return [&](glm::mat4 model) { - return WorldPass->setup(this, model); + return [&](render::LodModel *const buf, glm::mat4 model) { + WorldPass->setup(this, model); + return dynamic_cast(buf)->draw(); }; } -std::function &)> Renderer::beginEntityPass() { +std::function &)> Renderer::beginEntityPass() { EntityPass->useIt(); EntityPass->start(this); - return [&](const std::vector& models) { - return EntityPass->setup(this, models); + return [&](render::Model *const buf, const std::vector &models) { + EntityPass->setup(this, models); + return dynamic_cast(buf)->drawInstanced(models.size()); }; } size_t Renderer::drawIndicatorCube(glm::mat4 model) { IndicatorPass->useIt(); - return IndicatorCubeBuffer.draw(IndicatorPass->setup(this, model)); + IndicatorPass->setup(this, model); + return IndicatorCubeBuffer.draw(); } void Renderer::endPass() { diff --git a/src/client/render/gl/Renderer.hpp b/src/client/render/gl/Renderer.hpp index a3a3efd..eefd475 100644 --- a/src/client/render/gl/Renderer.hpp +++ b/src/client/render/gl/Renderer.hpp @@ -6,7 +6,7 @@ #include "pass/EntityProgram.hpp" #include "pass/SkyProgram.hpp" #include "pass/ColorProgram.hpp" -#include "buffer/Colored.hpp" +#include "api/Models.hpp" namespace render::gl { @@ -41,8 +41,8 @@ public: } void beginFrame() override; - std::function beginWorldPass() override; - std::function&)> beginEntityPass() override; + std::function beginWorldPass() override; + std::function&)> beginEntityPass() override; size_t drawIndicatorCube(glm::mat4 model) override; void endPass() override; void swapBuffer(Window&) override; @@ -74,7 +74,7 @@ private: std::unique_ptr EntityPass; std::unique_ptr SkyPass; std::unique_ptr IndicatorPass; - buffer::Colored IndicatorCubeBuffer; + Indicator IndicatorCubeBuffer; glm::mat4 ProjectionMatrix; glm::mat4 ViewMatrix; diff --git a/src/client/render/gl/api/Models.cpp b/src/client/render/gl/api/Models.cpp new file mode 100644 index 0000000..675b0ac --- /dev/null +++ b/src/client/render/gl/api/Models.cpp @@ -0,0 +1,152 @@ +#include "Models.hpp" + +using namespace render::gl; + +Shape::Shape(const std::vector& pos) { + size = pos.size(); + glGenBuffers(1, &bufferId); + glBindBuffer(GL_ARRAY_BUFFER, bufferId); + glBufferData(GL_ARRAY_BUFFER, pos.size() * sizeof(glm::vec3), pos.data(), GL_STATIC_DRAW); +} +Shape::~Shape() { + glDeleteBuffers(1, &bufferId); +} +size_t Shape::draw() { + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, bufferId); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); + glDrawArrays(GL_TRIANGLES, 0, size); + glDisableVertexAttribArray(0); + return size; +} + +Indicator::Indicator(const std::vector& pos, const std::vector& col) { + assert(pos.size() == col.size()); + size = pos.size(); + glGenBuffers(1, &vertexBufferId); + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + glBufferData(GL_ARRAY_BUFFER, pos.size() * sizeof(glm::vec3), pos.data(), GL_STATIC_DRAW); + glGenBuffers(1, &colorBufferId); + glBindBuffer(GL_ARRAY_BUFFER, colorBufferId); + glBufferData(GL_ARRAY_BUFFER, col.size() * sizeof(glm::vec4), col.data(), GL_STATIC_DRAW); +} +Indicator::~Indicator() { + glDeleteBuffers(1, &colorBufferId); + glDeleteBuffers(1, &vertexBufferId); +} +void Indicator::enableAttribs() { + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0); + + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, colorBufferId); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void *)0); +} +void Indicator::disableAttribs() { + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); +} +size_t Indicator::draw() { + enableAttribs(); + glDrawArrays(GL_LINES, 0, size); + disableAttribs(); + return size; +} +size_t Indicator::drawInstanced(size_t count) { + enableAttribs(); + glDrawArraysInstanced(GL_LINES, 0, size, count); + disableAttribs(); + return size * count; +} + +void enableAttribs() { + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_HALF_FLOAT, GL_FALSE, sizeof(render::PackedVertexData), + reinterpret_cast(offsetof(render::PackedVertexData, PosMat[0]))); + glEnableVertexAttribArray(1); + glVertexAttribIPointer(1, 1, GL_UNSIGNED_SHORT, sizeof(render::PackedVertexData), + reinterpret_cast(offsetof(render::PackedVertexData, PosMat[3]))); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_HALF_FLOAT, GL_FALSE, sizeof(render::PackedVertexData), + reinterpret_cast(offsetof(render::PackedVertexData, Nrm))); +} +void disableAttribs() { + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); +} + +Model::Model(const Data& data) { + indexSize = data.indices.size(); + glGenBuffers(1, &vertexBufferId); + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + glBufferData(GL_ARRAY_BUFFER, data.vertices.size() * sizeof(render::PackedVertexData), data.vertices.data(), GL_STATIC_DRAW); + glGenBuffers(1, &indexBufferId); + glBindBuffer(GL_ARRAY_BUFFER, indexBufferId); + glBufferData(GL_ARRAY_BUFFER, data.indices.size() * sizeof(glm::u16), data.indices.data(), GL_STATIC_DRAW); +} +Model::~Model() { + glDeleteBuffers(1, &vertexBufferId); + glDeleteBuffers(1, &indexBufferId); +} +size_t Model::draw() { + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + enableAttribs(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId); + glDrawElements(GL_TRIANGLES, indexSize, GL_UNSIGNED_SHORT, (void *)0); + disableAttribs(); + return indexSize; +} +size_t Model::drawInstanced(size_t count) { + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + enableAttribs(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId); + glDrawElementsInstanced(GL_TRIANGLES, indexSize, GL_UNSIGNED_SHORT, (void *)0, count); + disableAttribs(); + return indexSize * count; +} + +LodModel::LodModel(const LodData& data) { + indexSize = data.first.indices.size(); + offsets = data.second; + glGenBuffers(1, &vertexBufferId); + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + glBufferData(GL_ARRAY_BUFFER, data.first.vertices.size() * sizeof(render::PackedVertexData), data.first.vertices.data(), GL_STATIC_DRAW); + glGenBuffers(1, &indexBufferId); + glBindBuffer(GL_ARRAY_BUFFER, indexBufferId); + glBufferData(GL_ARRAY_BUFFER, data.first.indices.size() * sizeof(glm::u16), data.first.indices.data(), GL_STATIC_DRAW); +} +LodModel::~LodModel() { + glDeleteBuffers(1, &vertexBufferId); + glDeleteBuffers(1, &indexBufferId); +} +size_t LodModel::draw() { + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + enableAttribs(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId); + const auto start = getOffset(level); + const auto end = getOffset(level+1); + const auto count = end - start; + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(glm::u16))); + disableAttribs(); + return count; +} +size_t LodModel::drawInstanced(size_t i) { + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferId); + enableAttribs(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferId); + const auto start = getOffset(level); + const auto end = getOffset(level+1); + const auto count = end - start; + glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(glm::u16)), i); + disableAttribs(); + return i * count; +} + +std::unique_ptr createLodModel(const LodModel::LodData& data) { + return std::make_unique(data); +} +void LodModel::MakeDefault() { + createFunc = createLodModel; +} \ No newline at end of file diff --git a/src/client/render/gl/api/Models.hpp b/src/client/render/gl/api/Models.hpp new file mode 100644 index 0000000..89d4356 --- /dev/null +++ b/src/client/render/gl/api/Models.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "../../api/Models.hpp" +#include +#include +#include + +namespace render::gl { + +/// Positions only buffer +class Shape final { +public: + Shape(const std::vector&); + ~Shape(); + + size_t draw(); + +private: + size_t size; + GLuint bufferId; +}; + +class Indicator final: public render::Indicator { +public: + Indicator(const std::vector&, const std::vector&); + ~Indicator(); + + size_t draw(); + size_t drawInstanced(size_t count); + +private: + size_t size; + GLuint vertexBufferId; + GLuint colorBufferId; + + void enableAttribs(); + void disableAttribs(); +}; + +class Model final: public render::Model { +public: + Model(const Data&); + ~Model(); + + size_t draw(); + size_t drawInstanced(size_t count); + +private: + size_t indexSize; + GLuint vertexBufferId; + GLuint indexBufferId; +}; +class LodModel final: public render::LodModel { +public: + LodModel(const LodData&); + ~LodModel(); + + static void MakeDefault(); + + size_t draw(); + size_t drawInstanced(size_t count); + +private: + GLuint vertexBufferId; + GLuint indexBufferId; +}; + +} \ No newline at end of file diff --git a/src/client/render/gl/buffer/Abstract.cpp b/src/client/render/gl/buffer/Abstract.cpp deleted file mode 100644 index 993b5ba..0000000 --- a/src/client/render/gl/buffer/Abstract.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "Abstract.hpp" - -using namespace buffer; - -Abstract::Abstract(GLenum shape): Shape(shape) { - glGenBuffers(1, &VertexBufferID); -} - -Abstract::~Abstract() { - glDeleteBuffers(1, &VertexBufferID); -} - -void Abstract::enableVertexAttrib() { - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID); - glVertexAttribPointer( - 0, // attribute - 3, // size - GL_FLOAT, // type - GL_FALSE, // normalized? - 0, // stride - (void *)0 // array buffer offset - ); -} -void Abstract::enableAllAttribs() { - enableVertexAttrib(); -} -void Abstract::disableVertexAttrib() { - glDisableVertexAttribArray(0); -} -void Abstract::disableAllAttribs() { - disableVertexAttrib(); -} - -void Abstract::setVertices(const unsigned long size, const void *data) { - glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID); - glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); -} \ No newline at end of file diff --git a/src/client/render/gl/buffer/Abstract.hpp b/src/client/render/gl/buffer/Abstract.hpp deleted file mode 100644 index 5282395..0000000 --- a/src/client/render/gl/buffer/Abstract.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "../../buffer/Abstract.hpp" - -namespace buffer { - /// Abstract OpenGL Buffer - class Abstract { - public: - Abstract(GLenum shape); - virtual ~Abstract(); - - /// Bind and draw buffer - virtual uint draw(params params) = 0; - - protected: - GLenum Shape; - - GLuint VertexBufferID; - - void enableVertexAttrib(); - void disableVertexAttrib(); - void enableAllAttribs(); - void disableAllAttribs(); - - void setVertices(const unsigned long size, const void *data); - }; -} diff --git a/src/client/render/gl/buffer/Colored.cpp b/src/client/render/gl/buffer/Colored.cpp deleted file mode 100644 index c4c2409..0000000 --- a/src/client/render/gl/buffer/Colored.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "Colored.hpp" - -using namespace buffer; - -Colored::Colored(GLenum shape, const unsigned long count, const std::vector &vertices, const std::vector &colors): Abstract(shape) { - glGenBuffers(1, &ColorBufferID); - setVertices(vertices.size() * sizeof(glm::vec3), &vertices[0]); - setColors(colors.size() * sizeof(glm::vec4), &colors[0]); - ElementCount = count; -} -Colored::~Colored() { - glDeleteBuffers(1, &ColorBufferID); -} - -uint Colored::draw(params params) { - if (params.vertexOnly) { - enableVertexAttrib(); - } else { - enableAllAttribs(); - } - if (params.instances == 1) { - glDrawArrays(Shape, 0, ElementCount); - } else { - glDrawArraysInstanced(Shape, 0, ElementCount, params.instances); - } - - if (params.vertexOnly) { - disableVertexAttrib(); - } else { - disableAllAttribs(); - } - return ElementCount * params.instances; -} - -void Colored::enableAllAttribs() { - enableVertexAttrib(); - - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID); - glVertexAttribPointer( - 1, // attribute - 4, // size - GL_FLOAT, // type - GL_FALSE, // normalized? - 0, // stride - (void *)0 // array buffer offset - ); -} -void Colored::disableAllAttribs() { - glDisableVertexAttribArray(1); - - disableVertexAttrib(); -} - -void Colored::setColors(const unsigned long size, const void *data) { - glBindBuffer(GL_ARRAY_BUFFER, ColorBufferID); - glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); -} \ No newline at end of file diff --git a/src/client/render/gl/buffer/Colored.hpp b/src/client/render/gl/buffer/Colored.hpp deleted file mode 100644 index ee434a7..0000000 --- a/src/client/render/gl/buffer/Colored.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Abstract.hpp" - -namespace buffer { - /// OpenGL VertexBuffer with Colors - class Colored: public Abstract { - public: - Colored(GLenum shape, const unsigned long count, const std::vector &vertices, const std::vector &colors); - virtual ~Colored(); - - void enableAllAttribs(); - void disableAllAttribs(); - - uint draw(params params) override; - - private: - unsigned long ElementCount; - - GLuint ColorBufferID; - - void setColors(const unsigned long size, const void *data); - }; -} \ No newline at end of file diff --git a/src/client/render/gl/buffer/LodShortIndexed.cpp b/src/client/render/gl/buffer/LodShortIndexed.cpp deleted file mode 100644 index 5797a25..0000000 --- a/src/client/render/gl/buffer/LodShortIndexed.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "LodShortIndexed.hpp" - -using namespace buffer; - -LodShortIndexed::LodShortIndexed(GLenum shape, const ShortIndexed::Data &data, const std::vector &offsets): ShortIndexed(shape, data), offsets(offsets) { } -LodShortIndexed::LodShortIndexed(GLenum shape, const LodShortIndexed::LodData &data): ShortIndexed(shape, data.first), offsets(data.second) { } -LodShortIndexed::~LodShortIndexed() { } - -#include - -uint LodShortIndexed::draw(buffer::params params) { - if(params.vertexOnly) { - enableVertexAttrib(); - } else { - enableAllAttribs(); - } - enableIndex(); - const auto start = getOffset(level); - const auto end = getOffset(level+1); - const auto count = end - start; - if (params.instances == 1) { - glDrawElements(Shape, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(GLushort))); - } else { - glDrawElementsInstanced(Shape, count, GL_UNSIGNED_SHORT, (void *)(start*sizeof(GLushort)), params.instances); - } - - if(params.vertexOnly) { - disableVertexAttrib(); - } else { - disableAllAttribs(); - } - return count * params.instances; -} \ No newline at end of file diff --git a/src/client/render/gl/buffer/LodShortIndexed.hpp b/src/client/render/gl/buffer/LodShortIndexed.hpp deleted file mode 100644 index b62c26b..0000000 --- a/src/client/render/gl/buffer/LodShortIndexed.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "ShortIndexed.hpp" - -namespace buffer { - /// ShortIndexed with merge indices for LOD - class LodShortIndexed: public ShortIndexed { - public: - using LodData = std::pair>; - - LodShortIndexed(GLenum shape, const ShortIndexed::Data &data, const std::vector &lod_offsets); - LodShortIndexed(GLenum shape, const LodShortIndexed::LodData &data); - virtual ~LodShortIndexed(); - - uint draw(params params) override; - - void inline setLevel(size_t l) { level = l; } - - private: - size_t level = 0; - std::vector offsets; - constexpr inline size_t getOffset(size_t level) const { - return level <= 0 ? 0 : (level-1 < offsets.size() ? offsets[level-1] : IndexSize); - } - }; -} - diff --git a/src/client/render/gl/buffer/ShortIndexed.cpp b/src/client/render/gl/buffer/ShortIndexed.cpp deleted file mode 100644 index ba30b25..0000000 --- a/src/client/render/gl/buffer/ShortIndexed.cpp +++ /dev/null @@ -1,131 +0,0 @@ -#include "ShortIndexed.hpp" - -#include "vboindexer.hpp" -#include "../../../../core/utils/logger.hpp" - -using namespace buffer; - -ShortIndexed::Data::Data(const std::vector &vs, const std::vector &indices): indices(indices), vertices(vs) { } -ShortIndexed::Data::Data(std::ifstream& in) { - { - size_t i_size; - in.read(reinterpret_cast(&i_size), sizeof(i_size)); - indices.resize(i_size); - in.read(reinterpret_cast(indices.data()), sizeof(GLushort) * i_size); - } - size_t v_size; - in.read(reinterpret_cast(&v_size), sizeof(v_size)); - vertices.resize(v_size, PackedVertexData(0, 0, 0, 0, 0, 0, 0, 0)); - in.read(reinterpret_cast(vertices.data()), sizeof(buffer::PackedVertexData) * v_size); -} -void ShortIndexed::Data::serialize(std::ofstream& out) { - { - size_t i_size = indices.size(); - out.write(reinterpret_cast(&i_size), sizeof(i_size)); - out.write(reinterpret_cast(indices.data()), sizeof(GLushort) * i_size); - } - size_t v_size = vertices.size(); - out.write(reinterpret_cast(&v_size), sizeof(v_size)); - out.write(reinterpret_cast(vertices.data()), sizeof(buffer::PackedVertexData) * v_size); -} -void ShortIndexed::Data::index(const std::vector& vs) { - indexVBO(vs, indices, vertices); -} - -ShortIndexed::ShortIndexed(GLenum shape, const std::vector &vertices): Abstract(shape) { - setData(ShortIndexed::Data(vertices)); -} -ShortIndexed::ShortIndexed(GLenum shape, const std::vector &vertices, const std::vector& indices): Abstract(shape) { - setData(ShortIndexed::Data(vertices, indices)); -} -ShortIndexed::ShortIndexed(GLenum shape, const ShortIndexed::Data &data): Abstract(shape) { - setData(data); -} - -ShortIndexed::~ShortIndexed() { - glDeleteBuffers(1, &IndexBufferID); -} - -void ShortIndexed::enableVertexAttrib() { - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID); - glVertexAttribPointer( - 0, // attribute - 3, // size - GL_HALF_FLOAT, // type - GL_FALSE, // normalized? - sizeof(PackedVertexData), // stride - reinterpret_cast(offsetof(PackedVertexData, PosMat[0])) // array buffer offset - ); -} - -void ShortIndexed::enableAllAttribs() { - enableVertexAttrib(); - - glEnableVertexAttribArray(1); - glVertexAttribIPointer( - 1, // attribute - 1, // size - GL_UNSIGNED_SHORT, // type - sizeof(PackedVertexData), // stride - reinterpret_cast(offsetof(PackedVertexData, PosMat[3])) // array buffer offset - ); - - glEnableVertexAttribArray(2); - glVertexAttribPointer( - 2, // attribute - 3, // size - GL_HALF_FLOAT, // type - GL_FALSE, // normalized? - sizeof(PackedVertexData), // stride - reinterpret_cast(offsetof(PackedVertexData, Nrm)) // array buffer offset - ); -} -void ShortIndexed::disableAllAttribs() { - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(1); - disableVertexAttrib(); -} -void ShortIndexed::enableIndex() { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID); -} - -uint ShortIndexed::draw(buffer::params params) { - if(IndexSize == 0) - return 0; - - if(params.vertexOnly) { - enableVertexAttrib(); - } else { - enableAllAttribs(); - } - enableIndex(); - if (params.instances == 1) { - glDrawElements(Shape, IndexSize, GL_UNSIGNED_SHORT, (void *)0); - } else { - glDrawElementsInstanced(Shape, IndexSize, GL_UNSIGNED_SHORT, (void *)0, params.instances); - } - - if(params.vertexOnly) { - disableVertexAttrib(); - } else { - disableAllAttribs(); - } - return IndexSize * params.instances; -} - -void ShortIndexed::setData(const ShortIndexed::Data& data) { - glGenBuffers(1, &IndexBufferID); - - IndexSize = data.indices.size(); - if(IndexSize != data.indices.size()) { - LOG_E("ShortBuffer overflow: " << data.indices.size()); - } - setIndicies(IndexSize * sizeof(GLushort), data.indices.data()); - setVertices(data.vertices.size() * sizeof(PackedVertexData), data.vertices.data()); -} - -void ShortIndexed::setIndicies(const unsigned long size, const void *data) { - glBindBuffer(GL_ARRAY_BUFFER, IndexBufferID); - glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); -} \ No newline at end of file diff --git a/src/client/render/gl/buffer/ShortIndexed.hpp b/src/client/render/gl/buffer/ShortIndexed.hpp deleted file mode 100644 index 64ee74e..0000000 --- a/src/client/render/gl/buffer/ShortIndexed.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Abstract.hpp" -#include "VertexData.hpp" - -namespace buffer { - /// OpenGL VertexBuffer with IndexBuffer - class ShortIndexed: public Abstract { - public: - /// Preindexed buffer data - struct Data { - std::vector indices; - std::vector vertices; - - Data() { } - Data(const std::vector &vertices, const std::vector &indices); - Data(const std::vector &vertices) { index(vertices); } - Data(std::ifstream &in); - - void index(const std::vector &vertices); - bool empty() const { - return indices.empty(); - } - void clear() { - indices.clear(); - vertices.clear(); - } - - void serialize(std::ofstream &out); - }; - - ShortIndexed(GLenum shape, const typename std::vector &vertices); - ShortIndexed(GLenum shape, const typename std::vector &vertices, const typename std::vector &indices); - ShortIndexed(GLenum shape, const typename ShortIndexed::Data &data); - virtual ~ShortIndexed(); - - uint draw(params params) override; - - protected: - void enableVertexAttrib(); - void enableAllAttribs(); - void disableAllAttribs(); - void enableIndex(); - GLushort IndexSize = 0; - private: - GLuint IndexBufferID; - - void setData(const ShortIndexed::Data &data); - void setIndicies(const unsigned long size, const void *data); - }; -} - diff --git a/src/client/render/gl/buffer/Vertex.cpp b/src/client/render/gl/buffer/Vertex.cpp deleted file mode 100644 index d761f70..0000000 --- a/src/client/render/gl/buffer/Vertex.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "Vertex.hpp" - -using namespace buffer; - -Vertex::Vertex(GLenum shape, const unsigned long count, const unsigned long size, const void *data): Abstract(shape) { - setVertices(size, data); - ElementCount = count; -} - -uint Vertex::draw(params) { - enableAllAttribs(); - glDrawArrays(Shape, 0, ElementCount); - disableAllAttribs(); - return ElementCount; -} \ No newline at end of file diff --git a/src/client/render/gl/buffer/Vertex.hpp b/src/client/render/gl/buffer/Vertex.hpp deleted file mode 100644 index 6accb32..0000000 --- a/src/client/render/gl/buffer/Vertex.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include "Abstract.hpp" - -/// OpenGL VertexBuffer -namespace buffer { - class Vertex: public Abstract { - public: - Vertex(GLenum shape, const unsigned long count, const unsigned long size, const void *data); - - uint draw(params) override; - - private: - unsigned long ElementCount; - }; -} diff --git a/src/client/render/gl/buffer/VertexData.hpp b/src/client/render/gl/buffer/VertexData.hpp deleted file mode 100644 index fe6b7c1..0000000 --- a/src/client/render/gl/buffer/VertexData.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include // for memcmp -#include - -namespace buffer { - /// Vertex properties - struct VertexData { - VertexData(const glm::vec3 &position, GLushort material, const glm::vec3 &normal): - Position(position), Material(material), Normal(normal) { } - glm::vec3 Position; - GLushort Material; - glm::vec3 Normal; - }; - - /// Quantized vertex properties - struct PackedVertexData { - PackedVertexData(GLushort x, GLushort y, GLushort z, GLushort mat, GLushort nx, GLushort ny, GLushort nz, GLushort nw = 0) { - PosMat[0] = x; - PosMat[1] = y; - PosMat[2] = z; - PosMat[3] = mat; - Nrm[0] = nx; - Nrm[1] = ny; - Nrm[2] = nz; - Nrm[3] = nw; - } - GLushort PosMat[4]; - GLushort Nrm[4]; //NOTE: Triplanar does not handle 10_10_10_2_REV - bool operator<(const PackedVertexData that) const { - return memcmp((void *)this, (void *)&that, sizeof(PackedVertexData)) > 0; - }; - }; -} diff --git a/src/client/render/gl/buffer/vboindexer.cpp b/src/client/render/gl/buffer/vboindexer.cpp deleted file mode 100644 index d78f29d..0000000 --- a/src/client/render/gl/buffer/vboindexer.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include - -#include - -#include "vboindexer.hpp" - -bool getSimilarVertexIndex_fast( - const buffer::PackedVertexData &packed, - std::map &VertexToOutIndex, - GLushort &result) -{ - std::map::iterator it = VertexToOutIndex.find(packed); - if ( it == VertexToOutIndex.end() ){ - return false; - }else{ - result = it->second; - return true; - } -} -bool getSimilarVertexIndex_fast( - const buffer::PackedVertexData &packed, - std::map &VertexToOutIndex, - unsigned int &result) -{ - std::map::iterator it = VertexToOutIndex.find(packed); - if ( it == VertexToOutIndex.end() ){ - return false; - }else{ - result = it->second; - return true; - } -} - -void indexVBO( - const std::vector &in_vertices, - - std::vector &out_indices, - std::vector &out_vertices) -{ - std::map VertexToOutIndex; - - out_indices.reserve(in_vertices.size()); - // For each input vertex - for (size_t i=0; i -#include -#include "VertexData.hpp" -#include - -void indexVBO( - const std::vector &in_vertices, - - std::vector &out_indices, - std::vector &out_vertices); - -#endif \ No newline at end of file diff --git a/src/client/render/gl/pass/ColorProgram.cpp b/src/client/render/gl/pass/ColorProgram.cpp index 1dc6b21..0d6dc4b 100644 --- a/src/client/render/gl/pass/ColorProgram.cpp +++ b/src/client/render/gl/pass/ColorProgram.cpp @@ -20,10 +20,9 @@ ColorProgram::~ColorProgram() { } std::string ColorProgram::getName() const { return "Color"; } -buffer::params ColorProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) { +void ColorProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) { const auto mvp = renderer->getProjectionMatrix() * renderer->getViewMatrix() * modelMatrix; setMVP(&mvp[0][0]); - return buffer::params{.vertexOnly = false}; } void ColorProgram::setMVP(const GLfloat *matrix) { diff --git a/src/client/render/gl/pass/ColorProgram.hpp b/src/client/render/gl/pass/ColorProgram.hpp index e6cde47..d728e09 100644 --- a/src/client/render/gl/pass/ColorProgram.hpp +++ b/src/client/render/gl/pass/ColorProgram.hpp @@ -9,7 +9,7 @@ namespace pass { ColorProgram(); ~ColorProgram(); - buffer::params setup(render::gl::Renderer *, glm::mat4 modelMatrix); + void setup(render::gl::Renderer *, glm::mat4 modelMatrix); protected: std::string getName() const override; diff --git a/src/client/render/gl/pass/EntityProgram.cpp b/src/client/render/gl/pass/EntityProgram.cpp index 9c72d40..d5fe6d6 100644 --- a/src/client/render/gl/pass/EntityProgram.cpp +++ b/src/client/render/gl/pass/EntityProgram.cpp @@ -17,11 +17,9 @@ EntityProgram::EntityProgram(const EntityProgram::options &opts) : VoxelProgram( } EntityProgram::~EntityProgram() { } -buffer::params EntityProgram::setup(render::gl::Renderer *renderer, const std::vector& modelsMatrices) { +void EntityProgram::setup(render::gl::Renderer *renderer, const std::vector& modelsMatrices) { setModels(&modelsMatrices[0][0][0], modelsMatrices.size()); - auto params = VoxelProgram::setup(renderer); - params.instances = modelsMatrices.size(); - return params; + VoxelProgram::setup(renderer); } void EntityProgram::setModels(const GLfloat *matrices, size_t count) { diff --git a/src/client/render/gl/pass/EntityProgram.hpp b/src/client/render/gl/pass/EntityProgram.hpp index 0018de6..f72fd82 100644 --- a/src/client/render/gl/pass/EntityProgram.hpp +++ b/src/client/render/gl/pass/EntityProgram.hpp @@ -11,7 +11,7 @@ namespace pass { static constexpr auto LOCATION = 6; - buffer::params setup(render::gl::Renderer *, const std::vector &modelsMatrices); + void setup(render::gl::Renderer *, const std::vector &modelsMatrices); void disable(); protected: diff --git a/src/client/render/gl/pass/Program.hpp b/src/client/render/gl/pass/Program.hpp index 36d1a62..cc6affc 100644 --- a/src/client/render/gl/pass/Program.hpp +++ b/src/client/render/gl/pass/Program.hpp @@ -6,7 +6,6 @@ #include #include "Shader.hpp" -#include "../buffer/Abstract.hpp" namespace render { struct passOptions; diff --git a/src/client/render/gl/pass/SkyProgram.cpp b/src/client/render/gl/pass/SkyProgram.cpp index 7f7fd33..792ee8b 100644 --- a/src/client/render/gl/pass/SkyProgram.cpp +++ b/src/client/render/gl/pass/SkyProgram.cpp @@ -4,50 +4,50 @@ using namespace pass; -const GLfloat g_cubemap_vertices[] = { - -1.0f, 1.0f, -1.0f, - -1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, +const std::vector g_cubemap_vertices = { + {-1.0f, 1.0f, -1.0f}, + {-1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, - -1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, -1.0f, - -1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, + {-1.0f, -1.0f, 1.0f}, + {-1.0f, -1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, 1.0f}, + {-1.0f, -1.0f, 1.0f}, - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, -1.0f}, + { 1.0f, -1.0f, -1.0f}, - -1.0f, -1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, + {-1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + { 1.0f, -1.0f, 1.0f}, + {-1.0f, -1.0f, 1.0f}, - -1.0f, 1.0f, -1.0f, - 1.0f, 1.0f, -1.0f, - 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, - -1.0f, 1.0f, 1.0f, - -1.0f, 1.0f, -1.0f, + {-1.0f, 1.0f, -1.0f}, + { 1.0f, 1.0f, -1.0f}, + { 1.0f, 1.0f, 1.0f}, + { 1.0f, 1.0f, 1.0f}, + {-1.0f, 1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f}, - -1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, -1.0f, - 1.0f, -1.0f, -1.0f, - -1.0f, -1.0f, 1.0f, - 1.0f, -1.0f, 1.0f + {-1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f}, + { 1.0f, -1.0f, -1.0f}, + {-1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, 1.0f} }; -SkyProgram::SkyProgram(): Program(), CubeBuffer(GL_TRIANGLES, 36, sizeof(g_cubemap_vertices), g_cubemap_vertices) { +SkyProgram::SkyProgram(): Program(), CubeBuffer(g_cubemap_vertices) { std::vector flags; std::vector shaders; @@ -72,13 +72,10 @@ void SkyProgram::start(render::gl::Renderer *renderer) { bindTexture(renderer->getSkyTexture()); } -buffer::params SkyProgram::setup() { - return buffer::params{.vertexOnly = true}; -} void SkyProgram::draw(render::gl::Renderer *renderer) { useIt(); start(renderer); - CubeBuffer.draw(setup()); + CubeBuffer.draw(); } void SkyProgram::setView(const GLfloat *matrix) { diff --git a/src/client/render/gl/pass/SkyProgram.hpp b/src/client/render/gl/pass/SkyProgram.hpp index 5ef0a43..3a74260 100644 --- a/src/client/render/gl/pass/SkyProgram.hpp +++ b/src/client/render/gl/pass/SkyProgram.hpp @@ -1,7 +1,7 @@ #pragma once #include "Program.hpp" -#include "../buffer/Vertex.hpp" +#include "../api/Models.hpp" namespace pass { /// Skybox pass @@ -11,7 +11,6 @@ namespace pass { ~SkyProgram(); void start(render::gl::Renderer *); - buffer::params setup(); /// Direct draw using internal buffer void draw(render::gl::Renderer *); @@ -28,6 +27,6 @@ namespace pass { GLuint ProjectionMatrixID; GLuint TextureID; - buffer::Vertex CubeBuffer; + render::gl::Shape CubeBuffer; }; } diff --git a/src/client/render/gl/pass/VoxelProgram.cpp b/src/client/render/gl/pass/VoxelProgram.cpp index c34942d..894fa17 100644 --- a/src/client/render/gl/pass/VoxelProgram.cpp +++ b/src/client/render/gl/pass/VoxelProgram.cpp @@ -62,10 +62,9 @@ void VoxelProgram::start(render::gl::Renderer *renderer) { setView(&renderer->getViewMatrix()[0][0]); setProj(&renderer->getProjectionMatrix()[0][0]); } -buffer::params VoxelProgram::setup(render::gl::Renderer *renderer) { +void VoxelProgram::setup(render::gl::Renderer *renderer) { setSphereProj(&renderer->getSphereProj()[0]); setCurvature(renderer->getCurvature()); - return buffer::params{.vertexOnly = false}; } void VoxelProgram::setProj(const GLfloat *matrix) { diff --git a/src/client/render/gl/pass/VoxelProgram.hpp b/src/client/render/gl/pass/VoxelProgram.hpp index a5daf7e..9d611e3 100644 --- a/src/client/render/gl/pass/VoxelProgram.hpp +++ b/src/client/render/gl/pass/VoxelProgram.hpp @@ -14,7 +14,7 @@ namespace pass { void start(render::gl::Renderer *); protected: - buffer::params setup(render::gl::Renderer *); + void setup(render::gl::Renderer *); std::string getName() const override; void setView(const GLfloat *matrix); diff --git a/src/client/render/gl/pass/WorldProgram.cpp b/src/client/render/gl/pass/WorldProgram.cpp index a33abcc..f933ad9 100644 --- a/src/client/render/gl/pass/WorldProgram.cpp +++ b/src/client/render/gl/pass/WorldProgram.cpp @@ -11,9 +11,9 @@ WorldProgram::WorldProgram(const WorldProgram::options& opts): VoxelProgram(opts WorldProgram::~WorldProgram() { } -buffer::params WorldProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) { +void WorldProgram::setup(render::gl::Renderer *renderer, glm::mat4 modelMatrix) { setModel(&modelMatrix[0][0]); - return VoxelProgram::setup(renderer); + VoxelProgram::setup(renderer); } void WorldProgram::setModel(const GLfloat *matrix) { diff --git a/src/client/render/gl/pass/WorldProgram.hpp b/src/client/render/gl/pass/WorldProgram.hpp index eeede0a..a3e0189 100644 --- a/src/client/render/gl/pass/WorldProgram.hpp +++ b/src/client/render/gl/pass/WorldProgram.hpp @@ -9,7 +9,7 @@ namespace pass { WorldProgram(const options &opts); ~WorldProgram(); - buffer::params setup(render::gl::Renderer *, glm::mat4 modelMatrix); + void setup(render::gl::Renderer *, glm::mat4 modelMatrix); protected: void setModel(const GLfloat *matrix); diff --git a/src/client/render/vk/Allocator.cpp b/src/client/render/vk/Allocator.cpp index 42433cf..6f8a5f1 100644 --- a/src/client/render/vk/Allocator.cpp +++ b/src/client/render/vk/Allocator.cpp @@ -7,12 +7,15 @@ using namespace render::vk; -constexpr auto HOST_EASILY_WRITABLE = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; -constexpr VkDeviceSize MIN_ALLOC_SIZE = 1 << 28; -const auto NO_DELETER = Allocator::MemoryDeleter(nullptr); -Allocator::memory_ptr Allocator::GetNull() { return Allocator::memory_ptr(nullptr, NO_DELETER); } +Allocator* Allocator::sInstance = nullptr; -Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalDevice(info.device), device(device) { +constexpr VkDeviceSize MIN_ALLOC_SIZE = 1 << 28; +const auto NO_DELETER = memory::Deleter(nullptr); +memory::ptr memory::GetNull() { return memory::ptr(nullptr, NO_DELETER); } + +Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalDevice(info.device), + capabilities({info.features.samplerAnisotropy == VK_TRUE}), device(device) +{ if(info.hasMemoryBudget()) { properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; properties2.pNext = &budget; @@ -83,166 +86,6 @@ void Allocator::setTracyZone(const char* name) { (void)name; } -Allocator::memory_ptr Allocator::createBuffer(const buffer_requirement& requirement, VkMemoryPropertyFlags properties, buffer_info& out) { - VkBufferCreateInfo bufferInfo{}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = requirement.size; - bufferInfo.usage = requirement.usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out.buffer) != VK_SUCCESS) { - LOG_E("Failed to create buffer"); - return GetNull(); - } - out.offset = 0; - - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(device, out.buffer, &memRequirements); - - auto memory = allocate(memRequirements, properties); - if (!memory || vkBindBufferMemory(device, out.buffer, memory->ref, memory->offset) != VK_SUCCESS) { - LOG_E("Failed to allocate buffer memory"); - return GetNull(); - } - - if (requirement.size != 0 && requirement.data != nullptr) { - if (memory->ptr != nullptr) { - memory->write(requirement.data, requirement.data_size, requirement.data_offset); - } else { - Allocator::buffer_info stagingBuffer; - if(auto stagingMemory = createBuffer({requirement.size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) { - stagingMemory->write(requirement.data, requirement.data_size, requirement.data_offset); - copyBuffer(stagingBuffer, out, requirement.size); - vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor - } else { - FATAL("Cannot allocate staging memory"); - return GetNull(); - } - } - } - return memory; -} -Allocator::memory_ptr Allocator::createBuffers(const std::vector& requirements, VkMemoryPropertyFlags properties, std::vector& out) { - assert(!requirements.empty()); - out.resize(requirements.size()+1); - - // Create buffers - VkMemoryRequirements memRequirements = {0, 0, UINT32_MAX}; - std::vector sizes; - sizes.resize(requirements.size()); - for (size_t i = 0; i < requirements.size(); i++) { - VkBufferCreateInfo bufferInfo{}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = requirements[i].size; - bufferInfo.usage = requirements[i].usage; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out[i].buffer) != VK_SUCCESS) { - LOG_E("Failed to create buffer"); - return GetNull(); - } - - VkMemoryRequirements individualMemRequirements; - vkGetBufferMemoryRequirements(device, out[i].buffer, &individualMemRequirements); - memRequirements.alignment = std::max(memRequirements.alignment, individualMemRequirements.alignment); - memRequirements.memoryTypeBits &= individualMemRequirements.memoryTypeBits; - sizes[i] = individualMemRequirements.size; - } - - // Align blocks - auto aligned = [&](VkDeviceSize offset) { - if (offset % memRequirements.alignment == 0) - return offset; - return offset + memRequirements.alignment - (offset % memRequirements.alignment); - }; - out[0].offset = 0; - for (size_t i = 1; i < out.size(); i++) { - out[i].offset = aligned(out[i-1].offset + sizes[i-1]); - } - memRequirements.size = out.back().offset; - out.pop_back(); - - // Bind memory - auto memory = allocate(memRequirements, properties); - if (!memory) { - LOG_E("Failed to allocate buffers"); - return GetNull(); - } - for (size_t i = 0; i < requirements.size(); i++) { - if (vkBindBufferMemory(device, out[i].buffer, memory->ref, memory->offset + out[i].offset) != VK_SUCCESS) { - LOG_E("Failed to bind buffer"); - return GetNull(); - } - } - - VkDeviceSize stagingSize = 0; - for (auto& requirement: requirements) - if (requirement.data != nullptr) - stagingSize = std::max(stagingSize, requirement.size); - - // Copy datas - if (stagingSize != 0) { - if (memory->ptr != nullptr) { - for (size_t i = 0; i < requirements.size(); i++) { - if (requirements[i].data != nullptr && requirements[i].size != 0) { - assert(requirements[i].data_size + requirements[i].data_offset <= requirements[i].size); - memory->write(requirements[i].data, requirements[i].data_size, out[i].offset + requirements[i].data_offset); - } - } - } else { - Allocator::buffer_info stagingBuffer; - if(auto stagingMemory = createBuffer({stagingSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) { - for (size_t i = 0; i < requirements.size(); i++) { - if (requirements[i].data != nullptr && requirements[i].size != 0) { - assert(requirements[i].data_size + requirements[i].data_offset <= requirements[i].size); - stagingMemory->write(requirements[i].data, requirements[i].data_size, requirements[i].data_offset); - copyBuffer(stagingBuffer, out[i], requirements[i].size); - } - } - vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor - } else { - FATAL("Cannot allocate staging memory"); - return GetNull(); - } - } - } - - return memory; -} -Allocator::memory_ptr Allocator::createImage(const VkImageCreateInfo& info, VkMemoryPropertyFlags properties, image_info& out, - const void *data, VkDeviceSize data_size, VkDeviceSize data_offset, VkImageLayout finalLayout) { - - if (vkCreateImage(device, &info, ALLOC, &out.image) != VK_SUCCESS) { - LOG_E("Failed to create image"); - return GetNull(); - } - out.offset = 0; - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, out.image, &memRequirements); - - auto memory = allocate(memRequirements, properties, true); - if (!memory || vkBindImageMemory(device, out.image, memory->ref, memory->offset) != VK_SUCCESS) { - LOG_E("Failed to allocate image memory"); - return GetNull(); - } - - if (data_size != 0 && data != nullptr) { - Allocator::buffer_info stagingBuffer; - if(auto stagingMemory = createBuffer({data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT}, HOST_EASILY_WRITABLE, stagingBuffer)) { - stagingMemory->write(data, data_size, data_offset); - transitionImageLayout(out.image, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - copyBufferToImage(stagingBuffer, out, info.extent.width, info.extent.height); - transitionImageLayout(out.image, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, finalLayout); - vkDestroyBuffer(device, stagingBuffer.buffer, ALLOC); //TODO: move to buffer destructor - } else { - FATAL("Cannot allocate staging memory"); - return GetNull(); - } - } - return memory; -} - void Allocator::updateProperties() { if (hasBudget()) { vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &properties2); @@ -256,7 +99,7 @@ void Allocator::updateProperties() { vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties); } } -Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties, bool optimalTiling) { +memory::ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties, bool optimalTiling) { // Search in existing allocations for (auto& alloc: allocations) { if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) && @@ -272,7 +115,7 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM auto it = alloc->areas.cbegin(); auto done = [&] { alloc->areas.insert(it, {requirements.size, start}); - return memory_ptr(new memory_area{alloc->memory, requirements.size, start, alloc->ptr != nullptr ? alloc->ptr + start : nullptr}, alloc->deleter); + return memory::ptr(new memory::area{alloc->memory, requirements.size, start, alloc->ptr != nullptr ? static_cast(alloc->ptr) + start : nullptr}, alloc->deleter); }; while (it != alloc->areas.cend()) { if (it->offset - start > requirements.size) { @@ -300,24 +143,24 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM } else { LOG_E("No suitable memory heap within memory budget"); LOG_D(requirements.memoryTypeBits << ' ' << properties << ' ' << requirements.size); - return GetNull(); + return memory::GetNull(); } VkDeviceMemory memory; if (vkAllocateMemory(device, &allocInfo, ALLOC, &memory) != VK_SUCCESS) { LOG_E("Failed to allocate memory!"); - return GetNull(); + return memory::GetNull(); } void *ptr = nullptr; - if ((getProperties().memoryTypes[allocInfo.memoryTypeIndex].propertyFlags & HOST_EASILY_WRITABLE) == HOST_EASILY_WRITABLE) { + if ((getProperties().memoryTypes[allocInfo.memoryTypeIndex].propertyFlags & memory::HOST_EASILY_WRITABLE) == memory::HOST_EASILY_WRITABLE) { vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr); - } + } //TODO: allow flushable memory auto allocation = allocations.emplace_back(new Allocation(device, memory, allocInfo.allocationSize, allocInfo.memoryTypeIndex, optimalTiling, ptr)).get(); allocation->areas.push_back({requirements.size, 0}); - return memory_ptr(new memory_area{memory, requirements.size, 0, ptr}, allocation->deleter); + return memory::ptr(new memory::area{memory, requirements.size, 0, ptr}, allocation->deleter); } void beginCmd(VkCommandBuffer buffer) { @@ -340,16 +183,14 @@ void submitCmd(VkCommandBuffer buffer, VkQueue queue) { vkQueueWaitIdle(queue); //MAYBE: use fences vkResetCommandBuffer(buffer, 0); } -void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size) { - //FIXME: assert no out of range - +void Allocator::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) { beginCmd(transferBuffer); VkBufferCopy copyRegion{}; copyRegion.srcOffset = 0; copyRegion.dstOffset = 0; copyRegion.size = size; - vkCmdCopyBuffer(transferBuffer, src.buffer, dst.buffer, 1, ©Region); + vkCmdCopyBuffer(transferBuffer, src, dst, 1, ©Region); submitCmd(transferBuffer, transferQueue); } @@ -394,11 +235,11 @@ void Allocator::transitionImageLayout(VkImage image, VkFormat format, VkImageLay submitCmd(graphicsBuffer, graphicsQueue); } -void Allocator::copyBufferToImage(buffer_info src, image_info dest, uint32_t width, uint32_t height) { +void Allocator::copyBufferToImage(VkBuffer src, VkImage dest, uint32_t width, uint32_t height) { beginCmd(transferBuffer); VkBufferImageCopy region{}; - region.bufferOffset = src.offset; + region.bufferOffset = 0; region.bufferRowLength = 0; region.bufferImageHeight = 0; @@ -410,7 +251,7 @@ void Allocator::copyBufferToImage(buffer_info src, image_info dest, uint32_t wid region.imageOffset = {0, 0, 0}; region.imageExtent = {width, height, 1}; - vkCmdCopyBufferToImage(transferBuffer, src.buffer, dest.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(transferBuffer, src, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); submitCmd(transferBuffer, transferQueue); } @@ -451,12 +292,16 @@ std::optional Allocator::findMemory(uint32_t typeFilter, VkMemoryPrope return {}; } -void Allocator::memory_area::write(const void* data, size_t data_size, size_t write_offset) { +void memory::area::write(const void* data, size_t data_size, size_t write_offset) { assert(ptr != nullptr && size >= write_offset + data_size); - memcpy(ptr + write_offset, data, data_size); + memcpy(static_cast(ptr) + write_offset, data, data_size); +} +void memory::area::read(void* data, size_t data_size, size_t read_offset) { + assert(ptr != nullptr && size >= read_offset + data_size); + memcpy(data, static_cast(ptr) + read_offset, data_size); } -void Allocator::MemoryDeleter::operator()(memory_area* area) { +void memory::Deleter::operator()(memory::area* area) { assert(area != nullptr && "Deleting null area"); if(owner != nullptr) { for (auto it = owner->areas.begin(); it != owner->areas.end(); ++it) { @@ -472,9 +317,9 @@ void Allocator::MemoryDeleter::operator()(memory_area* area) { LOG_E("Allocation area not found"); delete area; } -Allocator::Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, bool optimalTiling, void *ptr): +Allocation::Allocation(VkDevice device, VkDeviceMemory memory, VkDeviceSize size, uint32_t memoryType, bool optimalTiling, void *ptr): device(device), memory(memory), size(size), memoryType(memoryType), optimalTiling(optimalTiling), ptr(ptr), deleter(this) { } -Allocator::Allocation::~Allocation() { +Allocation::~Allocation() { if(!areas.empty()) LOG_E("Freeing " << areas.size() << " floating buffers"); diff --git a/src/client/render/vk/Allocator.hpp b/src/client/render/vk/Allocator.hpp index 9432027..f05c31d 100644 --- a/src/client/render/vk/Allocator.hpp +++ b/src/client/render/vk/Allocator.hpp @@ -1,9 +1,11 @@ #pragma once #include "forward.hpp" +#include "../../../core/flags.hpp" +#include "api/Memory.hpp" +#include #include #include -#include namespace tracy { class VkCtx; @@ -11,65 +13,47 @@ namespace tracy { typedef tracy::VkCtx* TracyVkCtx; namespace render::vk { -class Allocator { -private: - struct Allocation; +struct Allocation { + Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, bool optimalTiling, void *ptr); + ~Allocation(); + + const VkDevice device; + const VkDeviceMemory memory; + const VkDeviceSize size; + const uint32_t memoryType; + const bool optimalTiling; + void *const ptr = nullptr; + const memory::Deleter deleter; + + struct area { VkDeviceSize size; VkDeviceSize offset; }; + std::vector areas; +}; +class Allocator final { public: Allocator(VkDevice, const PhysicalDeviceInfo&); ~Allocator(); - struct memory_area { - VkDeviceMemory ref; - VkDeviceSize size; - VkDeviceSize offset; - void *ptr = nullptr; + memory::ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false); + bool deallocate(const memory::area&); - void write(const void*, VkDeviceSize size, VkDeviceSize offset = 0); - void read(void*, VkDeviceSize size, VkDeviceSize offset = 0); - }; - - class MemoryDeleter { - public: - MemoryDeleter(Allocation *owner): owner(owner) { } - void operator()(memory_area *); - private: - Allocation *owner; - }; - - using memory_ptr = std::unique_ptr; - - memory_ptr allocate(VkMemoryRequirements, VkMemoryPropertyFlags, bool optimalTiling = false); - bool deallocate(const memory_area&); - - struct buffer_info { - VkBuffer buffer = nullptr; - VkDeviceSize offset = 0; - }; - struct buffer_requirement { - VkDeviceSize size; - VkBufferUsageFlags usage; - const void *data = nullptr; - VkDeviceSize data_size = 0; - VkDeviceSize data_offset = 0; - }; - memory_ptr createBuffer(const buffer_requirement&, VkMemoryPropertyFlags, buffer_info&); - memory_ptr createBuffers(const std::vector &, VkMemoryPropertyFlags, std::vector &); - - struct image_info { - VkImage image = nullptr; - VkDeviceSize offset = 0; - }; - memory_ptr createImage(const VkImageCreateInfo&, VkMemoryPropertyFlags, image_info&, - const void *data = nullptr, VkDeviceSize data_size = 0, VkDeviceSize data_offset = 0, - VkImageLayout finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - void copyBuffer(buffer_info srcBuffer, buffer_info dstBuffer, VkDeviceSize size); + void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size); void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); - void copyBufferToImage(buffer_info buffer, image_info image, uint32_t width, uint32_t height); + void copyBufferToImage(VkBuffer src, VkImage dst, uint32_t width, uint32_t height); void setTracyZone(const char* name); - static memory_ptr GetNull(); + struct Capabilities { + bool anisotropy; + }; + + constexpr VkDevice getDevice() const { return device; } + constexpr Capabilities getCapabilities() const { return capabilities; } + + static void MakeDefault(Allocator *ptr) { sInstance = ptr; } + static _FORCE_INLINE_ Allocator *GetDefault() { + assert(sInstance != nullptr && "No default allocator"); + return sInstance; + } private: std::optional findMemory(uint32_t, VkMemoryPropertyFlags, VkDeviceSize size = 0); @@ -77,23 +61,8 @@ private: constexpr const VkPhysicalDeviceMemoryProperties &getProperties() const { return hasBudget() ? properties2.memoryProperties : properties; } void updateProperties(); - struct Allocation { - Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, bool optimalTiling, void *ptr); - ~Allocation(); - - const VkDevice device; - const VkDeviceMemory memory; - const VkDeviceSize size; - const uint32_t memoryType; - const bool optimalTiling; - void *const ptr = nullptr; - const MemoryDeleter deleter; - - struct area { VkDeviceSize size; VkDeviceSize offset; }; - std::vector areas; - }; - VkPhysicalDevice const physicalDevice; + Capabilities const capabilities; VkDevice const device; VkPhysicalDeviceMemoryProperties properties{}; VkPhysicalDeviceMemoryProperties2 properties2{}; @@ -108,5 +77,7 @@ private: VkCommandBuffer graphicsBuffer; std::vector> allocations; + + static Allocator *sInstance; }; } \ No newline at end of file diff --git a/src/client/render/vk/CommandCenter.cpp b/src/client/render/vk/CommandCenter.cpp index 4adf814..456a342 100644 --- a/src/client/render/vk/CommandCenter.cpp +++ b/src/client/render/vk/CommandCenter.cpp @@ -2,20 +2,15 @@ #include "PhysicalDeviceInfo.hpp" #include "Pipeline.hpp" -#include "../Renderer.hpp" +#include "Renderer.hpp" #include "buffer/VertexData.hpp" -#include "texture.hpp" using namespace render::vk; #define CONTENT_DIR "content/" #define TEXTURES_DIR CONTENT_DIR "textures/" -CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vector &views, - const Pipeline& pipe, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device), - indexedBufferMemory(Allocator::GetNull()), sampleImageMemory(Allocator::GetNull()), - uniformBuffersMemory(Allocator::GetNull()) -{ +CommandCenter::CommandCenter(VkDevice device, const PhysicalDeviceInfo &info, const renderOptions &opt): device(device) { { // Graphics command pool vkGetDeviceQueue(device, info.queueIndices.graphicsFamily.value(), 0, &graphicsQueue); VkCommandPoolCreateInfo poolInfo{}; @@ -28,114 +23,26 @@ CommandCenter::CommandCenter(VkDevice device, Allocator& alloc, const std::vecto } } { // Vertex buffers (const) - size_t vertexSize = sizeof(buffer::vk::vertices[0]) * buffer::vk::vertices.size(); - size_t indexSize = sizeof(buffer::vk::indices[0]) * buffer::vk::indices.size(); - if(std::vector out; indexedBufferMemory = alloc.createBuffers({ - {indexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, buffer::vk::indices.data(), indexSize, 0}, - {vertexSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, buffer::vk::vertices.data(), vertexSize, 0} - }, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, out)) { - indexBuffer = out[0]; - vertexBuffer = out[1]; - } else { + modelBuffer = ShortIndexedVertexBuffer::Create(buffer::vk::vertices, buffer::vk::indices); + if (!modelBuffer) { FATAL("Cannot create vertex buffer"); } } { // Texture sampler (const) - std::vector data; - dds::header_info header; - if (dds::readDDS(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", data, header)) { - FATAL("Cannot read texture"); - } - - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = header.width; - imageInfo.extent.height = header.height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = header.mipMapCount; //TODO: - imageInfo.arrayLayers = 1; - imageInfo.format = header.format; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.flags = 0; - - sampleImageMemory = alloc.createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, sampleImage, data.data(), data.size()); - if(!sampleImageMemory) { - FATAL("Cannot create texture image"); - } - - VkImageViewCreateInfo viewInfo{}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = sampleImage.image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = header.format; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &viewInfo, nullptr, &sampleImageView) != VK_SUCCESS) { - FATAL("Failed to create texture image view!"); - } - - VkSamplerCreateInfo samplerInfo{}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - - if (info.features.samplerAnisotropy && opt.anisotropy > 0) { - samplerInfo.anisotropyEnable = VK_TRUE; - samplerInfo.maxAnisotropy = 1 << (opt.anisotropy-1); - } else { - samplerInfo.anisotropyEnable = VK_FALSE; - samplerInfo.maxAnisotropy = 1.f; - } - - samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - samplerInfo.unnormalizedCoordinates = VK_FALSE; - - samplerInfo.compareEnable = VK_FALSE; - samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; - - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.mipLodBias = 0.0f; //TODO: - samplerInfo.minLod = 0.0f; - samplerInfo.maxLod = 0.0f; - - if (vkCreateSampler(device, &samplerInfo, nullptr, &sampleSampler) != VK_SUCCESS) { + sampleTexture = Texture::LoadFromFile(TEXTURES_DIR "1024-realistic/terrain/Mapl.dds", {true, true, Texture::Wrap::MIRRORED_REPEAT, opt.anisotropy}); + if (!sampleTexture) { FATAL("Failed to create texture sampler!"); } } - - allocate(alloc, views, pipe, info.swapDetails.capabilities.currentExtent, opt); } CommandCenter::~CommandCenter() { if(!freed) free(); - vkDestroyBuffer(device, indexBuffer.buffer, ALLOC); - vkDestroyBuffer(device, vertexBuffer.buffer, ALLOC); - indexedBufferMemory.reset(); - - vkDestroySampler(device, sampleSampler, ALLOC); - vkDestroyImageView(device, sampleImageView, ALLOC); - vkDestroyImage(device, sampleImage.image, ALLOC); - sampleImageMemory.reset(); - vkDestroyCommandPool(device, graphicsPool, ALLOC); } #include -void CommandCenter::allocate(Allocator& alloc, const std::vector& views, const Pipeline& pipe, VkExtent2D extent, - const renderOptions& opt) -{ +void CommandCenter::allocate(const std::vector& views, const Pipeline& pipe, VkExtent2D extent, const renderOptions& opt) { assert(freed); framebuffers.resize(views.size()); @@ -160,10 +67,10 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector& v { // Uniform buffers VkDeviceSize bufferSize = sizeof(buffer::vk::UniformBufferObject); - std::vector requirements; - requirements.resize(framebuffers.size(), Allocator::buffer_requirement{bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT}); - uniformBuffersMemory = alloc.createBuffers(requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers); - if (!uniformBuffersMemory) { + std::vector requirements; + requirements.resize(framebuffers.size(), Buffer::requirement(bufferSize, Buffer::Usage::UNIFORM)); + uniformBuffers.allocate(requirements, true); + if (!uniformBuffers) { FATAL("Failed to allocate UBO"); } } @@ -200,15 +107,10 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector& v for (size_t i = 0; i < descriptorSets.size(); i++) { VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = uniformBuffers[i].buffer; + bufferInfo.buffer = uniformBuffers.at(i); bufferInfo.offset = 0; bufferInfo.range = sizeof(buffer::vk::UniformBufferObject); - VkDescriptorImageInfo imageInfo{}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo.imageView = sampleImageView; - imageInfo.sampler = sampleSampler; - std::array descriptorWrites{}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = descriptorSets[i]; @@ -224,7 +126,7 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector& v descriptorWrites[1].dstArrayElement = 0; descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWrites[1].descriptorCount = 1; - descriptorWrites[1].pImageInfo = &imageInfo; + descriptorWrites[1].pImageInfo = &sampleTexture->getDescriptor(); vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); } @@ -266,10 +168,10 @@ void CommandCenter::allocate(Allocator& alloc, const std::vector& v vkCmdBeginRenderPass(graphicsBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBindPipeline(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getPipeline()); - VkBuffer vertexBuffers[] = {vertexBuffer.buffer}; + VkBuffer vertexBuffers[] = {modelBuffer->getVertex()}; VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(graphicsBuffers[i], 0, 1, vertexBuffers, offsets); - vkCmdBindIndexBuffer(graphicsBuffers[i], indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16); + vkCmdBindIndexBuffer(graphicsBuffers[i], modelBuffer->getIndex(), 0, VK_INDEX_TYPE_UINT16); vkCmdBindDescriptorSets(graphicsBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.getLayout(), 0, 1, &descriptorSets[i], 0, nullptr); vkCmdDrawIndexed(graphicsBuffers[i], static_cast(buffer::vk::indices.size()), 1, 0, 0, 0); vkCmdEndRenderPass(graphicsBuffers[i]); @@ -290,12 +192,6 @@ void CommandCenter::free() { vkDestroyDescriptorPool(device, descriptorPool, nullptr); - for (size_t i = 0; i < uniformBuffers.size(); i++) { - vkDestroyBuffer(device, uniformBuffers[i].buffer, ALLOC); - } - uniformBuffersMemory.reset(); - - for (size_t i = 0; i < framebuffers.size(); i++) { vkDestroyFramebuffer(device, framebuffers[i], nullptr); } @@ -315,8 +211,7 @@ void CommandCenter::updateUBO(uint32_t idx) { ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(90.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); ubo.proj = proj; - - memcpy(uniformBuffersMemory->ptr + uniformBuffers[idx].offset, &ubo, sizeof(ubo)); + uniformBuffers.write(idx, data_view(&ubo, sizeof(ubo))); } void CommandCenter::submitGraphics(uint32_t idx, VkSemaphore waitSemaphore, VkSemaphore signalSemaphore, VkFence submittedFence) { diff --git a/src/client/render/vk/CommandCenter.hpp b/src/client/render/vk/CommandCenter.hpp index 4a0a35b..684a169 100644 --- a/src/client/render/vk/CommandCenter.hpp +++ b/src/client/render/vk/CommandCenter.hpp @@ -2,22 +2,23 @@ #include "forward.hpp" #include -#include "Allocator.hpp" #include +#include "api/Buffers.hpp" +#include "api/Images.hpp" namespace render::vk { class SwapChain; class Pipeline; -class CommandCenter { +class CommandCenter final { public: - CommandCenter(VkDevice, Allocator&, const std::vector&, const Pipeline&, const PhysicalDeviceInfo&, const renderOptions&); + CommandCenter(VkDevice, const PhysicalDeviceInfo&, const renderOptions&); ~CommandCenter(); void updateUBO(uint32_t idx); void submitGraphics(uint32_t, VkSemaphore, VkSemaphore, VkFence); - void allocate(Allocator&, const std::vector &, const Pipeline&, VkExtent2D, const renderOptions&); + void allocate(const std::vector&, const Pipeline&, VkExtent2D, const renderOptions&); void free(); private: @@ -32,18 +33,12 @@ private: VkDescriptorPool descriptorPool; std::vector descriptorSets; - Allocator::buffer_info vertexBuffer; - Allocator::buffer_info indexBuffer; - Allocator::memory_ptr indexedBufferMemory; + std::unique_ptr modelBuffer; - Allocator::image_info sampleImage; - VkImageView sampleImageView; - VkSampler sampleSampler; - Allocator::memory_ptr sampleImageMemory; + std::unique_ptr sampleTexture; glm::mat4 proj; - std::vector uniformBuffers; - Allocator::memory_ptr uniformBuffersMemory; + BufferGroup uniformBuffers; bool freed = true; }; diff --git a/src/client/render/vk/Pipeline.hpp b/src/client/render/vk/Pipeline.hpp index ba52c22..88e8dbd 100644 --- a/src/client/render/vk/Pipeline.hpp +++ b/src/client/render/vk/Pipeline.hpp @@ -4,7 +4,7 @@ namespace render::vk { -class Pipeline { +class Pipeline final { public: Pipeline(VkDevice, const PhysicalDeviceInfo&, const renderOptions&); ~Pipeline(); diff --git a/src/client/render/vk/Renderer.cpp b/src/client/render/vk/Renderer.cpp index 36db369..b9f94c4 100644 --- a/src/client/render/vk/Renderer.cpp +++ b/src/client/render/vk/Renderer.cpp @@ -46,10 +46,12 @@ Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInf set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window); - allocator = std::make_unique(device, *physicalInfo.get()); - swapChain = std::make_unique(device, *physicalInfo.get()); - pipeline = std::make_unique(device, *physicalInfo.get(), options); - commandCenter = std::make_unique(device, *allocator.get(), swapChain->getImageViews(), *pipeline.get(), *physicalInfo.get(), options); + allocator = std::make_unique(device, getInfos()); + Allocator::MakeDefault(allocator.get()); + swapChain = std::make_unique(device, getInfos()); + pipeline = std::make_unique(device, getInfos(), options); + commandCenter = std::make_unique(device, getInfos(), options); + commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent, options); { imageAvailableSemaphores.resize(opt.inFlightFrames); @@ -101,9 +103,9 @@ void Renderer::recreateSwapChain() { physicalInfo->swapDetails = SwapChainSupportDetails::Query(physicalInfo->device, physicalInfo->surface); set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window); - swapChain = std::make_unique(device, *physicalInfo.get()); - pipeline = std::make_unique(device, *physicalInfo.get(), options); - commandCenter->allocate(*allocator.get(), swapChain->getImageViews(), *pipeline.get(), physicalInfo->swapDetails.capabilities.currentExtent, options); + swapChain = std::make_unique(device, getInfos()); + pipeline = std::make_unique(device, getInfos(), options); + commandCenter->allocate(swapChain->getImageViews(), *pipeline.get(), getInfos().swapDetails.capabilities.currentExtent, options); } void Renderer::destroySwapChain() { commandCenter->free(); @@ -124,11 +126,8 @@ void set_current_extent(VkSurfaceCapabilitiesKHR &capabilities, GLFWwindow* ptr) std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, windowSize.first)), std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, windowSize.second))}; }; -VKAPI_ATTR VkBool32 VKAPI_CALL debugValidationCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* pUserData) +VKAPI_ATTR VkBool32 VKAPI_CALL debugValidationCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void*) { switch (messageSeverity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: @@ -414,7 +413,7 @@ void Renderer::beginFrame() { } } -std::function Renderer::beginWorldPass() { +std::function Renderer::beginWorldPass() { assert(currentImage < swapChain->getImageViews().size()); commandCenter->updateUBO(currentImage); @@ -422,16 +421,16 @@ std::function Renderer::beginWorldPass() { renderFinishedSemaphores[currentFrame], inFlightFences[currentFrame]); /*WorldPass->useIt(); WorldPass->start(this);*/ - return [&](glm::mat4) { - return buffer::params{}; //WorldPass->setup(this, model); + return [&](render::LodModel *const, glm::mat4) { + return 0; //WorldPass->setup(this, model); }; } -std::function &)> Renderer::beginEntityPass() { +std::function &)> Renderer::beginEntityPass() { /*EntityPass->useIt(); EntityPass->start(this);*/ - return [&](const std::vector&) { - return buffer::params{}; //EntityPass->setup(this, models); + return [&](render::Model *const, const std::vector&) { + return 0; //EntityPass->setup(this, models); }; } diff --git a/src/client/render/vk/Renderer.hpp b/src/client/render/vk/Renderer.hpp index ce20a1a..89b22b1 100644 --- a/src/client/render/vk/Renderer.hpp +++ b/src/client/render/vk/Renderer.hpp @@ -20,8 +20,8 @@ public: static _FORCE_INLINE_ Renderer *Get() { return static_cast(render::Renderer::Get()); } void beginFrame() override; - std::function beginWorldPass() override; - std::function &)> beginEntityPass() override; + std::function beginWorldPass() override; + std::function &)> beginEntityPass() override; size_t drawIndicatorCube(glm::mat4 model) override; void endPass() override; void swapBuffer(Window&) override; @@ -34,11 +34,15 @@ public: void reloadShaders(const passOptions &) override; void reloadTextures(const std::string &, float mipMapLOD, float anisotropy) override; + Allocator* getAllocator() const { return allocator.get(); } + void setResized() { framebufferResized = true; } private: Renderer(VkInstance, VkDevice, const PhysicalDeviceInfo &, const renderOptions &); + const PhysicalDeviceInfo &getInfos() const { return *physicalInfo.get(); } + renderOptions options; VkInstance instance; diff --git a/src/client/render/vk/SwapChain.hpp b/src/client/render/vk/SwapChain.hpp index 5a4d03a..32b075e 100644 --- a/src/client/render/vk/SwapChain.hpp +++ b/src/client/render/vk/SwapChain.hpp @@ -6,7 +6,7 @@ namespace render::vk { -class SwapChain { +class SwapChain final { public: SwapChain(VkDevice, const PhysicalDeviceInfo &); ~SwapChain(); diff --git a/src/client/render/vk/api/Buffers.cpp b/src/client/render/vk/api/Buffers.cpp new file mode 100644 index 0000000..6dcdd7e --- /dev/null +++ b/src/client/render/vk/api/Buffers.cpp @@ -0,0 +1,184 @@ +#include "Buffers.hpp" +#include "../Allocator.hpp" +#include "../../../../core/utils/logger.hpp" + +using namespace render::vk; + +Buffer::~Buffer() { + vkDestroyBuffer(Allocator::GetDefault()->getDevice(), ref, ALLOC); + //NOTE: memory_ptr self destroy +} + +memory::ptr createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, const render::data_view view, Buffer::info &out) { + auto alloc = Allocator::GetDefault(); + auto device = alloc->getDevice(); + + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferInfo.size = size; + bufferInfo.usage = usage; + if (view) + bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out.ref) != VK_SUCCESS) { + LOG_E("Failed to create buffer"); + return memory::GetNull(); + } + out.offset = 0; + + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, out.ref, &memRequirements); + + auto memory = alloc->allocate(memRequirements, properties); + if (!memory || vkBindBufferMemory(device, out.ref, memory->ref, memory->offset) != VK_SUCCESS) { + LOG_E("Failed to allocate buffer memory"); + return memory::GetNull(); + } + + if (view) { + if (memory->ptr != nullptr) { + memory->write(view.ptr, view.size); + } else if(auto staging = WritableBuffer::Create(size)) { + staging->write(view, 0); + alloc->copyBuffer(staging->getRef(), out.ref, size); + } else { + FATAL("Cannot allocate staging memory"); + return memory::GetNull(); + } + } + return memory; +} +memory::ptr createBuffers(const std::vector& requirements, VkMemoryPropertyFlags properties, std::vector& out) { + assert(!requirements.empty()); + out.resize(requirements.size()+1); + + auto alloc = Allocator::GetDefault(); + auto device = alloc->getDevice(); + + // Create buffers + VkMemoryRequirements memRequirements = {0, 0, UINT32_MAX}; + std::vector sizes; + sizes.resize(requirements.size()); + for (size_t i = 0; i < requirements.size(); i++) { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + bufferInfo.size = requirements[i].size; + bufferInfo.usage = static_cast(requirements[i].usage); + if (requirements[i].view) + bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + if (vkCreateBuffer(device, &bufferInfo, ALLOC, &out[i].ref) != VK_SUCCESS) { + LOG_E("Failed to create buffer"); + return memory::GetNull(); + } + + VkMemoryRequirements individualMemRequirements; + vkGetBufferMemoryRequirements(device, out[i].ref, &individualMemRequirements); + memRequirements.alignment = std::max(memRequirements.alignment, individualMemRequirements.alignment); + memRequirements.memoryTypeBits &= individualMemRequirements.memoryTypeBits; + sizes[i] = individualMemRequirements.size; + } + + // Align blocks + auto aligned = [&](VkDeviceSize offset) { + if (offset % memRequirements.alignment == 0) + return offset; + return offset + memRequirements.alignment - (offset % memRequirements.alignment); + }; + out[0].offset = 0; + for (size_t i = 1; i < out.size(); i++) { + out[i].offset = aligned(out[i-1].offset + sizes[i-1]); + } + memRequirements.size = out.back().offset; + out.pop_back(); + + // Bind memory + auto memory = alloc->allocate(memRequirements, properties); + if (!memory) { + LOG_E("Failed to allocate buffers"); + return memory::GetNull(); + } + for (size_t i = 0; i < requirements.size(); i++) { + if (vkBindBufferMemory(device, out[i].ref, memory->ref, memory->offset + out[i].offset) != VK_SUCCESS) { + LOG_E("Failed to bind buffer"); + return memory::GetNull(); + } + } + + VkDeviceSize stagingSize = 0; + for (auto& requirement: requirements) + if (requirement.view) + stagingSize = std::max(stagingSize, requirement.size); + + // Copy views + // MAYBE: allow single copy + if (stagingSize != 0) { + if (memory->ptr != nullptr) { + for (size_t i = 0; i < requirements.size(); i++) { + if (requirements[i].view) { + assert(requirements[i].view.size <= requirements[i].size); + memory->write(requirements[i].view.ptr, requirements[i].view.size, out[i].offset); + } + } + } else if(auto staging = WritableBuffer::Create(stagingSize)) { + for (size_t i = 0; i < requirements.size(); i++) { + if (requirements[i].view) { + assert(requirements[i].view.size <= requirements[i].size); + staging->write(requirements[i].view, 0); + alloc->copyBuffer(staging->getRef(), out[i].ref, requirements[i].size); + } + } + } else { + FATAL("Cannot allocate staging memory"); + return memory::GetNull(); + } + } + + return memory; +} + +void Buffer::MakeDefault() { } + +std::unique_ptr WritableBuffer::Create(size_t size, Usage usage, const data_view write) { + vk::Buffer::info tmp; + auto mem = createBuffer(size, static_cast(usage), memory::HOST_EASILY_WRITABLE, write, tmp); + return std::unique_ptr(new WritableBuffer(tmp.ref, std::move(mem), tmp.offset)); +} +void WritableBuffer::write(const data_view view, size_t offset) { + memory->write(view.ptr, view.size, memOffset + offset); +} +void WritableBuffer::read(data_ref ref, size_t offset) { + memory->read(ref.ptr, ref.size, memOffset + offset); +} + +ShortIndexedVertexBuffer::~ShortIndexedVertexBuffer() { + vkDestroyBuffer(Allocator::GetDefault()->getDevice(), vertex, ALLOC); + vkDestroyBuffer(Allocator::GetDefault()->getDevice(), index, ALLOC); + //NOTE: memory_ptr self destroy +} +std::unique_ptr ShortIndexedVertexBuffer::Create(const data_view vertices, const data_view indices) { + std::vector tmp; + auto mem = createBuffers({{vertices.size, Usage::VERTEX, vertices}, {indices.size, Usage::INDEX, indices}}, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, tmp); + return std::unique_ptr(new ShortIndexedVertexBuffer(tmp.at(0).ref, tmp.at(1).ref, std::move(mem))); +} + +BufferGroup::~BufferGroup() { + free(); +} + +void BufferGroup::allocate(const std::vector & reqs, bool writable) { + free(); + memory = createBuffers(reqs, writable ? memory::HOST_EASILY_WRITABLE : (VkMemoryPropertyFlags)VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, refs); +} +void BufferGroup::free() { + for (const auto& buffer: refs) { + vkDestroyBuffer(Allocator::GetDefault()->getDevice(), buffer.ref, ALLOC); + } + refs.clear(); + memory = memory::GetNull(); +} +void BufferGroup::write(size_t i, const data_view view) { + memory->write(view.ptr, view.size, refs.at(i).offset); +} \ No newline at end of file diff --git a/src/client/render/vk/api/Buffers.hpp b/src/client/render/vk/api/Buffers.hpp new file mode 100644 index 0000000..5e28488 --- /dev/null +++ b/src/client/render/vk/api/Buffers.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include "../../api/Buffers.hpp" +#include "Memory.hpp" +#include + +namespace render::vk { + +/// Self-container Vulkan buffer +class Buffer: public render::Buffer { +public: + ~Buffer(); + + VkBuffer getRef() const { return ref; } + + static void MakeDefault(); + + struct info { + VkBuffer ref = nullptr; + VkDeviceSize offset = 0; + }; + +protected: + Buffer(VkBuffer ref, memory::ptr mem): + ref(ref), memory(std::move(mem)) { } + VkBuffer ref; + memory::ptr memory; +}; + +/// Writable (aka Host visible) vulkan buffer +class WritableBuffer: public render::WritableBuffer, public Buffer { +public: + static std::unique_ptr Create(size_t size, Usage usage = Usage::TRANSFER_SRC, const data_view write = data_view()); + + void write(const data_view, size_t offset) override; + void read(data_ref, size_t offset) override; + + explicit operator bool() const { return ref && memory->ptr; } + +protected: + WritableBuffer(VkBuffer ref, memory::ptr mem, VkDeviceSize memOffset = 0): + vk::Buffer(ref, std::move(mem)), memOffset(memOffset) { } + const VkDeviceSize memOffset; +}; + +/// Fast (aka Device local local) vulkan buffer +class FastBuffer: public render::FastBuffer, public Buffer { +public: + +protected: + FastBuffer(VkBuffer ref, memory::ptr mem): + vk::Buffer(ref, std::move(mem)) { } +}; + +class ShortIndexedVertexBuffer: public render::ShortIndexedVertexBuffer { +public: + static std::unique_ptr Create(const data_view vertices, const data_view indices); + ~ShortIndexedVertexBuffer(); + + VkBuffer getVertex() const { return vertex; } + VkBuffer getIndex() const { return index; } + + explicit operator bool() const { return vertex && index; } + +protected: + ShortIndexedVertexBuffer(VkBuffer vertex, VkBuffer index, memory::ptr mem): + vertex(vertex), index(index), memory(std::move(mem)) { } + VkBuffer vertex; + VkBuffer index; + memory::ptr memory; +}; + +class BufferGroup { +public: + BufferGroup(): memory(memory::GetNull()) { } + ~BufferGroup(); + + void allocate(const std::vector &, bool writable); + VkBuffer at(size_t i) const { return refs.at(i).ref; } + /// Requires last allocate to be writable + void write(size_t, const data_view); + + explicit operator bool() const { return memory && !refs.empty(); } + +private: + void free(); + std::vector refs; + memory::ptr memory; +}; + +} \ No newline at end of file diff --git a/src/client/render/vk/api/Images.cpp b/src/client/render/vk/api/Images.cpp new file mode 100644 index 0000000..0bdb0ec --- /dev/null +++ b/src/client/render/vk/api/Images.cpp @@ -0,0 +1,139 @@ +#include "Images.hpp" +#include "Buffers.hpp" +#include "../Allocator.hpp" +#include "../../../../core/utils/logger.hpp" + +using namespace render::vk; + +Image::~Image() { + vkDestroyImage(Allocator::GetDefault()->getDevice(), ref, ALLOC); +} +Texture::~Texture() { + vkDestroySampler(Allocator::GetDefault()->getDevice(), sampler, ALLOC); + vkDestroyImageView(Allocator::GetDefault()->getDevice(), view, ALLOC); +} + +memory::ptr createImage(const Image::requirement& req, VkMemoryPropertyFlags properties, const render::data_view view, Image::info& out) { + auto alloc = Allocator::GetDefault(); + auto device = alloc->getDevice(); + + VkImageCreateInfo info{}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + info.imageType = VK_IMAGE_TYPE_2D; + info.extent.width = req.props.size.width; + info.extent.height = req.props.size.height; + info.extent.depth = 1; + info.mipLevels = req.props.mipMap; //TODO: + info.arrayLayers = 1; + info.format = static_cast(req.props.format); + info.tiling = req.linear ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; + info.initialLayout = static_cast(req.layout); + info.usage = static_cast(req.usage); + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.flags = 0; + if (view) { + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + if (vkCreateImage(device, &info, ALLOC, &out.ref) != VK_SUCCESS) { + LOG_E("Failed to create image"); + return memory::GetNull(); + } + out.offset = 0; + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, out.ref, &memRequirements); + + auto memory = alloc->allocate(memRequirements, properties, true); + if (!memory || vkBindImageMemory(device, out.ref, memory->ref, memory->offset) != VK_SUCCESS) { + LOG_E("Failed to allocate image memory"); + return memory::GetNull(); + } + + if (view) { + if(auto staging = WritableBuffer::Create(view.size)) { + staging->write(view, 0); + alloc->transitionImageLayout(out.ref, info.format, info.initialLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + alloc->copyBufferToImage(staging->getRef(), out.ref, info.extent.width, info.extent.height); + alloc->transitionImageLayout(out.ref, info.format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast(req.layout)); + } else { + FATAL("Cannot allocate staging memory"); + return memory::GetNull(); + } + } + return memory; +} +//TODO: createImages + +std::unique_ptr Texture::LoadFromFile(const std::string& path, const sampling& props) { + auto device = Allocator::GetDefault()->getDevice(); + + std::vector data; + auto header = [&] { + if (auto header = render::Image::Read(path, data)) { + return header.value(); + } + FATAL("Cannot read texture"); + }(); + + vk::Image::info img; + auto mem = createImage({header.size, header.mipMap, header.format, Layout::SHADER_READ_ONLY, Usage::SAMPLED, false}, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, data, img); + if(!mem) { + FATAL("Cannot create texture image"); + } + + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = img.ref; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = static_cast(header.format); + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = 1; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + VkImageView view; + if (vkCreateImageView(device, &viewInfo, ALLOC, &view) != VK_SUCCESS) { + FATAL("Failed to create texture image view!"); + } + + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = props.magLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + samplerInfo.minFilter = props.minLinear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; + + const auto wrap = static_cast(props.wrap); + samplerInfo.addressModeU = wrap; + samplerInfo.addressModeV = wrap; + samplerInfo.addressModeW = wrap; + + if (Allocator::GetDefault()->getCapabilities().anisotropy && props.anisotropy > 0) { + samplerInfo.anisotropyEnable = VK_TRUE; + samplerInfo.maxAnisotropy = 1 << (props.anisotropy-1); + } else { + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1.f; + } + + samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipLodBias = 0.0f; //TODO: + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 0.0f; + + VkSampler sampler; + if (vkCreateSampler(device, &samplerInfo, ALLOC, &sampler) != VK_SUCCESS) { + FATAL("Failed to create texture sampler!"); + } + + return std::unique_ptr(new Texture(sampler, view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, img.ref, std::move(mem))); +} \ No newline at end of file diff --git a/src/client/render/vk/api/Images.hpp b/src/client/render/vk/api/Images.hpp new file mode 100644 index 0000000..a07dd87 --- /dev/null +++ b/src/client/render/vk/api/Images.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "../../api/Images.hpp" +#include "Memory.hpp" + +namespace render::vk { + +class Image: public render::Image { +public: + virtual ~Image(); + + static void MakeDefault(); + + struct info { + VkImage ref = nullptr; + VkDeviceSize offset = 0; + }; + +protected: + Image(VkImage ref, memory::ptr mem): + ref(ref), memory(std::move(mem)) { } + VkImage ref; + memory::ptr memory; +}; + +class Texture: public render::Texture, Image { +public: + ~Texture(); + + const VkDescriptorImageInfo &getDescriptor() const { return descriptor; } + + static std::unique_ptr LoadFromFile(const std::string&, const sampling&); + +protected: + Texture(VkSampler sampler, VkImageView view, VkImageLayout layout, VkImage ref, memory::ptr memory): + vk::Image(ref, std::move(memory)), sampler(sampler), view(view), descriptor({sampler, view, layout}) { } + VkSampler sampler; + VkImageView view; + const VkDescriptorImageInfo descriptor; +}; + +} \ No newline at end of file diff --git a/src/client/render/vk/api/Memory.hpp b/src/client/render/vk/api/Memory.hpp new file mode 100644 index 0000000..a9badf8 --- /dev/null +++ b/src/client/render/vk/api/Memory.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "../forward.hpp" +#include + +namespace render::vk { struct Allocation; } +namespace render::vk::memory { + +constexpr VkMemoryPropertyFlags HOST_EASILY_WRITABLE = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; +struct area { + VkDeviceMemory ref; + VkDeviceSize size; + VkDeviceSize offset; + void *ptr = nullptr; + + void write(const void*, VkDeviceSize size, VkDeviceSize offset = 0); + void read(void*, VkDeviceSize size, VkDeviceSize offset = 0); +}; + +class Deleter { +public: + Deleter(Allocation *owner): owner(owner) { } + void operator()(area *); +private: + Allocation *owner; +}; + +using ptr = std::unique_ptr; + +ptr GetNull(); + +} \ No newline at end of file diff --git a/src/client/render/vk/buffer/Buffer.hpp b/src/client/render/vk/buffer/Buffer.hpp deleted file mode 100644 index 0c55b95..0000000 --- a/src/client/render/vk/buffer/Buffer.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include - -namespace buffer::vk { - -class MemoryArea { - -private: - VkDeviceMemory ref; - size_t size; - std::vector<> -}; -class Buffer { - -private: - std::weak_ptr<> - VkBuffer ref; - - size_t offset; - size_t size; - - // Only is mappable - void* data = nullptr; -}; - -} \ No newline at end of file diff --git a/src/client/render/vk/texture.cpp b/src/client/render/vk/texture.cpp deleted file mode 100644 index 7189c8a..0000000 --- a/src/client/render/vk/texture.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "texture.hpp" -#include -#include -#include -#include -#include -#include -#include - -#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII -#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII -#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII - -VkResult render::vk::dds::readDDS(const std::string& imagepath, std::vector& data, header_info& info) { - - unsigned char header[124]; - - FILE *fp; - - /* try to open the file */ - fp = fopen(imagepath.c_str(), "rb"); - if (fp == NULL){ - printf("%s could not be opened.\n", imagepath.c_str()); getchar(); - return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT; - } - - /* verify the type of file */ - char filecode[4]; - fread(filecode, 1, 4, fp); - if (strncmp(filecode, "DDS ", 4) != 0) { - fclose(fp); - return VK_ERROR_INVALID_DEVICE_ADDRESS_EXT; - } - - /* get the surface desc */ - fread(&header, 124, 1, fp); - - info.height = *(unsigned int*)&(header[8 ]); - info.width = *(unsigned int*)&(header[12]); - unsigned int linearSize = *(unsigned int*)&(header[16]); - info.mipMapCount = *(unsigned int*)&(header[24]); - unsigned int fourCC = *(unsigned int*)&(header[80]); - - - /* how big is it going to be including all mipmaps? */ - unsigned int bufsize = info.mipMapCount > 1 ? linearSize * 2 : linearSize; - data.resize(bufsize); - fread(data.data(), 1, bufsize, fp); - /* close the file pointer */ - fclose(fp); - - switch(fourCC) - { - case FOURCC_DXT1: - info.format = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; - break; - case FOURCC_DXT3: - info.format = VK_FORMAT_BC2_SRGB_BLOCK; - break; - case FOURCC_DXT5: - info.format = VK_FORMAT_BC3_SRGB_BLOCK; - break; - //MAYBE: VK_FORMAT_BC6H_SFLOAT_BLOCK - default: - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - -#if FALSE - glTextureParameteri(textureID, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); - glTextureParameteri(textureID, GL_TEXTURE_MIN_FILTER, linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST); - - TODO: glGenerateTextureMipmap(textureID); -#endif - return VK_SUCCESS; -} \ No newline at end of file diff --git a/src/client/render/vk/texture.hpp b/src/client/render/vk/texture.hpp deleted file mode 100644 index 56ca58d..0000000 --- a/src/client/render/vk/texture.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace render::vk::dds { -struct header_info { - unsigned int height; - unsigned int width; - unsigned int mipMapCount; - VkFormat format; -}; -VkResult readDDS(const std::string& imagepath, std::vector& data, header_info& info); -} \ No newline at end of file diff --git a/src/client/state.hpp b/src/client/state.hpp index 137ab33..7e9260d 100644 --- a/src/client/state.hpp +++ b/src/client/state.hpp @@ -10,7 +10,7 @@ struct state { camera_pos position = camera_pos(voxel_pos(0), 1); std::optional look_at = {}; - std::shared_ptr contouring; + contouring::Abstract* contouring; std::array console_buffer; }; diff --git a/src/client/world/DistantUniverse.cpp b/src/client/world/DistantUniverse.cpp index d1335fb..d68f723 100644 --- a/src/client/world/DistantUniverse.cpp +++ b/src/client/world/DistantUniverse.cpp @@ -11,7 +11,7 @@ using namespace world::client; -DistantUniverse::DistantUniverse(const connection& ct, const options& opt): Universe(), peer(ct), +DistantUniverse::DistantUniverse(const connection& ct, const options& opt, const std::string& contouring): Universe(contouring), peer(ct), loadDistance(opt.loadDistance), keepDistance(opt.keepDistance), serverDistance(0) { } DistantUniverse::~DistantUniverse() { } diff --git a/src/client/world/DistantUniverse.hpp b/src/client/world/DistantUniverse.hpp index e44096c..0da00f0 100644 --- a/src/client/world/DistantUniverse.hpp +++ b/src/client/world/DistantUniverse.hpp @@ -10,7 +10,7 @@ namespace world::client { /// Whole universe container in network client class DistantUniverse final: public Universe { public: - DistantUniverse(const connection&, const options &); + DistantUniverse(const connection&, const options &, const std::string&); ~DistantUniverse(); void update(voxel_pos, float) override; diff --git a/src/client/world/LocalUniverse.cpp b/src/client/world/LocalUniverse.cpp index 8a9a930..000dd3e 100644 --- a/src/client/world/LocalUniverse.cpp +++ b/src/client/world/LocalUniverse.cpp @@ -8,7 +8,7 @@ using namespace world::client; -LocalUniverse::LocalUniverse(server_handle *const handle): Universe(), handle(handle) { +LocalUniverse::LocalUniverse(server_handle *const handle, const std::string& contour): Universe(contour), handle(handle) { assert(handle != nullptr); for (auto i = 0; i < 500 && !handle->running; i++) { LOG_D("Waiting local server startup"); @@ -22,11 +22,6 @@ LocalUniverse::~LocalUniverse() { handle->running = false; } -void LocalUniverse::setContouring(const std::shared_ptr& ct) { - Universe::setContouring(ct); - last_chunk = chunk_pos(INT_MAX); -} - void LocalUniverse::update(voxel_pos pos, float) { const auto cur_chunk = glm::divide(pos); const auto chunkChange = cur_chunk != last_chunk; diff --git a/src/client/world/LocalUniverse.hpp b/src/client/world/LocalUniverse.hpp index c1e807b..7b01551 100644 --- a/src/client/world/LocalUniverse.hpp +++ b/src/client/world/LocalUniverse.hpp @@ -7,14 +7,12 @@ namespace world::client { /// Whole universe container in client with in-memory server class LocalUniverse final: public Universe { public: - LocalUniverse(server_handle *const handle); + LocalUniverse(server_handle *const handle, const std::string& contouring); ~LocalUniverse(); void update(voxel_pos pos, float deltaTime) override; void emit(const action::packet &) override; - void setContouring(const std::shared_ptr &ct) override; - ray_result raycast(const geometry::Ray &ray) const override; protected: diff --git a/src/client/world/Universe.cpp b/src/client/world/Universe.cpp index 4dd5cfa..f1f67b6 100644 --- a/src/client/world/Universe.cpp +++ b/src/client/world/Universe.cpp @@ -1,16 +1,12 @@ #include "Universe.hpp" -#include "../contouring/Dummy.hpp" +#include "../contouring/FlatDualMC.hpp" using namespace world::client; -Universe::Universe(): world::Universe(), contouring(std::make_shared()) { } +Universe::Universe(const std::string& ct): world::Universe(), contouring(std::make_unique(ct)) { } Universe::~Universe() { } -void Universe::setContouring(const std::shared_ptr& ct) { - contouring = ct; -} - /* void ServerUniverse::getEntitiesModels(const std::function&, buffer::Abstract *const)> &draw, const std::optional &frustum, const glm::llvec3 &offset, int density) { std::vector mats; diff --git a/src/client/world/Universe.hpp b/src/client/world/Universe.hpp index bd2589f..2c55ab3 100644 --- a/src/client/world/Universe.hpp +++ b/src/client/world/Universe.hpp @@ -12,7 +12,7 @@ namespace world::client { /// Whole universe container in abstract client class Universe: public world::Universe { public: - Universe(); + Universe(const std::string& contouring); virtual ~Universe(); struct connection: net::connection { @@ -25,11 +25,9 @@ namespace world::client { /// Send action to ServerUniverse virtual void emit(const action::packet &) = 0; - /// Change contouring worker - virtual void setContouring(const std::shared_ptr &ct); /// Get current contouring worker - std::shared_ptr getContouring() const { - return contouring; + contouring::Abstract* getContouring() const { + return contouring.get(); } //TODO: move to ClientUniverse @@ -37,6 +35,6 @@ namespace world::client { protected: /// Contouring worker - std::shared_ptr contouring; + std::unique_ptr contouring; }; } \ No newline at end of file diff --git a/src/client/world/index.cpp b/src/client/world/index.cpp index f65f697..c857f85 100644 --- a/src/client/world/index.cpp +++ b/src/client/world/index.cpp @@ -6,13 +6,13 @@ #include "../../core/utils/logger.hpp" namespace world::client { - std::unique_ptr Load(const std::optional& ct, server_handle *const localHandle, const Universe::options &distOpts) { + std::unique_ptr Load(const std::optional& ct, server_handle *const localHandle, const Universe::options &distOpts, const std::string& contouring) { if(ct.has_value()) { - return std::make_unique(ct.value(), distOpts); + return std::make_unique(ct.value(), distOpts, contouring); #ifndef STANDALONE } else if(localHandle != nullptr) { LOG_D("Using local universe"); - return std::make_unique(localHandle); + return std::make_unique(localHandle, contouring); #endif } else { FATAL("Must enable server.allow_local or define client.connection"); diff --git a/src/client/world/index.hpp b/src/client/world/index.hpp index d1a2648..6cf690c 100644 --- a/src/client/world/index.hpp +++ b/src/client/world/index.hpp @@ -4,5 +4,5 @@ #include "../../core/server_handle.hpp" namespace world::client { - std::unique_ptr Load(const std::optional& ct, server_handle *const localHandle, const Universe::options& distOpts); + std::unique_ptr Load(const std::optional& ct, server_handle *const localHandle, const Universe::options& distOpts, const std::string& contouring); } diff --git a/src/server/Server.hpp b/src/server/Server.hpp index 33406e8..caebc95 100644 --- a/src/server/Server.hpp +++ b/src/server/Server.hpp @@ -14,7 +14,7 @@ public: void run(); - server_handle *const getHandle() { return localHandle; } + server_handle *getHandle() { return localHandle; } private: config::server::options& options;