godot_voxel/generators/graph/voxel_graph_compiler.h
2022-04-15 16:09:35 +01:00

117 lines
3.6 KiB
C++

#ifndef VOXEL_GRAPH_COMPILER_H
#define VOXEL_GRAPH_COMPILER_H
#include "voxel_graph_runtime.h"
namespace zylann::voxel {
struct PortRemap {
ProgramGraph::PortLocation original;
ProgramGraph::PortLocation expanded;
};
struct ExpandedNodeRemap {
uint32_t expanded_node_id;
uint32_t original_node_id;
};
struct GraphRemappingInfo {
std::vector<PortRemap> user_to_expanded_ports;
std::vector<ExpandedNodeRemap> expanded_to_user_node_ids;
};
VoxelGraphRuntime::CompilationResult expand_expression_nodes(
ProgramGraph &graph, const VoxelGraphNodeDB &type_db, GraphRemappingInfo *remap_info);
// Functions usable by node implementations during the compilation stage
class CompileContext {
public:
CompileContext(/*const ProgramGraph::Node &node,*/ std::vector<uint16_t> &program,
std::vector<VoxelGraphRuntime::HeapResource> &heap_resources, std::vector<Variant> &params) :
/*_node(node),*/ _program(program), _heap_resources(heap_resources), _params(params) {}
Variant get_param(size_t i) const {
CRASH_COND(i > _params.size());
return _params[i];
}
// Typical use is to pass a struct containing all compile-time arguments the operation will need
template <typename T>
void set_params(T params) {
// Can be called only once per node
CRASH_COND(_params_added);
// We will need to align memory, so the struct will not be immediately stored here.
// Instead we put a header that tells how much to advance in order to reach the beginning of the struct,
// which will be at an aligned position.
// We align to the maximum alignment between the struct,
// and the type of word we store inside the program buffer, which is uint16.
const size_t params_alignment = math::max(alignof(T), alignof(uint16_t));
const size_t params_offset_index = _program.size();
// Prepare space to store the offset (at least 1 since that header is one word)
_program.push_back(1);
// Align memory for the struct.
// Note, we index with words, not bytes.
const size_t struct_offset =
math::alignup(_program.size() * sizeof(uint16_t), params_alignment) / sizeof(uint16_t);
if (struct_offset > _program.size()) {
_program.resize(struct_offset);
}
// Write offset in header
_program[params_offset_index] = struct_offset - params_offset_index;
// Allocate space for the struct. It is measured in words, so it can be up to 1 byte larger.
_params_size_in_words = (sizeof(T) + sizeof(uint16_t) - 1) / sizeof(uint16_t);
_program.resize(_program.size() + _params_size_in_words);
// Write struct
T &p = *reinterpret_cast<T *>(&_program[struct_offset]);
p = params;
_params_added = true;
}
// In case the compilation step produces a resource to be deleted
template <typename T>
void add_memdelete_cleanup(T *ptr) {
VoxelGraphRuntime::HeapResource hr;
hr.ptr = ptr;
hr.deleter = [](void *p) {
// TODO We have no guarantee it was allocated with memnew :|
T *tp = reinterpret_cast<T *>(p);
memdelete(tp);
};
_heap_resources.push_back(hr);
}
void make_error(String message) {
_error_message = message;
_has_error = true;
}
bool has_error() const {
return _has_error;
}
const String &get_error_message() const {
return _error_message;
}
size_t get_params_size_in_words() const {
return _params_size_in_words;
}
private:
//const ProgramGraph::Node &_node;
std::vector<uint16_t> &_program;
std::vector<VoxelGraphRuntime::HeapResource> &_heap_resources;
std::vector<Variant> &_params;
String _error_message;
size_t _params_size_in_words = 0;
bool _has_error = false;
bool _params_added = false;
};
typedef void (*CompileFunc)(CompileContext &);
} // namespace zylann::voxel
#endif // VOXEL_GRAPH_COMPILER_H