Blender V4.3
eevee_lightcache.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <mutex>
12
13#include "DRW_render.hh"
14
15#include "BKE_global.hh"
16#include "BKE_lightprobe.h"
17
19
20#include "BLI_threads.h"
21#include "BLI_time.h"
22
25
26#include "GPU_capabilities.hh"
27#include "GPU_context.hh"
28
29#include "WM_api.hh"
30#include "WM_types.hh"
31
32#include "wm_window.hh"
33
34#include "eevee_engine.h"
35#include "eevee_instance.hh"
36
37#include "eevee_lightcache.hh"
38
39/* -------------------------------------------------------------------- */
43namespace blender::eevee {
44
45class LightBake {
46 private:
47 Depsgraph *depsgraph_;
48
50 int frame_;
52 int delay_ms_;
58 std::string &report_;
59
64 void *gl_context_ = nullptr;
66 GPUContext *gpu_context_ = nullptr;
67
69 Instance *instance_ = nullptr;
71 draw::Manager *manager_ = nullptr;
72
74 Vector<Object *> original_probes_;
77 std::mutex result_mutex_;
78
79 public:
81 ViewLayer *view_layer,
82 Scene *scene,
83 Span<Object *> probes,
84 bool run_as_job,
85 std::string &report,
86 int frame,
87 int delay_ms = 0)
88 : depsgraph_(DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER)),
89 frame_(frame),
90 delay_ms_(delay_ms),
91 report_(report),
92 original_probes_(probes)
93 {
95 bake_result_.resize(probes.size());
96 bake_result_.fill(nullptr);
97
98 if (run_as_job && !GPU_use_main_context_workaround()) {
99 /* This needs to happen in main thread. */
100 gl_context_ = WM_system_gpu_context_create();
102 }
103 }
104
106 {
108 DEG_graph_free(depsgraph_);
109 }
110
117 void update()
118 {
120
121 for (auto i : bake_result_.index_range()) {
122 if (bake_result_[i] == nullptr) {
123 continue;
124 }
125 Object *orig_ob = original_probes_[i];
126
127 {
128 std::scoped_lock lock(result_mutex_);
129
130 LightProbeObjectCache *cache = orig_ob->lightprobe_cache;
131 /* Delete any existing cache. */
132 if (cache->grid_static_cache != nullptr) {
134 }
135 /* Pass ownership to original object. */
136 cache->grid_static_cache = bake_result_[i];
137 bake_result_[i] = nullptr;
138 }
139 /* Propagate the cache to evaluated object. */
141 }
142 }
143
147 void run(bool *stop = nullptr, bool *do_update = nullptr, float *progress = nullptr)
148 {
149 DEG_graph_relations_update(depsgraph_);
150 DEG_evaluate_on_framechange(depsgraph_, frame_);
151
152 if (delay_ms_ > 0) {
153 BLI_time_sleep_ms(delay_ms_);
154 }
155
156 context_enable();
157 manager_ = new draw::Manager();
158 instance_ = new eevee::Instance();
159 instance_->init_light_bake(depsgraph_, manager_);
160 context_disable();
161
162 for (auto i : original_probes_.index_range()) {
163 Object *eval_ob = DEG_get_evaluated_object(depsgraph_, original_probes_[i]);
164
165 instance_->light_bake_irradiance(
166 *eval_ob,
167 [this]() { context_enable(); },
168 [this]() { context_disable(); },
169 [&]() { return (G.is_break == true) || ((stop != nullptr) ? *stop : false); },
170 [&](LightProbeGridCacheFrame *cache_frame, float grid_progress) {
171 {
172 std::scoped_lock lock(result_mutex_);
173 /* Delete any existing cache that wasn't transferred to the original object. */
174 if (bake_result_[i] != nullptr) {
176 }
177 bake_result_[i] = cache_frame;
178 }
179
180 if (do_update) {
181 *do_update = true;
182 }
183
184 if (progress) {
185 *progress = (i + grid_progress) / original_probes_.size();
186 }
187 });
188
189 if (StringRefNull(instance_->info_get()) != "") {
190 /* Pipe report to operator. */
191 report_ = instance_->info_get();
192 }
193
194 if ((G.is_break == true) || (stop != nullptr && *stop == true)) {
195 break;
196 }
197 }
198
199 delete_resources();
200 }
201
202 private:
203 void context_enable(bool render_begin = true)
204 {
206 /* Reuse main draw context. */
209 }
210 else if (gl_context_ == nullptr) {
211 /* Main thread case. */
213 }
214 else {
215 /* Worker thread case. */
217 if (gpu_context_ == nullptr) {
218 /* Create GPUContext in worker thread as it needs the correct gl context bound (which can
219 * only be bound in worker thread because of some GL driver requirements). */
220 gpu_context_ = GPU_context_create(nullptr, gl_context_);
221 }
223 }
224
225 if (render_begin) {
227 }
228 }
229
230 void context_disable()
231 {
233 /* Reuse main draw context. */
237 }
238 else if (gl_context_ == nullptr) {
239 /* Main thread case. */
242 }
243 else {
244 /* Worker thread case. */
248 }
249 }
250
257 void delete_resources()
258 {
259 /* Bind context without GPU_render_begin(). */
260 context_enable(false);
261
262 /* Free GPU data (Textures, Frame-buffers, etc...). */
263 delete instance_;
264 delete manager_;
265
266 /* Delete / unbind the GL & GPU context. Assumes it is currently bound. */
268 /* Reuse main draw context. */
271 }
272 else if (gl_context_ == nullptr) {
273 /* Main thread case. */
275 }
276 else {
277 /* Worker thread case. */
278 if (gpu_context_ != nullptr) {
279 GPU_context_discard(gpu_context_);
280 }
283 }
284 }
285};
286
287} // namespace blender::eevee
288
291/* -------------------------------------------------------------------- */
295using namespace blender::eevee;
296
298 wmWindow *win,
299 Main *bmain,
300 ViewLayer *view_layer,
301 Scene *scene,
302 blender::Vector<Object *> original_probes,
303 std::string &report,
304 int delay_ms,
305 int frame)
306{
307 /* Do not bake if there is a render going on. */
308 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
309 return nullptr;
310 }
311
312 /* Stop existing baking job. */
314
315 wmJob *wm_job = WM_jobs_get(wm,
316 win,
317 scene,
318 "Bake Lighting",
321
322 LightBake *bake = new LightBake(
323 bmain, view_layer, scene, std::move(original_probes), true, report, frame, delay_ms);
324
326 WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0);
327 WM_jobs_callbacks(wm_job,
329 nullptr,
332
333 G.is_break = false;
334
335 return wm_job;
336}
337
339 ViewLayer *view_layer,
340 Scene *scene,
341 blender::Vector<Object *> original_probes,
342 std::string &report,
343 int frame)
344{
345 LightBake *bake = new LightBake(
346 bmain, view_layer, scene, std::move(original_probes), false, report, frame);
347 /* TODO(fclem): Can remove this cast once we remove the previous EEVEE light cache. */
348 return reinterpret_cast<void *>(bake);
349}
350
352{
353 delete static_cast<LightBake *>(job_data);
354}
355
356void EEVEE_NEXT_lightbake_update(void *job_data)
357{
358 static_cast<LightBake *>(job_data)->update();
359}
360
361void EEVEE_NEXT_lightbake_job(void *job_data, wmJobWorkerStatus *worker_status)
362{
363 static_cast<LightBake *>(job_data)->run(
364 &worker_status->stop, &worker_status->do_update, &worker_status->progress);
365}
366
General operations for probes.
void BKE_lightprobe_grid_cache_frame_free(struct LightProbeGridCacheFrame *cache)
#define BLI_assert(a)
Definition BLI_assert.h:50
int BLI_thread_is_main(void)
Definition threads.cc:179
Platform independent time functions.
void BLI_time_sleep_ms(int ms)
Definition time.c:85
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
Depsgraph * DEG_graph_new(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
Definition depsgraph.cc:273
void DEG_graph_free(Depsgraph *graph)
Definition depsgraph.cc:301
void DEG_evaluate_on_framechange(Depsgraph *graph, float frame, DepsgraphEvaluateSyncWriteback sync_writeback=DEG_EVALUATE_SYNC_WRITEBACK_NO)
void DEG_graph_relations_update(Depsgraph *graph)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_SHADING
Definition DNA_ID.h:1061
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
void DRW_blender_gpu_render_context_disable(void *re_gpu_context)
void DRW_gpu_context_disable()
void DRW_system_gpu_render_context_enable(void *re_system_gpu_context)
void DRW_gpu_context_enable()
void DRW_system_gpu_render_context_disable(void *re_system_gpu_context)
void DRW_blender_gpu_render_context_enable(void *re_gpu_context)
bool GPU_use_main_context_workaround()
void GPU_render_end()
GPUContext * GPU_context_create(void *ghost_window, void *ghost_context)
void GPU_context_main_lock()
void GPU_render_begin()
void GPU_context_main_unlock()
void GPU_context_discard(GPUContext *)
@ WM_JOB_TYPE_LIGHT_BAKE
Definition WM_api.hh:1602
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1578
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1565
@ WM_JOB_PROGRESS
Definition WM_api.hh:1566
@ WM_JOB_PRIORITY
Definition WM_api.hh:1560
#define NC_SCENE
Definition WM_types.hh:345
#define NA_EDITED
Definition WM_types.hh:550
volatile int lock
struct GPUContext GPUContext
constexpr int64_t size() const
Definition BLI_span.hh:253
int64_t size() const
IndexRange index_range() const
void resize(const int64_t new_size)
void fill(const T &value) const
A running instance of the engine.
void light_bake_irradiance(Object &probe, FunctionRef< void()> context_enable, FunctionRef< void()> context_disable, FunctionRef< bool()> stop, FunctionRef< void(LightProbeGridCacheFrame *, float progress)> result_update)
void init_light_bake(Depsgraph *depsgraph, draw::Manager *manager)
LightBake(Main *bmain, ViewLayer *view_layer, Scene *scene, Span< Object * > probes, bool run_as_job, std::string &report, int frame, int delay_ms=0)
void run(bool *stop=nullptr, bool *do_update=nullptr, float *progress=nullptr)
void EEVEE_NEXT_lightbake_job(void *job_data, wmJobWorkerStatus *worker_status)
void EEVEE_NEXT_lightbake_update(void *job_data)
void EEVEE_NEXT_lightbake_job_data_free(void *job_data)
wmJob * EEVEE_NEXT_lightbake_job_create(wmWindowManager *wm, wmWindow *win, Main *bmain, ViewLayer *view_layer, Scene *scene, blender::Vector< Object * > original_probes, std::string &report, int delay_ms, int frame)
void * EEVEE_NEXT_lightbake_job_data_alloc(Main *bmain, ViewLayer *view_layer, Scene *scene, blender::Vector< Object * > original_probes, std::string &report, int frame)
#define G(x, y, z)
static void update(bNodeTree *ntree)
struct LightProbeGridCacheFrame * grid_static_cache
struct LightProbeObjectCache * lightprobe_cache
void WM_jobs_stop_type(wmWindowManager *wm, const void *owner, eWM_JobType job_type)
Definition wm_jobs.cc:621
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:352
wmJob * WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, const char *name, const eWM_JobFlag flag, const eWM_JobType job_type)
Definition wm_jobs.cc:189
void WM_jobs_callbacks(wmJob *wm_job, wm_jobs_start_callback startjob, void(*initjob)(void *), void(*update)(void *), void(*endjob)(void *))
Definition wm_jobs.cc:364
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:336
void * WM_system_gpu_context_create()
void wm_window_reset_drawable()
void WM_system_gpu_context_dispose(void *context)