Blender V5.0
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
42
43#include "BLI_cpp_type.hh"
44#include "BLI_function_ref.hh"
46#include "BLI_vector.hh"
47
48#include "FN_user_data.hh"
49
50#ifndef NDEBUG
51# include <atomic>
52# include <thread>
53# define FN_LAZY_FUNCTION_DEBUG_THREADS
54#endif
55
57
58enum class ValueUsage : uint8_t {
73};
74
75class LazyFunction;
76
101
106class Params {
107 public:
112#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
113 std::thread::id main_thread_id_;
114 std::atomic<bool> allow_multi_threading_;
115#endif
116
117 Params(const LazyFunction &fn, bool allow_multi_threading_initially);
118
124 void *try_get_input_data_ptr(int index) const;
125
130 void *try_get_input_data_ptr_or_request(int index);
131
138 void *get_output_data_ptr(int index);
139
144 void output_set(int index);
145
150 bool output_was_set(int index) const;
151
155 ValueUsage get_output_usage(int index) const;
156
161 void set_input_unused(int index);
162
166 template<typename T> T extract_input(int index);
167 template<typename T> T &get_input(int index) const;
168 template<typename T> T *try_get_input_data_ptr(int index) const;
169 template<typename T> T *try_get_input_data_ptr_or_request(int index);
170 template<typename T> void set_output(int index, T &&value);
171
177
178 private:
179 void assert_valid_thread() const;
180
186 virtual void *try_get_input_data_ptr_impl(int index) const = 0;
187 virtual void *try_get_input_data_ptr_or_request_impl(int index) = 0;
188 virtual void *get_output_data_ptr_impl(int index) = 0;
189 virtual void output_set_impl(int index) = 0;
190 virtual bool output_was_set_impl(int index) const = 0;
191 virtual ValueUsage get_output_usage_impl(int index) const = 0;
192 virtual void set_input_unused_impl(int index) = 0;
193 virtual bool try_enable_multi_threading_impl();
194};
195
199struct Input {
204 const char *debug_name;
208 const CPPType *type;
219
222 {
223 }
224};
225
226struct Output {
231 const char *debug_name;
235 const CPPType *type = nullptr;
236
238};
239
245 protected:
246 const char *debug_name_ = "unknown";
253
254 public:
255 virtual ~LazyFunction() = default;
256
262 virtual std::string name() const;
263 virtual std::string input_name(int index) const;
264 virtual std::string output_name(int index) const;
265
270 virtual void *init_storage(LinearAllocator<> &allocator) const;
271
275 virtual void destruct_storage(void *storage) const;
276
281 virtual void possible_output_dependencies(int output_index,
282 FunctionRef<void(Span<int>)> fn) const;
283
287 Span<Input> inputs() const;
291 Span<Output> outputs() const;
292
298 void execute(Params &params, const Context &context) const;
299
303 bool always_used_inputs_available(const Params &params) const;
304
315
316 private:
321 virtual void execute_impl(Params &params, const Context &context) const = 0;
322};
323
324/* -------------------------------------------------------------------- */
327
329{
330 return inputs_;
331}
332
334{
335 return outputs_;
336}
337
338inline void LazyFunction::execute(Params &params, const Context &context) const
339{
341 this->execute_impl(params, context);
342}
343
345
346/* -------------------------------------------------------------------- */
349
351 [[maybe_unused]] bool allow_multi_threading_initially)
352 : fn_(fn)
354 ,
355 main_thread_id_(std::this_thread::get_id()),
356 allow_multi_threading_(allow_multi_threading_initially)
357#endif
358{
359}
360
361inline void *Params::try_get_input_data_ptr(const int index) const
362{
363 BLI_assert(index >= 0 && index < fn_.inputs().size());
364 return this->try_get_input_data_ptr_impl(index);
365}
366
367inline void *Params::try_get_input_data_ptr_or_request(const int index)
368{
369 BLI_assert(index >= 0 && index < fn_.inputs().size());
370 this->assert_valid_thread();
371 return this->try_get_input_data_ptr_or_request_impl(index);
372}
373
374inline void *Params::get_output_data_ptr(const int index)
375{
376 BLI_assert(index >= 0 && index < fn_.outputs().size());
377 this->assert_valid_thread();
378 return this->get_output_data_ptr_impl(index);
379}
380
381inline void Params::output_set(const int index)
382{
383 BLI_assert(index >= 0 && index < fn_.outputs().size());
384 this->assert_valid_thread();
385 this->output_set_impl(index);
386}
387
388inline bool Params::output_was_set(const int index) const
389{
390 BLI_assert(index >= 0 && index < fn_.outputs().size());
391 return this->output_was_set_impl(index);
392}
393
394inline ValueUsage Params::get_output_usage(const int index) const
395{
396 BLI_assert(index >= 0 && index < fn_.outputs().size());
397 return this->get_output_usage_impl(index);
398}
399
400inline void Params::set_input_unused(const int index)
401{
402 BLI_assert(index >= 0 && index < fn_.inputs().size());
403 this->assert_valid_thread();
404 this->set_input_unused_impl(index);
405}
406
407template<typename T> inline T Params::extract_input(const int index)
408{
409 this->assert_valid_thread();
410 void *data = this->try_get_input_data_ptr(index);
411 BLI_assert(data != nullptr);
412 T return_value = std::move(*static_cast<T *>(data));
413 return return_value;
414}
415
416template<typename T> inline T &Params::get_input(const int index) const
417{
418 void *data = this->try_get_input_data_ptr(index);
419 BLI_assert(data != nullptr);
420 return *static_cast<T *>(data);
421}
422
423template<typename T> inline T *Params::try_get_input_data_ptr(const int index) const
424{
425 this->assert_valid_thread();
426 return static_cast<T *>(this->try_get_input_data_ptr(index));
427}
428
429template<typename T> inline T *Params::try_get_input_data_ptr_or_request(const int index)
430{
431 this->assert_valid_thread();
432 return static_cast<T *>(this->try_get_input_data_ptr_or_request(index));
433}
434
435template<typename T> inline void Params::set_output(const int index, T &&value)
436{
437 using DecayT = std::decay_t<T>;
438 this->assert_valid_thread();
439 void *data = this->get_output_data_ptr(index);
440 new (data) DecayT(std::forward<T>(value));
441 this->output_set(index);
442}
443
445{
446 this->assert_valid_thread();
447 const bool success = this->try_enable_multi_threading_impl();
448#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
449 if (success) {
451 }
452#endif
453 return success;
454}
455
456inline void Params::assert_valid_thread() const
457{
458#ifdef FN_LAZY_FUNCTION_DEBUG_THREADS
460 return;
461 }
462 if (main_thread_id_ != std::this_thread::get_id()) {
464 }
465#endif
466}
467
469
470} // namespace blender::fn::lazy_function
471
472namespace blender {
473namespace lf = fn::lazy_function;
474}
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define FN_LAZY_FUNCTION_DEBUG_THREADS
BMesh const char void * data
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)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define T
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)