Quick cleanup, also patch preview nodes

master
Marc Gilleron 2021-01-07 23:36:14 +00:00
parent e00ed9b538
commit 04c1d61cd2
4 changed files with 46 additions and 67 deletions

View File

@ -580,6 +580,7 @@ void VoxelGraphEditor::update_previews() {
for (size_t i = 0; i < previews.size(); ++i) {
PreviewInfo &info = previews[i];
// TODO This won't work efficiently since we use buffers, we should use a different method
const float v = runtime.get_memory_value(info.address);
const float g = clamp((v - info.min_value) * info.value_scale, 0.f, 1.f);
info.control->get_image()->set_pixel(ix, iy, Color(g, g, g));

View File

@ -284,6 +284,9 @@ VoxelGraphNodeDB::VoxelGraphNodeDB() {
// TODO Most operations need SIMD support
// SUGG the program could be a list of pointers to polymorphic heap-allocated classes...
// but I find that the data struct approach is kinda convenient too?
{
NodeType &t = types[VoxelGeneratorGraph::NODE_CONSTANT];
t.name = "Constant";

View File

@ -18,11 +18,11 @@
//#endif
template <typename T>
inline const T &read(const std::vector<uint8_t> &mem, uint32_t &p) {
inline const T &read(const ArraySlice<uint8_t> &mem, uint32_t &p) {
#ifdef DEBUG_ENABLED
CRASH_COND(p + sizeof(T) > mem.size());
#endif
const T *v = (const T *)&mem[p];
const T *v = reinterpret_cast<const T *>(&mem[p]);
p += sizeof(T);
return *v;
}
@ -44,12 +44,10 @@ VoxelGraphRuntime::~VoxelGraphRuntime() {
void VoxelGraphRuntime::clear() {
_program.clear();
_memory.resize(8, 0);
_ranges.resize(4, Interval());
_xzy_program_start = 0;
const float fmax = std::numeric_limits<float>::max();
_last_x = fmax;
_last_z = fmax;
_xz_last_min = Vector2(fmax, fmax);
_xz_last_max = Vector2(fmax, fmax);
@ -74,12 +72,6 @@ void VoxelGraphRuntime::clear() {
r.deleter(r.ptr);
}
_heap_resources.clear();
// for (size_t i = 0; i < _image_range_grids.size(); ++i) {
// ImageRangeGrid *im = _image_range_grids[i];
// memdelete(im);
// }
// _image_range_grids.clear();
}
bool VoxelGraphRuntime::compile(const ProgramGraph &graph, bool debug) {
@ -178,15 +170,15 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
// const uint32_t *order_raw = order.data();
//#endif
_memory.clear();
_ranges.clear();
struct MemoryHelper {
std::vector<float> &value_mem;
std::vector<Interval> &ra_mem;
std::vector<Buffer> &buffer_mem;
uint16_t add_var() {
uint16_t a = value_mem.size();
value_mem.push_back(0.f);
uint16_t a = ra_mem.size();
ra_mem.push_back(Interval());
Buffer b;
b.data = nullptr;
b.is_constant = false;
@ -195,8 +187,8 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
}
uint16_t add_constant(float v) {
uint16_t a = value_mem.size();
value_mem.push_back(v);
uint16_t a = ra_mem.size();
ra_mem.push_back(Interval::from_single_value(v));
Buffer b;
b.data = nullptr;
b.is_constant = true;
@ -206,7 +198,7 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
}
};
MemoryHelper mem{ _memory, _buffers };
MemoryHelper mem{ _ranges, _buffers };
// Main inputs X, Y, Z
mem.add_var();
@ -230,6 +222,7 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
_xzy_program_start = _program.size();
}
// We still hardcode some of the nodes. Maybe we can abstract them too one day.
switch (node->type_id) {
case VoxelGeneratorGraph::NODE_CONSTANT: {
CRASH_COND(type.outputs.size() != 1);
@ -258,8 +251,8 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
_compilation_result.node_id = node_id;
return false;
}
if (_memory.size() > 0) {
_sdf_output_address = _memory.size() - 1;
if (_buffers.size() > 0) {
_sdf_output_address = _buffers.size() - 1;
}
break;
@ -336,20 +329,12 @@ bool VoxelGraphRuntime::_compile(const ProgramGraph &graph, bool debug) {
} // switch type
}
// In case there is nothing
while (_memory.size() < 4) {
// In case there is nothing, add minimal nodes for correctness
while (_buffers.size() < 4) {
mem.add_var();
}
// Reserve space for range analysis
_memory.resize(_memory.size() * 2);
// Make it a copy to keep eventual constants at consistent adresses
const size_t half_size = _memory.size() / 2;
for (size_t i = 0, j = half_size; i < half_size; ++i, ++j) {
_memory[j] = _memory[i];
}
CRASH_COND(_buffers.size() != half_size);
CRASH_COND(_buffers.size() != _ranges.size());
PRINT_VERBOSE(String("Compiled voxel graph. Program size: {0}b, buffers: {1}")
.format(varray(
@ -386,7 +371,7 @@ void VoxelGraphRuntime::generate_xz_slice(ArraySlice<float> dst, Vector2i dst_si
#ifdef DEBUG_ENABLED
CRASH_COND(_buffers.size() == 0);
CRASH_COND(_buffers.size() != _memory.size() / 2);
CRASH_COND(_buffers.size() != _ranges.size());
#endif
#ifdef TOOLS_ENABLED
ERR_FAIL_COND_MSG(!has_output(), "The graph has no SDF output");
@ -399,10 +384,7 @@ void VoxelGraphRuntime::generate_xz_slice(ArraySlice<float> dst, Vector2i dst_si
// Input buffers
{
// TODO When not using range analysis, it should be possible to fill the input buffers with whatever we want.
// So eventually we should put these buffers out
// TODO User-provided buffers may not need to be owned, or even recomputed
// TODO Move this away from here, allow to specify custom inputs
Buffer &x_buffer = buffers[0];
Buffer &y_buffer = buffers[1];
@ -515,8 +497,8 @@ void VoxelGraphRuntime::generate_xz_slice(ArraySlice<float> dst, Vector2i dst_si
const ArraySlice<uint8_t> program(_program, 0, _program.size());
while (pc < _program.size()) {
const uint8_t opid = _program[pc++];
while (pc < program.size()) {
const uint8_t opid = program[pc++];
const VoxelGraphNodeDB::NodeType &node_type = VoxelGraphNodeDB::get_singleton()->get_type(opid);
const uint32_t inputs_size = node_type.inputs.size() * sizeof(uint16_t);
@ -527,7 +509,7 @@ void VoxelGraphRuntime::generate_xz_slice(ArraySlice<float> dst, Vector2i dst_si
const ArraySlice<uint16_t> outputs = program.sub(pc, outputs_size).reinterpret_cast_to<uint16_t>();
pc += outputs_size;
const uint16_t params_size = read<uint16_t>(_program, pc);
const uint16_t params_size = read<uint16_t>(program, pc);
ArraySlice<uint8_t> params;
if (params_size > 0) {
params = program.sub(pc, params_size);
@ -559,25 +541,23 @@ void VoxelGraphRuntime::generate_xz_slice(ArraySlice<float> dst, Vector2i dst_si
}
}
// TODO Accept float bounds
Interval VoxelGraphRuntime::analyze_range(Vector3i min_pos, Vector3i max_pos) {
#ifdef TOOLS_ENABLED
ERR_FAIL_COND_V_MSG(!has_output(), Interval(), "The graph has no SDF output");
#endif
ArraySlice<float> min_memory(_memory, 0, _memory.size() / 2);
ArraySlice<float> max_memory(_memory, _memory.size() / 2, _memory.size());
min_memory[0] = min_pos.x;
min_memory[1] = min_pos.y;
min_memory[2] = min_pos.z;
max_memory[0] = max_pos.x;
max_memory[1] = max_pos.y;
max_memory[2] = max_pos.z;
ArraySlice<Interval> ranges(_ranges, 0, _ranges.size());
ranges[0] = Interval(min_pos.x, max_pos.x);
ranges[1] = Interval(min_pos.y, max_pos.y);
ranges[2] = Interval(min_pos.z, max_pos.z);
const ArraySlice<uint8_t> program(_program, 0, _program.size());
uint32_t pc = 0;
while (pc < _program.size()) {
const uint8_t opid = _program[pc++];
while (pc < program.size()) {
const uint8_t opid = program[pc++];
const VoxelGraphNodeDB::NodeType &node_type = VoxelGraphNodeDB::get_singleton()->get_type(opid);
const uint32_t inputs_size = node_type.inputs.size() * sizeof(uint16_t);
@ -588,7 +568,7 @@ Interval VoxelGraphRuntime::analyze_range(Vector3i min_pos, Vector3i max_pos) {
const ArraySlice<uint16_t> outputs = program.sub(pc, outputs_size).reinterpret_cast_to<uint16_t>();
pc += outputs_size;
const uint16_t params_size = read<uint16_t>(_program, pc);
const uint16_t params_size = read<uint16_t>(program, pc);
ArraySlice<uint8_t> params;
if (params_size > 0) {
params = program.sub(pc, params_size);
@ -596,7 +576,7 @@ Interval VoxelGraphRuntime::analyze_range(Vector3i min_pos, Vector3i max_pos) {
}
ERR_FAIL_COND_V(node_type.range_analysis_func == nullptr, Interval());
node_type.range_analysis_func(RangeAnalysisContext(inputs, outputs, params, min_memory, max_memory));
node_type.range_analysis_func(RangeAnalysisContext(inputs, outputs, params, ranges));
#ifdef VOXEL_DEBUG_GRAPH_PROG_SENTINEL
// If this fails, the program is ill-formed
@ -604,7 +584,7 @@ Interval VoxelGraphRuntime::analyze_range(Vector3i min_pos, Vector3i max_pos) {
#endif
}
return Interval(min_memory[_sdf_output_address], max_memory[_sdf_output_address]);
return ranges[_sdf_output_address];
}
uint16_t VoxelGraphRuntime::get_output_port_address(ProgramGraph::PortLocation port) const {
@ -614,6 +594,8 @@ uint16_t VoxelGraphRuntime::get_output_port_address(ProgramGraph::PortLocation p
}
float VoxelGraphRuntime::get_memory_value(uint16_t address) const {
CRASH_COND(address >= _memory.size());
return _memory[address];
CRASH_COND(address >= _buffers.size());
const Buffer &buffer = _buffers[address];
// TODO This is a patch implementation. We may need to remove this method eventually
return buffer.data == nullptr ? buffer.constant_value : buffer.data[0];
}

View File

@ -159,26 +159,22 @@ public:
class RangeAnalysisContext : public _ProcessContext {
public:
inline RangeAnalysisContext(const ArraySlice<uint16_t> inputs, ArraySlice<uint16_t> outputs,
const ArraySlice<uint8_t> params,
ArraySlice<float> min_memory, ArraySlice<float> max_memory) :
const ArraySlice<uint8_t> params, ArraySlice<Interval> ranges) :
_ProcessContext(inputs, outputs, params),
_min_memory(min_memory),
_max_memory(max_memory) {}
_ranges(ranges) {}
inline const Interval get_input(uint32_t i) const {
const uint32_t address = get_input_address(i);
return Interval{ _min_memory[address], _max_memory[address] };
return _ranges[address];
}
inline void set_output(uint32_t i, const Interval r) {
const uint32_t address = get_output_address(i);
_min_memory[address] = r.min;
_max_memory[address] = r.max;
_ranges[address] = r;
}
private:
ArraySlice<float> _min_memory;
ArraySlice<float> _max_memory;
ArraySlice<Interval> _ranges;
};
typedef void (*CompileFunc)(CompileContext &);
@ -189,8 +185,7 @@ private:
bool _compile(const ProgramGraph &graph, bool debug);
std::vector<uint8_t> _program;
std::vector<float> _memory;
std::vector<Interval> _ranges;
std::vector<Buffer> _buffers;
Vector2 _xz_last_min;
Vector2 _xz_last_max;
@ -199,8 +194,6 @@ private:
std::vector<HeapResource> _heap_resources;
uint32_t _xzy_program_start;
float _last_x;
float _last_z;
int _sdf_output_address = -1;
CompilationResult _compilation_result;