Remove some useless allocations
This commit is contained in:
parent
9e9bb8987f
commit
f7c2f7069e
|
@ -370,10 +370,9 @@ namespace contouring {
|
||||||
const auto area_offset = glm::divide(std::get<0>(area.first).as_voxel());
|
const auto area_offset = glm::divide(std::get<0>(area.first).as_voxel());
|
||||||
robin_hood::unordered_set<chunk_pos> done;
|
robin_hood::unordered_set<chunk_pos> done;
|
||||||
for (const auto& occ: occlusion) {
|
for (const auto& occ: occlusion) {
|
||||||
const geometry::Ray ray(start, occ, dist);
|
geometry::Ray::iterator it(geometry::Ray(start, occ, dist));
|
||||||
std::vector<voxel_pos> points; //TODO: iterator
|
glm::llvec3 point;
|
||||||
ray.grid(points);
|
while (it.next(point)) {
|
||||||
for(auto& point: points) {
|
|
||||||
auto it = area.second.find(glm::lvec3(point) - area_offset);
|
auto it = area.second.find(glm::lvec3(point) - area_offset);
|
||||||
const auto buffer = solid ? it->second.first : it->second.second;
|
const auto buffer = solid ? it->second.first : it->second.second;
|
||||||
if(it != area.second.end() && buffer != NULL && done.insert(it->first).second) {
|
if(it != area.second.end() && buffer != NULL && done.insert(it->first).second) {
|
||||||
|
|
|
@ -61,9 +61,17 @@ int Client::connectionCallback(uint64_t stream_id, uint8_t* bytes, size_t length
|
||||||
case picoquic_callback_stream_fin: {
|
case picoquic_callback_stream_fin: {
|
||||||
assert(stream_ctx::IsServerId(stream_id));
|
assert(stream_ctx::IsServerId(stream_id));
|
||||||
auto stream_ctx = (in_stream_ctx *)v_stream_ctx;
|
auto stream_ctx = (in_stream_ctx *)v_stream_ctx;
|
||||||
|
const auto is_fin = fin_or_event == picoquic_callback_stream_fin;
|
||||||
|
|
||||||
/* Data arrival on stream #x, maybe with fin mark */
|
if (stream_ctx == NULL) {
|
||||||
if (stream_ctx == NULL) { // New stream from server
|
if (is_fin) { // Single frame packet
|
||||||
|
if (length > 0) {
|
||||||
|
onPacket(data::out_view(bytes, length), PacketFlags::TINY);
|
||||||
|
}
|
||||||
|
reset(stream_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// New long stream from server
|
||||||
stream_ctx = receive(stream_id);
|
stream_ctx = receive(stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +79,7 @@ int Client::connectionCallback(uint64_t stream_id, uint8_t* bytes, size_t length
|
||||||
stream_ctx->buffer.write(bytes, length);
|
stream_ctx->buffer.write(bytes, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fin_or_event == picoquic_callback_stream_fin) {
|
if (is_fin) {
|
||||||
if (onPacket(data::out_view(stream_ctx->buffer.data.data(), stream_ctx->buffer.data.size()), PacketFlags::NONE)) {
|
if (onPacket(data::out_view(stream_ctx->buffer.data.data(), stream_ctx->buffer.data.size()), PacketFlags::NONE)) {
|
||||||
close(stream_ctx);
|
close(stream_ctx);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include "../data/mem.hpp"
|
||||||
#include "../utils/logger.hpp"
|
#include "../utils/logger.hpp"
|
||||||
|
|
||||||
namespace data {
|
namespace data {
|
||||||
|
@ -9,7 +9,9 @@ namespace data {
|
||||||
class file_content: public std::vector<char> {
|
class file_content: public std::vector<char> {
|
||||||
public:
|
public:
|
||||||
// Read first
|
// Read first
|
||||||
file_content(const std::vector<std::string>& paths): std::vector<char>() {
|
file_content(const std::vector<std::string>& paths, data::out_view prefix = data::out_view(nullptr, 0)):
|
||||||
|
std::vector<char>(), prefix_size(prefix.size())
|
||||||
|
{
|
||||||
std::ifstream is = [&]() {
|
std::ifstream is = [&]() {
|
||||||
for(auto& path: paths) {
|
for(auto& path: paths) {
|
||||||
std::ifstream is(path, std::ios::in | std::ios::binary | std::ios::ate);
|
std::ifstream is(path, std::ios::in | std::ios::binary | std::ios::ate);
|
||||||
|
@ -22,10 +24,18 @@ public:
|
||||||
}();
|
}();
|
||||||
const auto end = is.tellg();
|
const auto end = is.tellg();
|
||||||
is.seekg(0, std::ios::beg);
|
is.seekg(0, std::ios::beg);
|
||||||
resize(end - is.tellg());
|
resize(end - is.tellg() + prefix_size);
|
||||||
is.read(data(), size());
|
memcpy(data(), prefix.ptr, prefix_size);
|
||||||
|
is.read(data() + prefix_size, size());
|
||||||
is.close();
|
is.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t prefix_size;
|
||||||
|
|
||||||
|
/// Data after prefix
|
||||||
|
data::out_view content() const {
|
||||||
|
return data::out_view((const uint8_t*)data() + prefix_size, size() - prefix_size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace data {
|
namespace data {
|
||||||
|
|
|
@ -83,6 +83,55 @@ namespace geometry {
|
||||||
}
|
}
|
||||||
points.push_back(current);
|
points.push_back(current);
|
||||||
}
|
}
|
||||||
|
/// Iterator implementation of grid
|
||||||
|
struct iterator {
|
||||||
|
enum class axis { X, Y, Z };
|
||||||
|
|
||||||
|
iterator(const Ray& r): current(r.from.as_voxel()),
|
||||||
|
d(r.dir * r.dist), l(glm::abs(d)),
|
||||||
|
dir((l.x >= l.y) && (l.x >= l.z) ? axis::X : ((l.y >= l.x) && (l.y >= l.z) ? axis::Y : axis::Z)),
|
||||||
|
count(dir == axis::X ? l.x : (dir == axis::Y ? l.y : l.z)),
|
||||||
|
inc(swap(glm::llvec3((d.x < 0) ? -1 : 1, (d.y < 0) ? -1 : 1, (d.z < 0) ? -1 : 1), dir)),
|
||||||
|
delta(swap(l << 1ll, dir)), err_1(delta.y - count), err_2(delta.z - count) { }
|
||||||
|
|
||||||
|
static constexpr inline glm::llvec3 swap(const glm::llvec3& in, const axis dir) { return dir == axis::X ? in :
|
||||||
|
(dir == axis::Y ? glm::llvec3(in.y, in.z, in.x) : glm::llvec3(in.z, in.x, in.y)); }
|
||||||
|
|
||||||
|
static constexpr inline long long& get(glm::llvec3& in, const axis dir, const axis target) {
|
||||||
|
const axis v = (axis)(((int)dir + (int)target) % 3);
|
||||||
|
return v == axis::X ? in.x : (v == axis::Y ? in.y : in.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next(glm::llvec3& out) {
|
||||||
|
if (count < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
count--;
|
||||||
|
out = current;
|
||||||
|
if (err_1 > 0) {
|
||||||
|
get(current, dir, axis::Y) += inc.y;
|
||||||
|
err_1 -= delta.x;
|
||||||
|
}
|
||||||
|
if (err_2 > 0) {
|
||||||
|
get(current, dir, axis::Z) += inc.z;
|
||||||
|
err_2 -= delta.x;
|
||||||
|
}
|
||||||
|
err_1 += delta.y;
|
||||||
|
err_2 += delta.z;
|
||||||
|
get(current, dir, axis::X) += inc.x;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::llvec3 current;
|
||||||
|
const glm::llvec3 d;
|
||||||
|
const glm::llvec3 l;
|
||||||
|
const axis dir;
|
||||||
|
glm::llvec3::value_type count;
|
||||||
|
const glm::llvec3 inc;
|
||||||
|
const glm::llvec3 delta;
|
||||||
|
int err_1;
|
||||||
|
int err_2;
|
||||||
|
};
|
||||||
|
|
||||||
IBox::ContainmentType intersect(const IBox& box) const {
|
IBox::ContainmentType intersect(const IBox& box) const {
|
||||||
const glm::llvec3 start = from.as_voxel();
|
const glm::llvec3 start = from.as_voxel();
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct in_stream_ctx: stream_ctx {
|
||||||
enum class PacketFlags {
|
enum class PacketFlags {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
DATAGRAM = 1 << 0,
|
DATAGRAM = 1 << 0,
|
||||||
|
TINY = 1 << 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract QUIC context
|
/// Abstract QUIC context
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
namespace net {
|
namespace net {
|
||||||
|
|
||||||
//TODO: preallocate static data pool
|
//TODO: preallocate static data pool
|
||||||
|
|
||||||
|
/// Write allocated packets
|
||||||
class PacketWriter final {
|
class PacketWriter final {
|
||||||
public:
|
public:
|
||||||
PacketWriter(size_t size): buffer((uint8_t*)malloc(size), size) { }
|
PacketWriter(size_t size): buffer((uint8_t*)malloc(size), size) { }
|
||||||
|
@ -27,6 +29,37 @@ public:
|
||||||
write(&d, sizeof(d));
|
write(&d, sizeof(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct varying_part {
|
||||||
|
varying_part(data::in_view &buffer): buffer(buffer), visible_size(0) { }
|
||||||
|
~varying_part() {
|
||||||
|
buffer.siz = buffer.cur + visible_size;
|
||||||
|
buffer.cur = buffer.siz;
|
||||||
|
}
|
||||||
|
|
||||||
|
data::in_view &buffer;
|
||||||
|
size_t visible_size;
|
||||||
|
|
||||||
|
constexpr size_t size() const { return visible_size; }
|
||||||
|
void* data() { return buffer.writeTo(0); }
|
||||||
|
void reserve(size_t target) {
|
||||||
|
if (target >= buffer.siz - buffer.cur) {
|
||||||
|
auto old = buffer.ptr;
|
||||||
|
buffer.ptr = (uint8_t*)malloc(target);
|
||||||
|
memcpy(buffer.ptr, old, buffer.siz);
|
||||||
|
free(old);
|
||||||
|
buffer.siz = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void resize(size_t target) {
|
||||||
|
reserve(target);
|
||||||
|
visible_size = target;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/// Only from resize, write, resize down
|
||||||
|
varying_part varying() {
|
||||||
|
return varying_part(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
bool isFull() const {
|
bool isFull() const {
|
||||||
return buffer.isDone();
|
return buffer.isDone();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
#include <vector>
|
#include "../data/mem.hpp"
|
||||||
#include <cassert>
|
|
||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
|
|
||||||
namespace zstd {
|
namespace zstd {
|
||||||
|
@ -73,6 +72,7 @@ namespace zstd {
|
||||||
class dict_set {
|
class dict_set {
|
||||||
public:
|
public:
|
||||||
dict_set(const std::vector<char>& data) { load(data.data(), data.size()); }
|
dict_set(const std::vector<char>& data) { load(data.data(), data.size()); }
|
||||||
|
dict_set(const data::out_view& data) { load(data.data(), data.size()); }
|
||||||
~dict_set() {
|
~dict_set() {
|
||||||
ZSTD_freeCDict(c);
|
ZSTD_freeCDict(c);
|
||||||
ZSTD_freeDDict(d);
|
ZSTD_freeDDict(d);
|
||||||
|
|
|
@ -7,20 +7,19 @@ namespace world {
|
||||||
|
|
||||||
template<class Areas>
|
template<class Areas>
|
||||||
Universe::ray_result Raycast(const geometry::Ray& ray, const Areas& areas) {
|
Universe::ray_result Raycast(const geometry::Ray& ray, const Areas& areas) {
|
||||||
//TODO: iterator
|
|
||||||
//MAYBE: ray + offset to get float precision
|
//MAYBE: ray + offset to get float precision
|
||||||
std::vector<voxel_pos> points;
|
|
||||||
ray.grid(points);
|
|
||||||
Universe::ray_result target;
|
Universe::ray_result target;
|
||||||
size_t dist = points.size();
|
size_t dist = UINT32_MAX - 1;
|
||||||
for(auto& area: areas) {
|
for(auto& area: areas) {
|
||||||
if(ray.intersect(area.second->getBounding()) != geometry::IBox::ContainmentType::Disjoint) {
|
if(ray.intersect(area.second->getBounding()) != geometry::IBox::ContainmentType::Disjoint) {
|
||||||
const auto &offset = area.second->getOffset().as_voxel();
|
const auto &offset = area.second->getOffset().as_voxel();
|
||||||
const auto &chunks = area.second->getChunks();
|
const auto &chunks = area.second->getChunks();
|
||||||
std::shared_ptr<world::Chunk> chunk = nullptr;
|
std::shared_ptr<world::Chunk> chunk = nullptr;
|
||||||
chunk_pos chunk_vec(INT_MAX);
|
chunk_pos chunk_vec(INT_MAX);
|
||||||
for (size_t i = 0; i < dist; i++) {
|
geometry::Ray::iterator it(ray);
|
||||||
const auto pos = points[i] - offset;
|
glm::llvec3 point;
|
||||||
|
for (size_t i = 0; i < dist && it.next(point); i++) {
|
||||||
|
const auto pos = point - offset;
|
||||||
const chunk_pos cPos = glm::divide(pos);
|
const chunk_pos cPos = glm::divide(pos);
|
||||||
if(cPos != chunk_vec) {
|
if(cPos != chunk_vec) {
|
||||||
if (const auto it = chunks.find(cPos); it != chunks.end()) {
|
if (const auto it = chunks.find(cPos); it != chunks.end()) {
|
||||||
|
|
|
@ -58,9 +58,17 @@ int Server::connectionCallback(Peer* peer, uint64_t stream_id, uint8_t* bytes, s
|
||||||
case picoquic_callback_stream_fin: {
|
case picoquic_callback_stream_fin: {
|
||||||
assert(stream_ctx::IsClientId(stream_id));
|
assert(stream_ctx::IsClientId(stream_id));
|
||||||
auto stream_ctx = (in_stream_ctx *)v_stream_ctx;
|
auto stream_ctx = (in_stream_ctx *)v_stream_ctx;
|
||||||
|
const auto is_fin = fin_or_event == picoquic_callback_stream_fin;
|
||||||
|
|
||||||
/* Data arrival on stream #x, maybe with fin mark */
|
if (stream_ctx == NULL) {
|
||||||
if (stream_ctx == NULL) { // New stream from peer
|
if (is_fin) { // Single frame packet
|
||||||
|
if (length > 0) {
|
||||||
|
onPacket(peer, data::out_view(bytes, length), PacketFlags::TINY);
|
||||||
|
}
|
||||||
|
peer->reset(stream_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// New long stream from server
|
||||||
stream_ctx = peer->receive(stream_id);
|
stream_ctx = peer->receive(stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +76,7 @@ int Server::connectionCallback(Peer* peer, uint64_t stream_id, uint8_t* bytes, s
|
||||||
stream_ctx->buffer.write(bytes, length);
|
stream_ctx->buffer.write(bytes, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fin_or_event == picoquic_callback_stream_fin) {
|
if (is_fin) {
|
||||||
if (onPacket(peer, data::out_view(stream_ctx->buffer.data.data(), stream_ctx->buffer.data.size()), PacketFlags::NONE)) {
|
if (onPacket(peer, data::out_view(stream_ctx->buffer.data.data(), stream_ctx->buffer.data.size()), PacketFlags::NONE)) {
|
||||||
peer->close(stream_ctx);
|
peer->close(stream_ctx);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
using namespace world::server;
|
using namespace world::server;
|
||||||
|
|
||||||
const auto AREAS_FILE = "/areas.idx";
|
const auto AREAS_FILE = "/areas.idx";
|
||||||
|
const auto COMPRESSION_PREFIX = (uint8_t)net::server_packet_type::COMPRESSION;
|
||||||
|
|
||||||
Universe::Universe(const Universe::options &options): host(options.connection,
|
Universe::Universe(const Universe::options &options): host(options.connection,
|
||||||
[&](net::server::Peer* peer) { return onConnect(peer); },
|
[&](net::server::Peer* peer) { return onConnect(peer); },
|
||||||
[&](net::server::Peer* peer, bool is_app, uint16_t reason) { return onDisconnect(peer, is_app, reason); },
|
[&](net::server::Peer* peer, bool is_app, uint16_t reason) { return onDisconnect(peer, is_app, reason); },
|
||||||
[&](net::server::Peer* peer, const data::out_view &buf, net::PacketFlags flags) { return onPacket(peer, buf, flags); }
|
[&](net::server::Peer* peer, const data::out_view &buf, net::PacketFlags flags) { return onPacket(peer, buf, flags); }
|
||||||
), dict_content({options.folderPath + "/zstd.dict", "content/zstd.dict"}), dicts(dict_content), dict_write_ctx(dicts.make_writer())
|
), dict_content({options.folderPath + "/zstd.dict", "content/zstd.dict"}, data::out_view(&COMPRESSION_PREFIX, sizeof(COMPRESSION_PREFIX))),
|
||||||
|
dicts(dict_content.content()), dict_write_ctx(dicts.make_writer())
|
||||||
{
|
{
|
||||||
setOptions(options);
|
setOptions(options);
|
||||||
folderPath = options.folderPath;
|
folderPath = options.folderPath;
|
||||||
|
@ -453,9 +455,7 @@ std::optional<uint16_t> Universe::onConnect(net::server::Peer* peer) {
|
||||||
peer->send(net::PacketWriter::Of(net::server_packet_type::CAPABILITIES, loadDistance));
|
peer->send(net::PacketWriter::Of(net::server_packet_type::CAPABILITIES, loadDistance));
|
||||||
|
|
||||||
//TODO: lock while not received
|
//TODO: lock while not received
|
||||||
//MAYBE: add net::server_packet_type::COMPRESSION to dict_content: zero copy
|
peer->send(data::out_buffer(data::out_view((uint8_t*)dict_content.data(), dict_content.size()), nullptr), net::server::queue::CHUNK);
|
||||||
peer->send(net::PacketWriter::Of(net::server_packet_type::COMPRESSION, dict_content.data(), dict_content.size()), net::server::queue::CHUNK);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto player = findEntity(PLAYER_ENTITY_ID, client->instanceId);
|
auto player = findEntity(PLAYER_ENTITY_ID, client->instanceId);
|
||||||
auto packet = net::PacketWriter(net::server_packet_type::TELEPORT, sizeof(size_t) + sizeof(voxel_pos));
|
auto packet = net::PacketWriter(net::server_packet_type::TELEPORT, sizeof(size_t) + sizeof(voxel_pos));
|
||||||
|
@ -582,12 +582,12 @@ data::out_buffer Universe::serializeChunk(area_<chunk_pos> id, const std::shared
|
||||||
ZoneScopedN("Chunk");
|
ZoneScopedN("Chunk");
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
data->write(out);
|
data->write(out);
|
||||||
std::vector<char> buffer;
|
auto packet = net::PacketWriter(net::server_packet_type::CHUNK, sizeof(id));
|
||||||
//FIXME: avoid buffer copy
|
|
||||||
dict_write_ctx.compress(out.str(), buffer);
|
|
||||||
auto packet = net::PacketWriter(net::server_packet_type::CHUNK, sizeof(id) + buffer.size());
|
|
||||||
packet.write(id);
|
packet.write(id);
|
||||||
packet.write(buffer.data(), buffer.size());
|
{
|
||||||
|
auto vec = packet.varying();
|
||||||
|
dict_write_ctx.compress(out.str(), vec);
|
||||||
|
}
|
||||||
return packet.finish();
|
return packet.finish();
|
||||||
}
|
}
|
||||||
void Universe::broadcastMessage(const std::string& text) {
|
void Universe::broadcastMessage(const std::string& text) {
|
||||||
|
|
Loading…
Reference in New Issue