Blender V5.0
render_opengl.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <condition_variable>
10#include <cstddef>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_bitmap.h"
16#include "BLI_fileops.h"
17#include "BLI_listbase.h"
19#include "BLI_mutex.hh"
20#include "BLI_string_utf8.h"
21#include "BLI_task.h"
22#include "BLI_task.hh"
23#include "BLI_utildefines.h"
24#include "BLI_vector.hh"
25
26#include "DNA_anim_types.h"
27#include "DNA_curve_types.h"
29#include "DNA_object_types.h"
30#include "DNA_scene_types.h"
31
32#include "BKE_anim_data.hh"
33#include "BKE_camera.h"
34#include "BKE_context.hh"
35#include "BKE_customdata.hh"
36#include "BKE_fcurve.hh"
37#include "BKE_global.hh"
38#include "BKE_image.hh"
39#include "BKE_image_format.hh"
40#include "BKE_image_save.hh"
41#include "BKE_lib_query.hh"
42#include "BKE_main.hh"
43#include "BKE_report.hh"
44#include "BKE_scene.hh"
45
46#include "DEG_depsgraph.hh"
48
49#include "DRW_engine.hh"
50
51#include "WM_api.hh"
52#include "WM_types.hh"
53
54#include "ED_gpencil_legacy.hh"
55#include "ED_screen.hh"
56#include "ED_view3d.hh"
58
59#include "IMB_imbuf.hh"
60#include "IMB_imbuf_types.hh"
61
62#include "MOV_write.hh"
63
64#include "RE_pipeline.h"
65
66#include "BLT_translation.hh"
67
68#include "RNA_access.hh"
69#include "RNA_define.hh"
70
71#include "SEQ_render.hh"
72
73#include "ANIM_action_legacy.hh"
74
75#include "GPU_context.hh"
76#include "GPU_framebuffer.hh"
77#include "GPU_matrix.hh"
78#include "GPU_state.hh"
79#include "GPU_viewport.hh"
80
81#include "CLG_log.h"
82
83#include "render_intern.hh"
84
86
87static CLG_LogRef LOG = {"render"};
88
89/* TODO(sergey): Find better approximation of the scheduled frames.
90 * For really high-resolution renders it might fail still. */
91#define MAX_SCHEDULED_FRAMES 8
92
93struct OGLRender : public RenderJobBase {
94 Main *bmain = nullptr;
95 Render *re = nullptr;
96 WorkSpace *workspace = nullptr;
98 Depsgraph *depsgraph = nullptr;
99
100 View3D *v3d = nullptr;
101 RegionView3D *rv3d = nullptr;
102 ARegion *region = nullptr;
103
104 int views_len = 0; /* multi-view views */
105
106 bool is_sequencer = false;
107 SpaceSeq *sseq = nullptr;
108 struct {
109 ImBuf **ibufs_arr = nullptr;
111
112 Image *ima = nullptr;
114
115 GPUOffScreen *ofs = nullptr;
116 int sizex = 0;
117 int sizey = 0;
118 int write_still = false;
119
121
123 ReportList *reports = nullptr;
124
125 int cfrao = 0;
126 int nfra = 0;
127
128 int totvideos = 0;
129
130 /* For only rendering frames that have a key in animation data. */
132
133 /* quick lookup */
134 int view_id = 0;
135
136 /* wm vars for timer and progress cursor */
137 wmWindowManager *wm = nullptr;
138 wmWindow *win = nullptr;
139
141
142 TaskPool *task_pool = nullptr;
143 bool pool_ok = true;
144 bool is_animation = false;
145
148 std::mutex task_mutex;
149 std::condition_variable task_condition;
150
151 wmJob *wm_job = nullptr;
152
153 bool ended = false;
154};
155
157{
158 View3D *v3d = oglrender->v3d;
159 RegionView3D *rv3d = oglrender->rv3d;
160 RenderData *rd = &oglrender->scene->r;
161
162 if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
163 return false;
164 }
165
166 return (rd->scemode & R_MULTIVIEW) &&
167 ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
168}
169
171{
172 RenderResult *rr;
173 RenderView *rv;
174 SceneRenderView *srv;
175 bool is_multiview;
176 Object *camera;
177 View3D *v3d = oglrender->v3d;
178
179 RenderData *rd = &oglrender->scene->r;
180
181 rr = RE_AcquireResultWrite(oglrender->re);
182
183 is_multiview = screen_opengl_is_multiview(oglrender);
184
185 if (!is_multiview) {
186 /* we only have one view when multiview is off */
187 rv = static_cast<RenderView *>(rr->views.first);
188
189 if (rv == nullptr) {
190 rv = MEM_callocN<RenderView>("new opengl render view");
191 BLI_addtail(&rr->views, rv);
192 }
193
194 while (rv->next) {
195 RenderView *rv_del = rv->next;
196 BLI_remlink(&rr->views, rv_del);
197
198 IMB_freeImBuf(rv_del->ibuf);
199
200 MEM_freeN(rv_del);
201 }
202 }
203 else {
204 if (v3d) {
205 RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
206 }
207
208 /* remove all the views that are not needed */
209 rv = static_cast<RenderView *>(rr->views.last);
210 while (rv) {
211 srv = static_cast<SceneRenderView *>(
214 rv = rv->prev;
215 }
216 else {
217 RenderView *rv_del = rv;
218 rv = rv_del->prev;
219
220 BLI_remlink(&rr->views, rv_del);
221
222 IMB_freeImBuf(rv_del->ibuf);
223
224 MEM_freeN(rv_del);
225 }
226 }
227
228 /* create all the views that are needed */
229 LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) {
230 if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
231 continue;
232 }
233
234 rv = static_cast<RenderView *>(
236
237 if (rv == nullptr) {
238 rv = MEM_callocN<RenderView>("new opengl render view");
239 STRNCPY_UTF8(rv->name, srv->name);
240 BLI_addtail(&rr->views, rv);
241 }
242 }
243 }
244
245 if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) {
246 oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
247 }
248
249 /* will only work for non multiview correctly */
250 if (v3d) {
251 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
252 BKE_render_result_stamp_info(oglrender->scene, camera, rr, false);
253 }
254 else {
255 BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false);
256 }
257
258 RE_ReleaseResult(oglrender->re);
259}
260
262{
263 Scene *scene = oglrender->scene;
264 Object *camera = nullptr;
265 int sizex = oglrender->sizex;
266 int sizey = oglrender->sizey;
267 ImBuf *ibuf_result = nullptr;
268
269 if (oglrender->is_sequencer) {
270 SpaceSeq *sseq = oglrender->sseq;
271 bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
272
273 /* use pre-calculated ImBuf (avoids deadlock), see: */
274 ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
275
276 if (ibuf) {
277 ibuf_result = IMB_dupImBuf(ibuf);
278 IMB_freeImBuf(ibuf);
279 /* OpenGL render is considered to be preview and should be
280 * as fast as possible. So currently we're making sure sequencer
281 * result is always byte to simplify color management pipeline.
282 *
283 * TODO(sergey): In the case of output to float container (EXR)
284 * it actually makes sense to keep float buffer instead.
285 */
286 if (ibuf_result->float_buffer.data != nullptr) {
287 IMB_byte_from_float(ibuf_result);
288 IMB_free_float_pixels(ibuf_result);
289 }
290 BLI_assert((sizex == ibuf->x) && (sizey == ibuf->y));
291 }
292 else if (gpd) {
293 /* If there are no strips, Grease Pencil still needs a buffer to draw on */
294 ibuf_result = IMB_allocImBuf(sizex, sizey, 32, IB_byte_data);
295 }
296
297 if (gpd) {
298 int i;
299 uchar *gp_rect;
300 uchar *render_rect = ibuf_result->byte_buffer.data;
301
303 GPU_offscreen_bind(oglrender->ofs, true);
304
305 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
306 GPU_clear_depth(1.0f);
307
309 wmOrtho2(0, scene->r.xsch, 0, scene->r.ysch);
310 GPU_matrix_translate_2f(scene->r.xsch / 2, scene->r.ysch / 2);
311
313 ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
315
316 gp_rect = static_cast<uchar *>(
317 MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
318 GPU_offscreen_read_color(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
319
320 for (i = 0; i < sizex * sizey * 4; i += 4) {
321 blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
322 }
323 GPU_offscreen_unbind(oglrender->ofs, true);
325
326 MEM_freeN(gp_rect);
327 }
328 }
329 else {
330 /* shouldn't suddenly give errors mid-render but possible */
331 Depsgraph *depsgraph = oglrender->depsgraph;
332 char err_out[256] = "unknown";
333 ImBuf *ibuf_view;
334 bool draw_sky = (scene->r.alphamode == R_ADDSKY);
335 const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
336 const char *viewname = RE_GetActiveRenderView(oglrender->re);
337 View3D *v3d = oglrender->v3d;
338
340
341 if (v3d != nullptr) {
342 ARegion *region = oglrender->region;
344 scene,
345 static_cast<eDrawType>(v3d->shading.type),
346 v3d,
347 region,
348 sizex,
349 sizey,
351 alpha_mode,
352 viewname,
353 true,
354 oglrender->ofs,
355 oglrender->viewport,
356 err_out);
357
358 /* for stamp only */
359 if (oglrender->rv3d->persp == RV3D_CAMOB && v3d->camera) {
360 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
361 }
362 }
363 else {
365 scene,
366 nullptr,
367 OB_SOLID,
368 scene->camera,
369 sizex,
370 sizey,
373 alpha_mode,
374 viewname,
375 oglrender->ofs,
376 oglrender->viewport,
377 err_out);
378 camera = scene->camera;
379 }
380
381 if (ibuf_view) {
382 ibuf_result = ibuf_view;
383 }
384 else {
385 CLOG_ERROR(&LOG, "%s: failed to get buffer, %s", __func__, err_out);
386 }
387 }
388
389 if (ibuf_result != nullptr) {
390 if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
391 BKE_image_stamp_buf(scene, camera, nullptr, ibuf_result);
392 }
393 RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
394 IMB_freeImBuf(ibuf_result);
395 }
396
397 /* Perform render step between renders to allow
398 * flushing of freed GPUBackend resources. */
401 GPU_flush();
402 }
403 GPU_render_step(true);
405}
406
408{
409 Scene *scene = oglrender->scene;
410 RenderResult *rr;
411 bool ok;
412 char filepath[FILE_MAX];
413
414 rr = RE_AcquireResultRead(oglrender->re);
415
416 path_templates::VariableMap template_variables;
417 BKE_add_template_variables_general(template_variables, &scene->id);
418 BKE_add_template_variables_for_render_path(template_variables, *scene);
419
420 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
422 filepath,
423 scene->r.pic,
424 relbase,
425 &template_variables,
426 scene->r.cfra,
427 &scene->r.im_format,
428 (scene->r.scemode & R_EXTENSION) != 0,
429 false,
430 nullptr);
431
432 if (!errors.is_empty()) {
433 std::unique_lock lock(oglrender->reports_mutex);
434 BKE_report_path_template_errors(oglrender->reports, RPT_ERROR, scene->r.pic, errors);
435 ok = false;
436 }
437 else {
438 /* write images as individual images or stereo */
439 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
440 ok = BKE_image_render_write(oglrender->reports, rr, scene, false, filepath);
441
442 RE_ReleaseResultImage(oglrender->re);
443 }
444
445 if (ok) {
446 CLOG_INFO_NOCHECK(&LOG, "OpenGL Render written to '%s'", filepath);
447 }
448 else {
449 CLOG_ERROR(&LOG, "OpenGL Render failed to write '%s'", filepath);
450 }
451}
452
453static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
454{
455 /* `d = s + (1-alpha_s)d` */
456 float mul;
457
458 mul = 1.0f - source[3];
459
460 dest[0] = (mul * dest[0]) + source[0];
461 dest[1] = (mul * dest[1]) + source[1];
462 dest[2] = (mul * dest[2]) + source[2];
463 dest[3] = (mul * dest[3]) + source[3];
464}
465
467{
468 RenderResult *rr;
469 RenderView *rv;
470 int view_id;
471 ImBuf *ibuf;
472 void *lock;
473
474 if (oglrender->is_sequencer) {
475 Scene *scene = oglrender->scene;
476
478 SpaceSeq *sseq = oglrender->sseq;
479 int chanshown = sseq ? sseq->chanshown : 0;
480
482 oglrender->depsgraph,
483 scene,
484 oglrender->sizex,
485 oglrender->sizey,
487 nullptr,
488 &context);
489
490 for (view_id = 0; view_id < oglrender->views_len; view_id++) {
491 context.view_id = view_id;
492 context.gpu_offscreen = oglrender->ofs;
493 context.gpu_viewport = oglrender->viewport;
495 &context, scene->r.cfra, chanshown);
496 }
497 }
498
499 rr = RE_AcquireResultRead(oglrender->re);
500 for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv; rv = rv->next, view_id++)
501 {
502 BLI_assert(view_id < oglrender->views_len);
503 RE_SetActiveRenderView(oglrender->re, rv->name);
504 oglrender->view_id = view_id;
505 /* render composite */
506 screen_opengl_render_doit(oglrender, rr);
507 }
508
509 RE_ReleaseResult(oglrender->re);
510
511 ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
512 if (ibuf) {
514 }
515 BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
517
518 if (oglrender->write_still) {
520 }
521}
522
523static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
524{
525 if (adt == nullptr || adt->action == nullptr) {
526 return;
527 }
528
529 Scene *scene = oglrender->scene;
530 int frame_start = PSFRA;
531 int frame_end = PEFRA;
532
534 if (fcu->driver != nullptr || fcu->fpt != nullptr) {
535 /* Drivers have values for any point in time, so to get "the keyed frames" they are
536 * useless. Same for baked FCurves, they also have keys for every frame, which is not
537 * useful for rendering the keyed subset of the frames. */
538 continue;
539 }
540
541 bool found = false; /* Not interesting, we just want a starting point for the for-loop. */
543 fcu->bezt, frame_start, fcu->totvert, &found);
544 for (; key_index < fcu->totvert; key_index++) {
545 BezTriple *bezt = &fcu->bezt[key_index];
546 /* The frame range to render uses integer frame numbers, and the frame
547 * step is also an integer, so we always render on the frame. */
548 int frame_nr = round_fl_to_int(bezt->vec[1][0]);
549
550 /* (frame_nr < frame_start) cannot happen because of the binary search above. */
551 BLI_assert(frame_nr >= frame_start);
552 if (frame_nr > frame_end) {
553 break;
554 }
555 BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
556 }
557 }
558}
559
561 const bGPdata *gp)
562{
563 if (gp == nullptr) {
564 return;
565 }
566
567 Scene *scene = oglrender->scene;
568 int frame_start = PSFRA;
569 int frame_end = PEFRA;
570
571 LISTBASE_FOREACH (const bGPDlayer *, gp_layer, &gp->layers) {
572 LISTBASE_FOREACH (const bGPDframe *, gp_frame, &gp_layer->frames) {
573 if (gp_frame->framenum < frame_start || gp_frame->framenum > frame_end) {
574 continue;
575 }
576 BLI_BITMAP_ENABLE(oglrender->render_frames, gp_frame->framenum - frame_start);
577 }
578 }
579}
580
582{
583 ID **id_p = cb_data->id_pointer;
584 if (*id_p == nullptr) {
585 return IDWALK_RET_NOP;
586 }
587 ID *id = *id_p;
588
589 ID *self_id = cb_data->self_id;
590 const LibraryForeachIDCallbackFlag cb_flag = cb_data->cb_flag;
591 if (cb_flag == IDWALK_CB_LOOPBACK || id == self_id) {
592 /* IDs may end up referencing themselves one way or the other, and those
593 * (the self_id ones) have always already been processed. */
595 }
596
597 OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
598
599 /* Whitelist of datablocks to follow pointers into. */
600 const ID_Type id_type = GS(id->name);
601 switch (id_type) {
602 /* Whitelist: */
603 case ID_ME: /* Mesh */
604 case ID_CU_LEGACY: /* Curve */
605 case ID_MB: /* MetaBall */
606 case ID_MA: /* Material */
607 case ID_TE: /* Tex (Texture) */
608 case ID_IM: /* Image */
609 case ID_LT: /* Lattice */
610 case ID_LA: /* Light */
611 case ID_CA: /* Camera */
612 case ID_KE: /* Key (shape key) */
613 case ID_VF: /* VFont (Vector Font) */
614 case ID_TXT: /* Text */
615 case ID_SPK: /* Speaker */
616 case ID_SO: /* Sound */
617 case ID_AR: /* bArmature */
618 case ID_NT: /* bNodeTree */
619 case ID_PA: /* ParticleSettings */
620 case ID_MC: /* MovieClip */
621 case ID_MSK: /* Mask */
622 case ID_LP: /* LightProbe */
623 case ID_CV: /* Curves */
624 case ID_PT: /* PointCloud */
625 case ID_VO: /* Volume */
626 break;
627
628 /* Blacklist: */
629 case ID_SCE: /* Scene */
630 case ID_LI: /* Library */
631 case ID_OB: /* Object */
632 case ID_WO: /* World */
633 case ID_SCR: /* Screen */
634 case ID_GR: /* Group */
635 case ID_AC: /* bAction */
636 case ID_BR: /* Brush */
637 case ID_WM: /* WindowManager */
638 case ID_LS: /* FreestyleLineStyle */
639 case ID_PAL: /* Palette */
640 case ID_PC: /* PaintCurve */
641 case ID_CF: /* CacheFile */
642 case ID_WS: /* WorkSpace */
643 /* Only follow pointers to specific datablocks, to avoid ending up in
644 * unrelated datablocks and exploding the number of blocks we follow. If the
645 * frames of the animation of certain objects should be taken into account,
646 * they should have been selected by the user. */
648
649 /* Special cases: */
650 case ID_GD_LEGACY: /* bGPdata, (Grease Pencil) */
651 /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation
652 * system that requires specific handling here. */
654 break;
655 case ID_GP:
656 /* TODO: gather frames. */
657 break;
658 }
659
661 gather_frames_to_render_for_adt(oglrender, adt);
662
663 return IDWALK_RET_NOP;
664}
665
674{
675 Scene *scene = oglrender->scene;
676 int frame_start = PSFRA;
677 int frame_end = PEFRA;
678
679 /* Will be freed in screen_opengl_render_end(). */
680 oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
681 "OGLRender::render_frames");
682
683 /* The first frame should always be rendered, otherwise there is nothing to write to file. */
684 BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
685
686 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
687 ID *id = &ob->id;
688
689 /* Gather the frames from the object animation data. */
691 gather_frames_to_render_for_adt(oglrender, adt);
692
693 /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
695 nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
696 }
698}
699
701{
702 /* new render clears all callbacks */
704 wmWindow *win = CTX_wm_window(C);
705 WorkSpace *workspace = CTX_wm_workspace(C);
706
707 const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
708
709 Scene *scene = !is_sequencer ? CTX_data_scene(C) : CTX_data_sequencer_scene(C);
710 if (!scene) {
711 return false;
712 }
713 ScrArea *prev_area = CTX_wm_area(C);
714 ARegion *prev_region = CTX_wm_region(C);
715 GPUOffScreen *ofs;
716 OGLRender *oglrender;
717 int sizex, sizey;
718 bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
719 const bool is_animation = RNA_boolean_get(op->ptr, "animation");
720 const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
721 const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
722 const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
723 (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
724 char err_out[256] = "unknown";
725
726 if (G.background) {
728 op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
729 return false;
730 }
731
732 /* only one render job at a time */
733 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
734 return false;
735 }
736
737 if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
739 op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
740 return false;
741 }
742
743 if (is_sequencer) {
744 is_view_context = false;
745 }
746 else {
747 /* ensure we have a 3d view */
749 RNA_boolean_set(op->ptr, "view_context", false);
750 is_view_context = false;
751 }
752
753 if (!is_view_context && scene->camera == nullptr) {
754 BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
755 return false;
756 }
757 }
758
759 /* stop all running jobs, except screen one. currently previews frustrate Render */
761
762 /* create offscreen buffer */
763 BKE_render_resolution(&scene->r, false, &sizex, &sizey);
764
765 /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
766 DRW_gpu_context_enable(); /* Off-screen creation needs to be done in DRW context. */
767 ofs = GPU_offscreen_create(sizex,
768 sizey,
769 true,
770 blender::gpu::TextureFormat::SFLOAT_16_16_16_16,
772 false,
773 err_out);
775
776 if (!ofs) {
777 BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
778 CTX_wm_area_set(C, prev_area);
779 CTX_wm_region_set(C, prev_region);
780 return false;
781 }
782
783 /* allocate opengl render */
784 oglrender = MEM_new<OGLRender>("OGLRender");
785 op->customdata = oglrender;
786
787 oglrender->ofs = ofs;
788 oglrender->sizex = sizex;
789 oglrender->sizey = sizey;
790 oglrender->viewport = GPU_viewport_create();
791 oglrender->bmain = CTX_data_main(C);
792 oglrender->scene = scene;
793 oglrender->current_scene = scene;
794 oglrender->workspace = workspace;
795 oglrender->view_layer = CTX_data_view_layer(C);
796 /* NOTE: The depsgraph is not only used to update scene for a new frames, but also to initialize
797 * output video handles, which does need evaluated scene. */
799 oglrender->cfrao = scene->r.cfra;
800
801 oglrender->write_still = is_write_still && !is_animation;
802 oglrender->is_animation = is_animation;
803 oglrender->color_depth = color_depth;
804
805 oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
806
807 oglrender->is_sequencer = is_sequencer;
808 if (is_sequencer) {
809 oglrender->sseq = CTX_wm_space_seq(C);
810 ImBuf **ibufs_arr = static_cast<ImBuf **>(
811 MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
812 oglrender->seq_data.ibufs_arr = ibufs_arr;
813 }
814
815 if (is_view_context) {
816 /* Prefer rendering camera in quad view if possible. */
817 if (!ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region)) {
818 /* If not get region activated by ED_view3d_context_activate earlier. */
819 oglrender->v3d = CTX_wm_view3d(C);
820 oglrender->region = CTX_wm_region(C);
821 }
822
823 oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
824
825 /* MUST be cleared on exit */
827 ED_view3d_datamask(oglrender->scene,
828 oglrender->view_layer,
829 oglrender->v3d,
830 &oglrender->scene->customdata_mask_modal);
831
832 /* apply immediately in case we're rendering from a script,
833 * running notifiers again will overwrite */
835 &oglrender->scene->customdata_mask_modal);
836 }
837
838 /* create render */
839 oglrender->re = RE_NewSceneRender(scene);
840
841 /* create image and image user */
842 oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
843 BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
844 BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
845
846 oglrender->iuser.scene = scene;
847
848 /* create render result */
850 oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
851
852 /* create render views */
853 screen_opengl_views_setup(oglrender);
854
855 /* wm vars */
856 oglrender->wm = wm;
857 oglrender->win = win;
858
859 if (is_animation) {
860 if (is_render_keyed_only) {
861 gather_frames_to_render(C, oglrender);
862 }
863
866 }
867 else {
868 oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_HIGH);
869 }
870 }
871
872 CTX_wm_area_set(C, prev_area);
873 CTX_wm_region_set(C, prev_region);
874
875 return true;
876}
877
878static void screen_opengl_render_end(OGLRender *oglrender)
879{
880 /* Ensure we don't call this both from the job and operator callbacks. */
881 if (oglrender->ended) {
882 return;
883 }
884
885 if (oglrender->task_pool) {
886 /* Trickery part for movie output:
887 *
888 * We MUST write frames in an exact order, so we only let background
889 * thread to work on that, and main thread is simply waits for that
890 * thread to do all the dirty work.
891 *
892 * After this loop is done work_and_wait() will have nothing to do,
893 * so we don't run into wrong order of frames written to the stream.
894 */
895 if (BKE_imtype_is_movie(oglrender->scene->r.im_format.imtype)) {
896 std::unique_lock lock(oglrender->task_mutex);
897 while (oglrender->num_scheduled_frames > 0) {
898 oglrender->task_condition.wait(lock);
899 }
900 }
901
903 BLI_task_pool_free(oglrender->task_pool);
904 oglrender->task_pool = nullptr;
905 }
906
907 MEM_SAFE_FREE(oglrender->render_frames);
908
909 if (!oglrender->movie_writers.is_empty()) {
910 if (BKE_imtype_is_movie(oglrender->scene->r.im_format.imtype)) {
911 for (MovieWriter *writer : oglrender->movie_writers) {
912 MOV_write_end(writer);
913 }
914 }
915 oglrender->movie_writers.clear_and_shrink();
916 }
917
918 if (oglrender->ofs || oglrender->viewport) {
920 GPU_offscreen_free(oglrender->ofs);
921 GPU_viewport_free(oglrender->viewport);
923
924 oglrender->ofs = nullptr;
925 oglrender->viewport = nullptr;
926 }
927
928 MEM_SAFE_FREE(oglrender->seq_data.ibufs_arr);
929
931
932 if (oglrender->wm_job) { /* exec will not have a job */
933 Depsgraph *depsgraph = oglrender->depsgraph;
934 oglrender->scene->r.cfra = oglrender->cfrao;
936 }
937 else if (oglrender->win) {
938 WM_cursor_modal_restore(oglrender->win);
939 }
940
942 G.is_rendering = false;
943 oglrender->ended = true;
944}
945
947{
949 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
950
951 if (oglrender->is_animation) {
953 }
954
955 screen_opengl_render_end(oglrender);
956 MEM_delete(oglrender);
957}
958
959/* share between invoke and exec */
961{
962 /* initialize animation */
963 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
964 Scene *scene = oglrender->scene;
965
966 ImageFormatData image_format;
967 BKE_image_format_init_for_write(&image_format, scene, nullptr, true);
968
969 oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r, &image_format);
970 oglrender->reports = op->reports;
971
972 if (BKE_imtype_is_movie(image_format.imtype)) {
973 size_t width, height;
974 int i;
975
977 &scene->r, &image_format, oglrender->sizex, oglrender->sizey, &width, &height);
978 oglrender->movie_writers.reserve(oglrender->totvideos);
979
980 for (i = 0; i < oglrender->totvideos; i++) {
981 Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
982 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
983 MovieWriter *writer = MOV_write_begin(scene_eval,
984 &scene->r,
985 &image_format,
986 oglrender->sizex,
987 oglrender->sizey,
988 oglrender->reports,
989 PRVRANGEON != 0,
990 suffix);
991 if (writer == nullptr) {
992 BKE_image_format_free(&image_format);
993 screen_opengl_render_end(oglrender);
994 MEM_delete(oglrender);
995 return false;
996 }
997 oglrender->movie_writers.append(writer);
998 }
999 }
1000
1001 BKE_image_format_free(&image_format);
1002
1003 G.is_rendering = true;
1004 oglrender->cfrao = scene->r.cfra;
1005 oglrender->nfra = PSFRA;
1006 scene->r.cfra = PSFRA;
1007
1008 return true;
1009}
1010
1015
1016static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
1017{
1018 OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
1019 Scene *scene = &task_data->tmp_scene;
1020 RenderResult *rr = task_data->rr;
1021 const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1022 const int cfra = scene->r.cfra;
1023 bool ok;
1024 /* Don't attempt to write if we've got an error. */
1025 if (!oglrender->pool_ok) {
1027 std::scoped_lock lock(oglrender->task_mutex);
1028 oglrender->num_scheduled_frames--;
1029 oglrender->task_condition.notify_all();
1030 return;
1031 }
1032 /* Construct local thread0safe copy of reports structure which we can
1033 * safely pass to the underlying functions.
1034 */
1035 ReportList reports;
1036 BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
1037 /* Do actual save logic here, depending on the file format.
1038 *
1039 * NOTE: We have to construct temporary scene with proper scene->r.cfra.
1040 * This is because underlying calls do not use r.cfra but use scene
1041 * for that.
1042 */
1043 if (is_movie) {
1044 ok = RE_WriteRenderViewsMovie(&reports,
1045 rr,
1046 scene,
1047 &scene->r,
1048 oglrender->movie_writers.data(),
1049 oglrender->totvideos,
1050 PRVRANGEON != 0);
1051 }
1052 else {
1053 /* TODO(sergey): We can in theory save some CPU ticks here because we
1054 * calculate file name again here.
1055 */
1056 char filepath[FILE_MAX];
1057 path_templates::VariableMap template_variables;
1058 BKE_add_template_variables_general(template_variables, &scene->id);
1059 BKE_add_template_variables_for_render_path(template_variables, *scene);
1060
1061 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
1063 filepath,
1064 scene->r.pic,
1065 relbase,
1066 &template_variables,
1067 cfra,
1068 &scene->r.im_format,
1069 (scene->r.scemode & R_EXTENSION) != 0,
1070 true,
1071 nullptr);
1072
1073 if (!errors.is_empty()) {
1074 BKE_report_path_template_errors(&reports, RPT_ERROR, scene->r.pic, errors);
1075 ok = false;
1076 }
1077 else {
1078 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
1079 ok = BKE_image_render_write(nullptr, rr, scene, true, filepath);
1080 }
1081
1082 if (!ok) {
1083 BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", filepath);
1084 }
1085 }
1086 if (reports.list.first != nullptr) {
1087 /* TODO: Should rather use new #BKE_reports_move_to_reports ? */
1088 std::unique_lock lock(oglrender->reports_mutex);
1089 for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
1090 report = report->next)
1091 {
1092 BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
1093 }
1094 }
1095 BKE_reports_free(&reports);
1096 if (!ok) {
1097 oglrender->pool_ok = false;
1098 }
1100
1101 {
1102 std::unique_lock lock(oglrender->task_mutex);
1103 oglrender->num_scheduled_frames--;
1104 oglrender->task_condition.notify_all();
1105 }
1106}
1107
1108static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
1109{
1110 /* Isolate task so that multithreaded image operations don't cause this thread to start
1111 * writing another frame. If that happens we may reach the MAX_SCHEDULED_FRAMES limit,
1112 * and cause the render thread and writing threads to deadlock waiting for each other. */
1113 WriteTaskData *task_data = (WriteTaskData *)task_data_v;
1114 blender::threading::isolate_task([&] { write_result(pool, task_data); });
1115}
1116
1118{
1119 if (!oglrender->pool_ok) {
1121 return false;
1122 }
1123 Scene *scene = oglrender->scene;
1124 WriteTaskData *task_data = MEM_callocN<WriteTaskData>("write task data");
1125 task_data->rr = rr;
1126 memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
1127 {
1128 std::unique_lock lock(oglrender->task_mutex);
1129 oglrender->num_scheduled_frames++;
1130 if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
1131 oglrender->task_condition.wait(lock);
1132 }
1133 }
1134 BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
1135 return true;
1136}
1137
1139{
1140 Scene *scene = oglrender->scene;
1141 Depsgraph *depsgraph = oglrender->depsgraph;
1142 char filepath[FILE_MAX];
1143 bool ok = false;
1144 const bool view_context = (oglrender->v3d != nullptr);
1145 bool is_movie;
1146 RenderResult *rr;
1147
1148 /* go to next frame */
1149 if (scene->r.cfra < oglrender->nfra) {
1150 scene->r.cfra++;
1151 }
1152 while (scene->r.cfra < oglrender->nfra) {
1154 scene->r.cfra++;
1155 }
1156
1157 is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1158
1159 if (!is_movie) {
1160 path_templates::VariableMap template_variables;
1161 BKE_add_template_variables_general(template_variables, &scene->id);
1162 BKE_add_template_variables_for_render_path(template_variables, *scene);
1163
1164 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
1166 filepath,
1167 scene->r.pic,
1168 relbase,
1169 &template_variables,
1170 scene->r.cfra,
1171 &scene->r.im_format,
1172 (scene->r.scemode & R_EXTENSION) != 0,
1173 true,
1174 nullptr);
1175
1176 if (!errors.is_empty()) {
1177 std::unique_lock lock(oglrender->reports_mutex);
1178 BKE_report_path_template_errors(oglrender->reports, RPT_ERROR, scene->r.pic, errors);
1179 ok = false;
1180 }
1181 else if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(filepath)) {
1182 {
1183 std::unique_lock lock(oglrender->reports_mutex);
1184 BKE_reportf(oglrender->reports, RPT_INFO, "Skipping existing frame \"%s\"", filepath);
1185 }
1186 ok = true;
1187 goto finally;
1188 }
1189 }
1190
1191 if (!oglrender->wm_job && oglrender->win) {
1192 /* When doing blocking animation render without a job from a Python script, show time cursor so
1193 * Blender doesn't appear frozen. */
1194 WM_cursor_time(oglrender->win, scene->r.cfra);
1195 }
1196
1198
1199 if (view_context) {
1200 if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
1201 oglrender->v3d->scenelock)
1202 {
1203 /* since BKE_scene_graph_update_for_newframe() is used rather
1204 * then ED_update_for_newframe() the camera needs to be set */
1205 if (BKE_scene_camera_switch_update(scene)) {
1206 oglrender->v3d->camera = scene->camera;
1207 }
1208 }
1209 }
1210 else {
1212 }
1213
1214 if (oglrender->render_frames == nullptr ||
1215 BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA))
1216 {
1217 /* render into offscreen buffer */
1218 screen_opengl_render_apply(oglrender);
1219 }
1220
1221 /* save to disk */
1222 rr = RE_AcquireResultRead(oglrender->re);
1223 {
1225 RE_ReleaseResult(oglrender->re);
1226
1227 ok = schedule_write_result(oglrender, new_rr);
1228 }
1229
1230finally: /* Step the frame and bail early if needed */
1231
1232 /* go to next frame */
1233 oglrender->nfra += scene->r.frame_step;
1234
1235 /* stop at the end or on error */
1236 if (scene->r.cfra >= PEFRA || !ok) {
1237 return false;
1238 }
1239
1240 return true;
1241}
1242
1244 wmOperator *op,
1245 const wmEvent *event)
1246{
1247 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1248
1249 /* Still render completes immediately, but still modal to show some feedback
1250 * in case render initialization takes a while. */
1251 if (!oglrender->is_animation) {
1252 screen_opengl_render_apply(oglrender);
1253 screen_opengl_render_end(oglrender);
1254 MEM_delete(oglrender);
1255 return OPERATOR_FINISHED;
1256 }
1257
1258 /* no running blender, remove handler and pass through */
1259 if (0 == WM_jobs_test(CTX_wm_manager(C), oglrender->scene, WM_JOB_TYPE_RENDER)) {
1260 screen_opengl_render_end(oglrender);
1261 MEM_delete(oglrender);
1263 }
1264
1265 /* catch escape key. */
1267}
1268
1269static void opengl_render_startjob(void *customdata, wmJobWorkerStatus *worker_status)
1270{
1271 OGLRender *oglrender = static_cast<OGLRender *>(customdata);
1272 Scene *scene = oglrender->scene;
1273
1274 bool canceled = false;
1275 bool finished = false;
1276
1277 while (!finished && !canceled) {
1278 /* Render while blocking main thread, since we use 3D viewport resources. */
1280
1281 if (worker_status->stop || G.is_break) {
1282 canceled = true;
1283 }
1284 else {
1285 finished = !screen_opengl_render_anim_step(oglrender);
1286 worker_status->progress = float(scene->r.cfra - PSFRA + 1) / float(PEFRA - PSFRA + 1);
1287 worker_status->do_update = true;
1288 }
1289
1291
1292 if (worker_status->stop || G.is_break) {
1293 canceled = true;
1294 }
1295 }
1296
1297 if (canceled) {
1298 /* Cancel task pool writing images asynchronously. */
1299 oglrender->pool_ok = false;
1300 }
1301}
1302
1303static void opengl_render_freejob(void *customdata)
1304{
1305 /* End the render here, as the modal handler might be called with the window out of focus. */
1306 OGLRender *oglrender = static_cast<OGLRender *>(customdata);
1307 screen_opengl_render_end(oglrender);
1308}
1309
1311 wmOperator *op,
1312 const wmEvent *event)
1313{
1314 const bool anim = RNA_boolean_get(op->ptr, "animation");
1315
1316 if (!screen_opengl_render_init(C, op)) {
1317 return OPERATOR_CANCELLED;
1318 }
1319
1320 if (anim) {
1322 return OPERATOR_CANCELLED;
1323 }
1324 }
1325
1326 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1327 render_view_open(C, event->xy[0], event->xy[1], op->reports);
1328
1329 /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
1330 oglrender->win = CTX_wm_window(C);
1331
1332 /* Setup animation job. */
1333 if (anim) {
1334 G.is_break = false;
1335
1336 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
1338 oglrender->scene,
1339 "Rendering viewport...",
1342
1343 oglrender->wm_job = wm_job;
1344
1346 WM_jobs_timer(wm_job, 0.01f, NC_SCENE | ND_RENDER_RESULT, 0);
1347 WM_jobs_callbacks(wm_job, opengl_render_startjob, nullptr, nullptr, nullptr);
1348 WM_jobs_start(CTX_wm_manager(C), wm_job);
1349 }
1350
1352
1354}
1355
1356/* executes blocking render */
1358{
1359 if (!screen_opengl_render_init(C, op)) {
1360 return OPERATOR_CANCELLED;
1361 }
1362
1363 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1364
1365 if (!oglrender->is_animation) { /* same as invoke */
1366 screen_opengl_render_apply(oglrender);
1367 screen_opengl_render_end(oglrender);
1368 MEM_delete(oglrender);
1369
1370 return OPERATOR_FINISHED;
1371 }
1372
1373 bool ret = true;
1374
1376 return OPERATOR_CANCELLED;
1377 }
1378
1379 while (ret) {
1381 }
1382
1383 screen_opengl_render_end(oglrender);
1384 MEM_delete(oglrender);
1385
1386 return OPERATOR_FINISHED;
1387}
1388
1390 wmOperatorType * /*ot*/,
1391 PointerRNA *ptr)
1392{
1393 if (!RNA_boolean_get(ptr, "animation")) {
1394 return "";
1395 }
1396
1397 if (RNA_boolean_get(ptr, "render_keyed_only")) {
1398 return TIP_(
1399 "Render the viewport for the animation range of this scene, but only render keyframes of "
1400 "selected objects");
1401 }
1402
1403 return TIP_("Render the viewport for the animation range of this scene");
1404}
1405
1407{
1408 PropertyRNA *prop;
1409
1410 /* identifiers */
1411 ot->name = "Viewport Render";
1412 ot->description = "Take a snapshot of the active viewport";
1413 ot->idname = "RENDER_OT_opengl";
1414
1415 /* API callbacks. */
1416 ot->get_description = screen_opengl_render_get_description;
1418 ot->exec = screen_opengl_render_exec; /* blocking */
1421
1423
1424 prop = RNA_def_boolean(ot->srna,
1425 "animation",
1426 false,
1427 "Animation",
1428 "Render files from the animation range of this scene");
1430
1431 prop = RNA_def_boolean(ot->srna,
1432 "render_keyed_only",
1433 false,
1434 "Render Keyframes Only",
1435 "Render only those frames where selected objects have a key in their "
1436 "animation data. Only used when rendering animation");
1438
1439 prop = RNA_def_boolean(
1440 ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
1442 prop = RNA_def_boolean(
1443 ot->srna,
1444 "write_still",
1445 false,
1446 "Write Image",
1447 "Save the rendered image to the output path (used only when animation is disabled)");
1449 prop = RNA_def_boolean(ot->srna,
1450 "view_context",
1451 true,
1452 "View Context",
1453 "Use the current 3D view for rendering, else use scene settings");
1455}
Functions for backward compatibility with the legacy Action API.
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
Camera data-block and utility functions.
struct Object * BKE_camera_multiview_render(const struct Scene *scene, struct Object *camera, const char *viewname)
WorkSpace * CTX_wm_workspace(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
#define CTX_DATA_END
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition customdata.cc:96
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
@ G_FLAG_RENDER_VIEWPORT
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot)
#define IMA_SIGNAL_FREE
Definition BKE_image.hh:169
void BKE_render_result_stamp_info(Scene *scene, Object *camera, RenderResult *rr, bool allocate_only)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
void BKE_image_stamp_buf(Scene *scene, Object *camera, const StampData *stamp_data_template, ImBuf *ibuf)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_image_format_free(ImageFormatData *imf)
blender::Vector< blender::bke::path_templates::Error > BKE_image_path_from_imformat(char *filepath, const char *base, const char *relbase, const blender::bke::path_templates::VariableMap *template_variables, int frame, const ImageFormatData *im_format, bool use_ext, bool use_frames, const char *suffix)
void BKE_image_format_init_for_write(ImageFormatData *imf, const Scene *scene_src, const ImageFormatData *imf_src, const bool allow_video=false)
bool BKE_imtype_is_movie(char imtype)
bool BKE_image_render_write(ReportList *reports, RenderResult *rr, const Scene *scene, const bool stamp, const char *filepath_basis, const ImageFormatData *format=nullptr, bool save_as_render=true)
@ IDWALK_RET_STOP_RECURSION
@ IDWALK_RET_NOP
LibraryForeachIDCallbackFlag
@ IDWALK_CB_LOOPBACK
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, LibraryForeachIDFlag flag)
Definition lib_query.cc:431
@ IDWALK_RECURSE
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
void BKE_report_path_template_errors(ReportList *reports, eReportType report_type, blender::StringRef path, blender::Span< blender::bke::path_templates::Error > errors)
void BKE_add_template_variables_for_render_path(blender::bke::path_templates::VariableMap &variables, const Scene &scene)
void BKE_add_template_variables_general(blender::bke::path_templates::VariableMap &variables, const ID *path_owner_id)
@ RPT_PRINT
Definition BKE_report.hh:55
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
eReportType
Definition BKE_report.hh:33
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_reports_free(ReportList *reports)
Definition report.cc:97
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:82
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2915
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2626
void BKE_scene_multiview_videos_dimensions_get(const RenderData *rd, const ImageFormatData *imf, size_t width, size_t height, size_t *r_width, size_t *r_height)
Definition scene.cc:3195
int BKE_scene_multiview_num_views_get(const RenderData *rd)
Definition scene.cc:2940
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:2988
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3154
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2265
bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
Definition scene.cc:2971
int BKE_scene_multiview_num_videos_get(const RenderData *rd, const ImageFormatData *imf)
Definition scene.cc:3216
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2700
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:37
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:78
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition BLI_bitmap.h:71
unsigned int BLI_bitmap
Definition BLI_bitmap.h:13
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
MINLINE int round_fl_to_int(float a)
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
#define FILE_MAX
#define STRNCPY_UTF8(dst, src)
unsigned char uchar
unsigned int uint
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:53
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:550
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:535
TaskPool * BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority)
Definition task_pool.cc:516
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:484
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:521
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:526
#define UNUSED_FUNCTION(x)
#define TIP_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_INFO_NOCHECK(clg_ref, format,...)
Definition CLG_log.h:204
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
ID_Type
@ ID_WM
@ ID_CA
@ ID_AR
@ ID_MC
@ ID_CF
@ ID_LI
@ ID_TE
@ ID_IM
@ ID_VO
@ ID_WS
@ ID_NT
@ ID_LA
@ ID_KE
@ ID_TXT
@ ID_SO
@ ID_SCE
@ ID_LS
@ ID_MSK
@ ID_CV
@ ID_PAL
@ ID_BR
@ ID_LP
@ ID_WO
@ ID_MA
@ ID_AC
@ ID_SCR
@ ID_CU_LEGACY
@ ID_GD_LEGACY
@ ID_VF
@ ID_ME
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PA
@ ID_PT
@ ID_PC
@ IMA_TYPE_R_RESULT
@ IMA_SHOW_STEREO
eDrawType
@ OB_SOLID
Object is a sort of wrapper for general info.
#define R_STAMP_ALL
@ R_STAMP_DRAW
@ R_NO_OVERWRITE
#define PSFRA
#define V3D_CAMERA_SCENE(scene, v3d)
eImageFormatDepth
@ R_IMF_CHAN_DEPTH_32
@ R_ADDSKY
@ R_ALPHAPREMUL
@ R_MULTIVIEW
@ R_EXTENSION
#define PRVRANGEON
#define PEFRA
@ SEQ_RENDER_SIZE_SCENE
@ SPACE_SEQ
@ SEQ_PREVIEW_SHOW_GPENCIL
@ V3D_OFSDRAW_SHOW_ANNOTATION
@ RV3D_CAMOB
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void DRW_gpu_context_disable()
void DRW_gpu_context_enable()
bool ED_operator_screenactive(bContext *C)
void ED_view3d_datamask(const Scene *scene, ViewLayer *view_layer, const View3D *v3d, CustomData_MeshMasks *r_cddata_masks)
bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
bool ED_view3d_context_activate(bContext *C)
ImBuf * ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph, Scene *scene, eDrawType drawtype, View3D *v3d, ARegion *region, int sizex, int sizey, eImBufFlags imbuf_flag, int alpha_mode, const char *viewname, bool restore_rv3d_mats, GPUOffScreen *ofs, GPUViewport *viewport, char err_out[256])
ImBuf * ED_view3d_draw_offscreen_imbuf_simple(Depsgraph *depsgraph, Scene *scene, View3DShading *shading_override, eDrawType drawtype, Object *camera, int width, int height, eImBufFlags imbuf_flags, eV3DOffscreenDrawFlag draw_flags, int alpha_mode, const char *viewname, GPUOffScreen *ofs, GPUViewport *viewport, char err_out[256])
void GPU_render_step(bool force_resource_release=false)
GPUBackendType GPU_backend_get_type()
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, blender::gpu::TextureFormat format, eGPUTextureUsage usage, bool clear, char err_out[256])
void GPU_clear_color(float red, float green, float blue, float alpha)
void GPU_offscreen_free(GPUOffScreen *offscreen)
void GPU_clear_depth(float depth)
void GPU_offscreen_read_color(GPUOffScreen *offscreen, eGPUDataFormat data_format, void *r_data)
void GPU_offscreen_unbind(GPUOffScreen *offscreen, bool restore)
void GPU_matrix_reset()
Definition gpu_matrix.cc:85
void GPU_matrix_translate_2f(float x, float y)
void GPU_flush()
Definition gpu_state.cc:305
@ GPU_DATA_UBYTE
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_HOST_READ
GPUViewport * GPU_viewport_create()
void GPU_viewport_free(GPUViewport *viewport)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_free_float_pixels(ImBuf *ibuf)
@ IB_DISPLAY_BUFFER_INVALID
@ IB_float_data
@ IB_byte_data
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#define C
Definition RandGen.cpp:29
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1778
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1765
@ WM_JOB_PROGRESS
Definition WM_api.hh:1766
@ WM_JOB_PRIORITY
Definition WM_api.hh:1760
#define ND_RENDER_RESULT
Definition WM_types.hh:446
#define NC_SCENE
Definition WM_types.hh:378
void ED_annotation_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
volatile int lock
BPy_StructRNA * depsgraph
static void mul(btAlignedObjectArray< T > &items, const Q &value)
void append(const T &value)
bool is_empty() const
T * data()
void reserve(const int64_t min_capacity)
void clear_and_shrink()
bool is_empty() const
nullptr float
#define offsetof(t, d)
#define GS(x)
void RE_SetOverrideCamera(Render *re, Object *cam_ob)
#define LOG(level)
Definition log.h:97
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
void MOV_write_end(MovieWriter *writer)
MovieWriter * MOV_write_begin(const Scene *scene, const RenderData *rd, const ImageFormatData *imf, int rectx, int recty, ReportList *reports, bool preview, const char *suffix)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
ImBuf * render_give_ibuf(const RenderData *context, float timeline_frame, int chanshown)
Definition render.cc:2028
void render_new_render_data(Main *bmain, Depsgraph *depsgraph, Scene *scene, int rectx, int recty, eSpaceSeq_Proxy_RenderSize preview_render_size, Render *render, RenderData *r_context)
Definition render.cc:210
void isolate_task(const Function &function)
Definition BLI_task.hh:248
std::mutex Mutex
Definition BLI_mutex.hh:47
const char * name
return ret
ScrArea * render_view_open(bContext *C, int mx, int my, ReportList *reports)
static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
static void UNUSED_FUNCTION addAlphaOverFloat(float dest[4], const float source[4])
static bool screen_opengl_render_anim_step(OGLRender *oglrender)
static wmOperatorStatus screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void screen_opengl_render_apply(OGLRender *oglrender)
static std::string screen_opengl_render_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
#define MAX_SCHEDULED_FRAMES
static void opengl_render_startjob(void *customdata, wmJobWorkerStatus *worker_status)
static wmOperatorStatus screen_opengl_render_exec(bContext *C, wmOperator *op)
static void screen_opengl_views_setup(OGLRender *oglrender)
static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
static void opengl_render_freejob(void *customdata)
static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
static void screen_opengl_render_write(OGLRender *oglrender)
static wmOperatorStatus screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void screen_opengl_render_end(OGLRender *oglrender)
static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
void RENDER_OT_opengl(wmOperatorType *ot)
static bool screen_opengl_is_multiview(OGLRender *oglrender)
static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr)
static bool screen_opengl_render_init(bContext *C, wmOperator *op)
static bool screen_opengl_render_anim_init(wmOperator *op)
static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender, const bGPdata *gp)
static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const int view_id)
RenderResult * RE_DuplicateRenderResult(RenderResult *rr)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RE_ReleaseResultImage(Render *re)
void RE_InitState(Render *re, Render *source, RenderData *rd, ListBase *, ViewLayer *single_layer, int winx, int winy, const rcti *disprect)
void RE_FreeRenderResult(RenderResult *rr)
RenderResult * RE_AcquireResultWrite(Render *re)
Render * RE_NewSceneRender(const Scene *scene)
RenderResult * RE_AcquireResultRead(Render *re)
void RE_ReleaseResult(Render *re)
const char * RE_GetActiveRenderView(Render *re)
bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, MovieWriter **movie_writers, const int totvideos, bool preview)
void RE_SetActiveRenderView(Render *re, const char *viewname)
void * regiondata
bAction * action
float vec[3][3]
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
struct Scene * scene
LibraryForeachIDCallbackFlag cb_flag
void * last
void * first
wmJob * wm_job
TaskPool * task_pool
BLI_bitmap * render_frames
ViewLayer * view_layer
std::mutex task_mutex
Render * re
ImBuf ** ibufs_arr
uint num_scheduled_frames
Depsgraph * depsgraph
RegionView3D * rv3d
GPUViewport * viewport
WorkSpace * workspace
wmWindowManager * wm
std::condition_variable task_condition
struct OGLRender::@275256070246063345275261234227353024320111056241 seq_data
ARegion * region
ReportList * reports
blender::Mutex reports_mutex
ImageUser iuser
eImageFormatDepth color_depth
GPUOffScreen * ofs
SpaceSeq * sseq
View3D * v3d
wmWindow * win
blender::Vector< MovieWriter * > movie_writers
struct ImageFormatData im_format
char pic[1024]
Scene * current_scene
ListBase views
struct ImBuf * ibuf
Definition RE_pipeline.h:49
struct RenderView * prev
Definition RE_pipeline.h:41
struct RenderView * next
Definition RE_pipeline.h:41
char name[64]
Definition RE_pipeline.h:42
ListBase list
Definition BKE_report.hh:75
Report * next
Definition BKE_report.hh:64
struct CustomData_MeshMasks customdata_mask
struct RenderData r
ListBase view_layers
struct CustomData_MeshMasks customdata_mask_modal
struct Object * camera
struct bGPdata * gpd
struct Object * camera
short scenelock
View3DShading shading
RenderResult * rr
wmEventType type
Definition WM_types.hh:757
int xy[2]
Definition WM_types.hh:761
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_cursor_modal_restore(wmWindow *win)
void WM_cursor_time(wmWindow *win, int nr)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:376
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:479
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:623
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:211
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:388
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:614
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:247
void WM_job_main_thread_lock_acquire(wmJob *wm_job)
Definition wm_jobs.cc:145
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:360
void WM_job_main_thread_lock_release(wmJob *wm_job)
Definition wm_jobs.cc:150
void wmOrtho2(float x1, float x2, float y1, float y2)