Blender V4.3
FN_lazy_function.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
43#include "BLI_cpp_type.hh"
44#include "BLI_function_ref.hh"
47#include "BLI_vector.hh"
48
49#include <atomic>
50#include <thread>
51
52#ifndef NDEBUG
53# define FN_LAZY_FUNCTION_DEBUG_THREADS
54#endif
55
57
58enum class ValueUsage : uint8_t {
62 Used,
67 Maybe,
72 Unused,
73};
74
75class LazyFunction;
76
83 public:
84 virtual ~LocalUserData() = default;
85};
86
94class UserData {
95 public:
96 virtual ~UserData() = default;
97
102};
103
128
133class Params {
134 public:
139#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
140 std::thread::id main_thread_id_;
141 std::atomic<bool> allow_multi_threading_;
142#endif
143
144 public:
145 Params(const LazyFunction &fn, bool allow_multi_threading_initially);
146
152 void *try_get_input_data_ptr(int index) const;
153
158 void *try_get_input_data_ptr_or_request(int index);
159
166 void *get_output_data_ptr(int index);
167
172 void output_set(int index);
173
178 bool output_was_set(int index) const;
179
183 ValueUsage get_output_usage(int index) const;
184
189 void set_input_unused(int index);
190
194 template<typename T> T extract_input(int index);
195 template<typename T> T &get_input(int index) const;
196 template<typename T> T *try_get_input_data_ptr(int index) const;
197 template<typename T> T *try_get_input_data_ptr_or_request(int index);
198 template<typename T> void set_output(int index, T &&value);
199
205
206 private:
207 void assert_valid_thread() const;
208
214 virtual void *try_get_input_data_ptr_impl(int index) const = 0;
215 virtual void *try_get_input_data_ptr_or_request_impl(int index) = 0;
216 virtual void *get_output_data_ptr_impl(int index) = 0;
217 virtual void output_set_impl(int index) = 0;
218 virtual bool output_was_set_impl(int index) const = 0;
219 virtual ValueUsage get_output_usage_impl(int index) const = 0;
220 virtual void set_input_unused_impl(int index) = 0;
221 virtual bool try_enable_multi_threading_impl();
222};
223
227struct Input {
232 const char *debug_name;
236 const CPPType *type;
247
248 Input(const char *debug_name, const CPPType &type, const ValueUsage usage = ValueUsage::Used)
249 : debug_name(debug_name), type(&type), usage(usage)
250 {
251 }
252};
253
254struct Output {
259 const char *debug_name;
263 const CPPType *type = nullptr;
264
265 Output(const char *debug_name, const CPPType &type) : debug_name(debug_name), type(&type) {}
266};
267
273 protected:
274 const char *debug_name_ = "unknown";
281
282 public:
283 virtual ~LazyFunction() = default;
284
290 virtual std::string name() const;
291 virtual std::string input_name(int index) const;
292 virtual std::string output_name(int index) const;
293
298 virtual void *init_storage(LinearAllocator<> &allocator) const;
299
303 virtual void destruct_storage(void *storage) const;
304
309 virtual void possible_output_dependencies(int output_index,
310 FunctionRef<void(Span<int>)> fn) const;
311
315 Span<Input> inputs() const;
319 Span<Output> outputs() const;
320
326 void execute(Params &params, const Context &context) const;
327
331 bool always_used_inputs_available(const Params &params) const;
332
343
344 private:
349 virtual void execute_impl(Params &params, const Context &context) const = 0;
350};
351
352/* -------------------------------------------------------------------- */
357{
358 return inputs_;
359}
360
362{
363 return outputs_;
364}
365
366inline void LazyFunction::execute(Params &params, const Context &context) const
367{
369 this->execute_impl(params, context);
370}
371
374/* -------------------------------------------------------------------- */
379 [[maybe_unused]] bool allow_multi_threading_initially)
380 : fn_(fn)
382 ,
383 main_thread_id_(std::this_thread::get_id()),
384 allow_multi_threading_(allow_multi_threading_initially)
385#endif
386{
387}
388
389inline void *Params::try_get_input_data_ptr(const int index) const
390{
391 BLI_assert(index >= 0 && index < fn_.inputs().size());
392 return this->try_get_input_data_ptr_impl(index);
393}
394
395inline void *Params::try_get_input_data_ptr_or_request(const int index)
396{
397 BLI_assert(index >= 0 && index < fn_.inputs().size());
398 this->assert_valid_thread();
399 return this->try_get_input_data_ptr_or_request_impl(index);
400}
401
402inline void *Params::get_output_data_ptr(const int index)
403{
404 BLI_assert(index >= 0 && index < fn_.outputs().size());
405 this->assert_valid_thread();
406 return this->get_output_data_ptr_impl(index);
407}
408
409inline void Params::output_set(const int index)
410{
411 BLI_assert(index >= 0 && index < fn_.outputs().size());
412 this->assert_valid_thread();
413 this->output_set_impl(index);
414}
415
416inline bool Params::output_was_set(const int index) const
417{
418 BLI_assert(index >= 0 && index < fn_.outputs().size());
419 return this->output_was_set_impl(index);
420}
421
422inline ValueUsage Params::get_output_usage(const int index) const
423{
424 BLI_assert(index >= 0 && index < fn_.outputs().size());
425 return this->get_output_usage_impl(index);
426}
427
428inline void Params::set_input_unused(const int index)
429{
430 BLI_assert(index >= 0 && index < fn_.inputs().size());
431 this->assert_valid_thread();
432 this->set_input_unused_impl(index);
433}
434
435template<typename T> inline T Params::extract_input(const int index)
436{
437 this->assert_valid_thread();
438 void *data = this->try_get_input_data_ptr(index);
439 BLI_assert(data != nullptr);
440 T return_value = std::move(*static_cast<T *>(data));
441 return return_value;
442}
443
444template<typename T> inline T &Params::get_input(const int index) const
445{
446 void *data = this->try_get_input_data_ptr(index);
447 BLI_assert(data != nullptr);
448 return *static_cast<T *>(data);
449}
450
451template<typename T> inline T *Params::try_get_input_data_ptr(const int index) const
452{
453 this->assert_valid_thread();
454 return static_cast<T *>(this->try_get_input_data_ptr(index));
455}
456
457template<typename T> inline T *Params::try_get_input_data_ptr_or_request(const int index)
458{
459 this->assert_valid_thread();
460 return static_cast<T *>(this->try_get_input_data_ptr_or_request(index));
461}
462
463template<typename T> inline void Params::set_output(const int index, T &&value)
464{
465 using DecayT = std::decay_t<T>;
466 this->assert_valid_thread();
467 void *data = this->get_output_data_ptr(index);
468 new (data) DecayT(std::forward<T>(value));
469 this->output_set(index);
470}
471
473{
474 this->assert_valid_thread();
475 const bool success = this->try_enable_multi_threading_impl();
476#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
477 if (success) {
479 }
480#endif
481 return success;
482}
483
484inline void Params::assert_valid_thread() const
485{
486#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
488 return;
489 }
490 if (main_thread_id_ != std::this_thread::get_id()) {
492 }
493#endif
494}
495
498} // namespace blender::fn::lazy_function
499
500namespace blender {
501namespace lf = fn::lazy_function;
502}
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define FN_LAZY_FUNCTION_DEBUG_THREADS
virtual void * init_storage(LinearAllocator<> &allocator) const
bool always_used_inputs_available(const Params &params) const
virtual void possible_output_dependencies(int output_index, FunctionRef< void(Span< int >)> fn) const
virtual std::string output_name(int index) const
virtual void destruct_storage(void *storage) const
virtual std::string input_name(int index) const
void execute(Params &params, const Context &context) const
void set_output(int index, T &&value)
void * try_get_input_data_ptr_or_request(int index)
void * try_get_input_data_ptr(int index) const
ValueUsage get_output_usage(int index) const
Params(const LazyFunction &fn, bool allow_multi_threading_initially)
virtual destruct_ptr< LocalUserData > get_local(LinearAllocator<> &allocator)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
std::unique_ptr< T, DestructValueAtAddress< T > > destruct_ptr
unsigned char uint8_t
Definition stdint.h:78
Context(void *storage, UserData *user_data, LocalUserData *local_user_data)
Input(const char *debug_name, const CPPType &type, const ValueUsage usage=ValueUsage::Used)
Output(const char *debug_name, const CPPType &type)