Blender V4.5
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.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 "render_intern.hh"
82
84
85/* TODO(sergey): Find better approximation of the scheduled frames.
86 * For really high-resolution renders it might fail still. */
87#define MAX_SCHEDULED_FRAMES 8
88
89struct OGLRender : public RenderJobBase {
90 Main *bmain = nullptr;
91 Render *re = nullptr;
92 WorkSpace *workspace = nullptr;
94 Depsgraph *depsgraph = nullptr;
95
96 View3D *v3d = nullptr;
97 RegionView3D *rv3d = nullptr;
98 ARegion *region = nullptr;
99
100 int views_len = 0; /* multi-view views */
101
102 bool is_sequencer = false;
103 SpaceSeq *sseq = nullptr;
104 struct {
105 ImBuf **ibufs_arr = nullptr;
107
108 Image *ima = nullptr;
110
111 GPUOffScreen *ofs = nullptr;
112 int sizex = 0;
113 int sizey = 0;
114 int write_still = false;
115
117
119 ReportList *reports = nullptr;
120
121 int cfrao = 0;
122 int nfra = 0;
123
124 int totvideos = 0;
125
126 /* For only rendering frames that have a key in animation data. */
128
129 /* quick lookup */
130 int view_id = 0;
131
132 /* wm vars for timer and progress cursor */
133 wmWindowManager *wm = nullptr;
134 wmWindow *win = nullptr;
135
137
138 TaskPool *task_pool = nullptr;
139 bool pool_ok = true;
140 bool is_animation = false;
141
144 std::mutex task_mutex;
145 std::condition_variable task_condition;
146
147 wmJob *wm_job = nullptr;
148
149 bool ended = false;
150};
151
153{
154 View3D *v3d = oglrender->v3d;
155 RegionView3D *rv3d = oglrender->rv3d;
156 RenderData *rd = &oglrender->scene->r;
157
158 if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
159 return false;
160 }
161
162 return (rd->scemode & R_MULTIVIEW) &&
163 ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
164}
165
167{
168 RenderResult *rr;
169 RenderView *rv;
170 SceneRenderView *srv;
171 bool is_multiview;
172 Object *camera;
173 View3D *v3d = oglrender->v3d;
174
175 RenderData *rd = &oglrender->scene->r;
176
177 rr = RE_AcquireResultWrite(oglrender->re);
178
179 is_multiview = screen_opengl_is_multiview(oglrender);
180
181 if (!is_multiview) {
182 /* we only have one view when multiview is off */
183 rv = static_cast<RenderView *>(rr->views.first);
184
185 if (rv == nullptr) {
186 rv = MEM_callocN<RenderView>("new opengl render view");
187 BLI_addtail(&rr->views, rv);
188 }
189
190 while (rv->next) {
191 RenderView *rv_del = rv->next;
192 BLI_remlink(&rr->views, rv_del);
193
194 IMB_freeImBuf(rv_del->ibuf);
195
196 MEM_freeN(rv_del);
197 }
198 }
199 else {
200 if (v3d) {
201 RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
202 }
203
204 /* remove all the views that are not needed */
205 rv = static_cast<RenderView *>(rr->views.last);
206 while (rv) {
207 srv = static_cast<SceneRenderView *>(
210 rv = rv->prev;
211 }
212 else {
213 RenderView *rv_del = rv;
214 rv = rv_del->prev;
215
216 BLI_remlink(&rr->views, rv_del);
217
218 IMB_freeImBuf(rv_del->ibuf);
219
220 MEM_freeN(rv_del);
221 }
222 }
223
224 /* create all the views that are needed */
225 LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) {
226 if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
227 continue;
228 }
229
230 rv = static_cast<RenderView *>(
231 BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
232
233 if (rv == nullptr) {
234 rv = MEM_callocN<RenderView>("new opengl render view");
235 STRNCPY(rv->name, srv->name);
236 BLI_addtail(&rr->views, rv);
237 }
238 }
239 }
240
241 if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) {
242 oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
243 }
244
245 /* will only work for non multiview correctly */
246 if (v3d) {
247 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
248 BKE_render_result_stamp_info(oglrender->scene, camera, rr, false);
249 }
250 else {
251 BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false);
252 }
253
254 RE_ReleaseResult(oglrender->re);
255}
256
258{
259 Scene *scene = oglrender->scene;
260 Object *camera = nullptr;
261 int sizex = oglrender->sizex;
262 int sizey = oglrender->sizey;
263 ImBuf *ibuf_result = nullptr;
264
265 if (oglrender->is_sequencer) {
266 SpaceSeq *sseq = oglrender->sseq;
267 bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
268
269 /* use pre-calculated ImBuf (avoids deadlock), see: */
270 ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
271
272 if (ibuf) {
273 ibuf_result = IMB_dupImBuf(ibuf);
274 IMB_freeImBuf(ibuf);
275 /* OpenGL render is considered to be preview and should be
276 * as fast as possible. So currently we're making sure sequencer
277 * result is always byte to simplify color management pipeline.
278 *
279 * TODO(sergey): In the case of output to float container (EXR)
280 * it actually makes sense to keep float buffer instead.
281 */
282 if (ibuf_result->float_buffer.data != nullptr) {
283 IMB_byte_from_float(ibuf_result);
284 IMB_free_float_pixels(ibuf_result);
285 }
286 BLI_assert((sizex == ibuf->x) && (sizey == ibuf->y));
287 }
288 else if (gpd) {
289 /* If there are no strips, Grease Pencil still needs a buffer to draw on */
290 ibuf_result = IMB_allocImBuf(sizex, sizey, 32, IB_byte_data);
291 }
292
293 if (gpd) {
294 int i;
295 uchar *gp_rect;
296 uchar *render_rect = ibuf_result->byte_buffer.data;
297
299 GPU_offscreen_bind(oglrender->ofs, true);
300
301 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
302 GPU_clear_depth(1.0f);
303
305 wmOrtho2(0, scene->r.xsch, 0, scene->r.ysch);
306 GPU_matrix_translate_2f(scene->r.xsch / 2, scene->r.ysch / 2);
307
309 ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
311
312 gp_rect = static_cast<uchar *>(
313 MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
314 GPU_offscreen_read_color(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
315
316 for (i = 0; i < sizex * sizey * 4; i += 4) {
317 blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
318 }
319 GPU_offscreen_unbind(oglrender->ofs, true);
321
322 MEM_freeN(gp_rect);
323 }
324 }
325 else {
326 /* shouldn't suddenly give errors mid-render but possible */
327 Depsgraph *depsgraph = oglrender->depsgraph;
328 char err_out[256] = "unknown";
329 ImBuf *ibuf_view;
330 bool draw_sky = (scene->r.alphamode == R_ADDSKY);
331 const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
332 const char *viewname = RE_GetActiveRenderView(oglrender->re);
333 View3D *v3d = oglrender->v3d;
334
336
337 if (v3d != nullptr) {
338 ARegion *region = oglrender->region;
340 scene,
341 static_cast<eDrawType>(v3d->shading.type),
342 v3d,
343 region,
344 sizex,
345 sizey,
347 alpha_mode,
348 viewname,
349 true,
350 oglrender->ofs,
351 oglrender->viewport,
352 err_out);
353
354 /* for stamp only */
355 if (oglrender->rv3d->persp == RV3D_CAMOB && v3d->camera) {
356 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
357 }
358 }
359 else {
361 scene,
362 nullptr,
363 OB_SOLID,
364 scene->camera,
365 sizex,
366 sizey,
369 alpha_mode,
370 viewname,
371 oglrender->ofs,
372 oglrender->viewport,
373 err_out);
374 camera = scene->camera;
375 }
376
377 if (ibuf_view) {
378 ibuf_result = ibuf_view;
379 }
380 else {
381 fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
382 }
383 }
384
385 if (ibuf_result != nullptr) {
386 if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
387 float *rectf = nullptr;
388 uchar *rect = nullptr;
389 if (ibuf_result->float_buffer.data) {
390 rectf = ibuf_result->float_buffer.data;
391 }
392 else {
393 rect = ibuf_result->byte_buffer.data;
394 }
395 BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty);
396 }
397 RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
398 IMB_freeImBuf(ibuf_result);
399 }
400
401 /* Perform render step between renders to allow
402 * flushing of freed GPUBackend resources. */
405 GPU_flush();
406 }
407 GPU_render_step(true);
409}
410
412{
413 Scene *scene = oglrender->scene;
414 RenderResult *rr;
415 bool ok;
416 char filepath[FILE_MAX];
417
418 rr = RE_AcquireResultRead(oglrender->re);
419
420 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
421 const path_templates::VariableMap template_variables =
424 filepath,
425 scene->r.pic,
426 relbase,
427 &template_variables,
428 scene->r.cfra,
429 &scene->r.im_format,
430 (scene->r.scemode & R_EXTENSION) != 0,
431 false,
432 nullptr);
433
434 if (!errors.is_empty()) {
435 std::unique_lock lock(oglrender->reports_mutex);
436 BKE_report_path_template_errors(oglrender->reports, RPT_ERROR, scene->r.pic, errors);
437 ok = false;
438 }
439 else {
440 /* write images as individual images or stereo */
441 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
442 ok = BKE_image_render_write(oglrender->reports, rr, scene, false, filepath);
443
444 RE_ReleaseResultImage(oglrender->re);
445 }
446
447 if (ok) {
448 printf("OpenGL Render written to '%s'\n", filepath);
449 }
450 else {
451 printf("OpenGL Render failed to write '%s'\n", filepath);
452 }
453}
454
455static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
456{
457 /* `d = s + (1-alpha_s)d` */
458 float mul;
459
460 mul = 1.0f - source[3];
461
462 dest[0] = (mul * dest[0]) + source[0];
463 dest[1] = (mul * dest[1]) + source[1];
464 dest[2] = (mul * dest[2]) + source[2];
465 dest[3] = (mul * dest[3]) + source[3];
466}
467
469{
470 RenderResult *rr;
471 RenderView *rv;
472 int view_id;
473 ImBuf *ibuf;
474 void *lock;
475
476 if (oglrender->is_sequencer) {
477 Scene *scene = oglrender->scene;
478
480 SpaceSeq *sseq = oglrender->sseq;
481 int chanshown = sseq ? sseq->chanshown : 0;
482
484 oglrender->depsgraph,
485 scene,
486 oglrender->sizex,
487 oglrender->sizey,
489 false,
490 &context);
491
492 for (view_id = 0; view_id < oglrender->views_len; view_id++) {
493 context.view_id = view_id;
494 context.gpu_offscreen = oglrender->ofs;
495 context.gpu_viewport = oglrender->viewport;
497 &context, scene->r.cfra, chanshown);
498 }
499 }
500
501 rr = RE_AcquireResultRead(oglrender->re);
502 for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv; rv = rv->next, view_id++)
503 {
504 BLI_assert(view_id < oglrender->views_len);
505 RE_SetActiveRenderView(oglrender->re, rv->name);
506 oglrender->view_id = view_id;
507 /* render composite */
508 screen_opengl_render_doit(oglrender, rr);
509 }
510
511 RE_ReleaseResult(oglrender->re);
512
513 ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
514 if (ibuf) {
516 }
517 BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
519
520 if (oglrender->write_still) {
522 }
523}
524
525static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
526{
527 if (adt == nullptr || adt->action == nullptr) {
528 return;
529 }
530
531 Scene *scene = oglrender->scene;
532 int frame_start = PSFRA;
533 int frame_end = PEFRA;
534
536 if (fcu->driver != nullptr || fcu->fpt != nullptr) {
537 /* Drivers have values for any point in time, so to get "the keyed frames" they are
538 * useless. Same for baked FCurves, they also have keys for every frame, which is not
539 * useful for rendering the keyed subset of the frames. */
540 continue;
541 }
542
543 bool found = false; /* Not interesting, we just want a starting point for the for-loop. */
545 fcu->bezt, frame_start, fcu->totvert, &found);
546 for (; key_index < fcu->totvert; key_index++) {
547 BezTriple *bezt = &fcu->bezt[key_index];
548 /* The frame range to render uses integer frame numbers, and the frame
549 * step is also an integer, so we always render on the frame. */
550 int frame_nr = round_fl_to_int(bezt->vec[1][0]);
551
552 /* (frame_nr < frame_start) cannot happen because of the binary search above. */
553 BLI_assert(frame_nr >= frame_start);
554 if (frame_nr > frame_end) {
555 break;
556 }
557 BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
558 }
559 }
560}
561
563 const bGPdata *gp)
564{
565 if (gp == nullptr) {
566 return;
567 }
568
569 Scene *scene = oglrender->scene;
570 int frame_start = PSFRA;
571 int frame_end = PEFRA;
572
573 LISTBASE_FOREACH (const bGPDlayer *, gp_layer, &gp->layers) {
574 LISTBASE_FOREACH (const bGPDframe *, gp_frame, &gp_layer->frames) {
575 if (gp_frame->framenum < frame_start || gp_frame->framenum > frame_end) {
576 continue;
577 }
578 BLI_BITMAP_ENABLE(oglrender->render_frames, gp_frame->framenum - frame_start);
579 }
580 }
581}
582
584{
585 ID **id_p = cb_data->id_pointer;
586 if (*id_p == nullptr) {
587 return IDWALK_RET_NOP;
588 }
589 ID *id = *id_p;
590
591 ID *self_id = cb_data->self_id;
592 const LibraryForeachIDCallbackFlag cb_flag = cb_data->cb_flag;
593 if (cb_flag == IDWALK_CB_LOOPBACK || id == self_id) {
594 /* IDs may end up referencing themselves one way or the other, and those
595 * (the self_id ones) have always already been processed. */
597 }
598
599 OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
600
601 /* Whitelist of datablocks to follow pointers into. */
602 const ID_Type id_type = GS(id->name);
603 switch (id_type) {
604 /* Whitelist: */
605 case ID_ME: /* Mesh */
606 case ID_CU_LEGACY: /* Curve */
607 case ID_MB: /* MetaBall */
608 case ID_MA: /* Material */
609 case ID_TE: /* Tex (Texture) */
610 case ID_IM: /* Image */
611 case ID_LT: /* Lattice */
612 case ID_LA: /* Light */
613 case ID_CA: /* Camera */
614 case ID_KE: /* Key (shape key) */
615 case ID_VF: /* VFont (Vector Font) */
616 case ID_TXT: /* Text */
617 case ID_SPK: /* Speaker */
618 case ID_SO: /* Sound */
619 case ID_AR: /* bArmature */
620 case ID_NT: /* bNodeTree */
621 case ID_PA: /* ParticleSettings */
622 case ID_MC: /* MovieClip */
623 case ID_MSK: /* Mask */
624 case ID_LP: /* LightProbe */
625 case ID_CV: /* Curves */
626 case ID_PT: /* PointCloud */
627 case ID_VO: /* Volume */
628 break;
629
630 /* Blacklist: */
631 case ID_SCE: /* Scene */
632 case ID_LI: /* Library */
633 case ID_OB: /* Object */
634 case ID_IP: /* Ipo (depreciated, replaced by FCurves) */
635 case ID_WO: /* World */
636 case ID_SCR: /* Screen */
637 case ID_GR: /* Group */
638 case ID_AC: /* bAction */
639 case ID_BR: /* Brush */
640 case ID_WM: /* WindowManager */
641 case ID_LS: /* FreestyleLineStyle */
642 case ID_PAL: /* Palette */
643 case ID_PC: /* PaintCurve */
644 case ID_CF: /* CacheFile */
645 case ID_WS: /* WorkSpace */
646 /* Only follow pointers to specific datablocks, to avoid ending up in
647 * unrelated datablocks and exploding the number of blocks we follow. If the
648 * frames of the animation of certain objects should be taken into account,
649 * they should have been selected by the user. */
651
652 /* Special cases: */
653 case ID_GD_LEGACY: /* bGPdata, (Grease Pencil) */
654 /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation
655 * system that requires specific handling here. */
657 break;
658 case ID_GP:
659 /* TODO: gather frames. */
660 break;
661 }
662
664 gather_frames_to_render_for_adt(oglrender, adt);
665
666 return IDWALK_RET_NOP;
667}
668
677{
678 Scene *scene = oglrender->scene;
679 int frame_start = PSFRA;
680 int frame_end = PEFRA;
681
682 /* Will be freed in screen_opengl_render_end(). */
683 oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
684 "OGLRender::render_frames");
685
686 /* The first frame should always be rendered, otherwise there is nothing to write to file. */
687 BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
688
689 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
690 ID *id = &ob->id;
691
692 /* Gather the frames from the object animation data. */
694 gather_frames_to_render_for_adt(oglrender, adt);
695
696 /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
698 nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
699 }
701}
702
704{
705 /* new render clears all callbacks */
707 wmWindow *win = CTX_wm_window(C);
708 WorkSpace *workspace = CTX_wm_workspace(C);
709
710 Scene *scene = CTX_data_scene(C);
711 ScrArea *prev_area = CTX_wm_area(C);
712 ARegion *prev_region = CTX_wm_region(C);
713 GPUOffScreen *ofs;
714 OGLRender *oglrender;
715 int sizex, sizey;
716 bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
717 const bool is_animation = RNA_boolean_get(op->ptr, "animation");
718 const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
719 const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
720 const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
721 const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
722 (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
723 char err_out[256] = "unknown";
724
725 if (G.background) {
727 op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
728 return false;
729 }
730
731 /* only one render job at a time */
732 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
733 return false;
734 }
735
736 if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
738 op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
739 return false;
740 }
741
742 if (is_sequencer) {
743 is_view_context = false;
744 }
745 else {
746 /* ensure we have a 3d view */
748 RNA_boolean_set(op->ptr, "view_context", false);
749 is_view_context = false;
750 }
751
752 if (!is_view_context && scene->camera == nullptr) {
753 BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
754 return false;
755 }
756 }
757
758 /* stop all running jobs, except screen one. currently previews frustrate Render */
760
761 /* create offscreen buffer */
762 BKE_render_resolution(&scene->r, false, &sizex, &sizey);
763
764 /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
765 DRW_gpu_context_enable(); /* Off-screen creation needs to be done in DRW context. */
766 ofs = GPU_offscreen_create(sizex,
767 sizey,
768 true,
771 false,
772 err_out);
774
775 if (!ofs) {
776 BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
777 CTX_wm_area_set(C, prev_area);
778 CTX_wm_region_set(C, prev_region);
779 return false;
780 }
781
782 /* allocate opengl render */
783 oglrender = MEM_new<OGLRender>("OGLRender");
784 op->customdata = oglrender;
785
786 oglrender->ofs = ofs;
787 oglrender->sizex = sizex;
788 oglrender->sizey = sizey;
789 oglrender->viewport = GPU_viewport_create();
790 oglrender->bmain = CTX_data_main(C);
791 oglrender->scene = scene;
792 oglrender->current_scene = scene;
793 oglrender->workspace = workspace;
794 oglrender->view_layer = CTX_data_view_layer(C);
795 /* NOTE: The depsgraph is not only used to update scene for a new frames, but also to initialize
796 * output video handles, which does need evaluated scene. */
798 oglrender->cfrao = scene->r.cfra;
799
800 oglrender->write_still = is_write_still && !is_animation;
801 oglrender->is_animation = is_animation;
802 oglrender->color_depth = color_depth;
803
804 oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
805
806 oglrender->is_sequencer = is_sequencer;
807 if (is_sequencer) {
808 oglrender->sseq = CTX_wm_space_seq(C);
809 ImBuf **ibufs_arr = static_cast<ImBuf **>(
810 MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
811 oglrender->seq_data.ibufs_arr = ibufs_arr;
812 }
813
814 if (is_view_context) {
815 /* Prefer rendering camera in quad view if possible. */
816 if (!ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region)) {
817 /* If not get region activated by ED_view3d_context_activate earlier. */
818 oglrender->v3d = CTX_wm_view3d(C);
819 oglrender->region = CTX_wm_region(C);
820 }
821
822 oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
823
824 /* MUST be cleared on exit */
826 ED_view3d_datamask(oglrender->scene,
827 oglrender->view_layer,
828 oglrender->v3d,
829 &oglrender->scene->customdata_mask_modal);
830
831 /* apply immediately in case we're rendering from a script,
832 * running notifiers again will overwrite */
834 &oglrender->scene->customdata_mask_modal);
835 }
836
837 /* create render */
838 oglrender->re = RE_NewSceneRender(scene);
839
840 /* create image and image user */
841 oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
842 BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
843 BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
844
845 oglrender->iuser.scene = scene;
846
847 /* create render result */
849 oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
850
851 /* create render views */
852 screen_opengl_views_setup(oglrender);
853
854 /* wm vars */
855 oglrender->wm = wm;
856 oglrender->win = win;
857
858 if (is_animation) {
859 if (is_render_keyed_only) {
860 gather_frames_to_render(C, oglrender);
861 }
862
865 }
866 else {
867 oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_HIGH);
868 }
869 }
870
871 CTX_wm_area_set(C, prev_area);
872 CTX_wm_region_set(C, prev_region);
873
874 return true;
875}
876
877static void screen_opengl_render_end(OGLRender *oglrender)
878{
879 /* Ensure we don't call this both from the job and operator callbacks. */
880 if (oglrender->ended) {
881 return;
882 }
883
884 if (oglrender->task_pool) {
885 /* Trickery part for movie output:
886 *
887 * We MUST write frames in an exact order, so we only let background
888 * thread to work on that, and main thread is simply waits for that
889 * thread to do all the dirty work.
890 *
891 * After this loop is done work_and_wait() will have nothing to do,
892 * so we don't run into wrong order of frames written to the stream.
893 */
894 if (BKE_imtype_is_movie(oglrender->scene->r.im_format.imtype)) {
895 std::unique_lock lock(oglrender->task_mutex);
896 while (oglrender->num_scheduled_frames > 0) {
897 oglrender->task_condition.wait(lock);
898 }
899 }
900
902 BLI_task_pool_free(oglrender->task_pool);
903 oglrender->task_pool = nullptr;
904 }
905
906 MEM_SAFE_FREE(oglrender->render_frames);
907
908 if (!oglrender->movie_writers.is_empty()) {
909 if (BKE_imtype_is_movie(oglrender->scene->r.im_format.imtype)) {
910 for (MovieWriter *writer : oglrender->movie_writers) {
911 MOV_write_end(writer);
912 }
913 }
914 oglrender->movie_writers.clear_and_shrink();
915 }
916
917 if (oglrender->ofs || oglrender->viewport) {
919 GPU_offscreen_free(oglrender->ofs);
920 GPU_viewport_free(oglrender->viewport);
922
923 oglrender->ofs = nullptr;
924 oglrender->viewport = nullptr;
925 }
926
927 MEM_SAFE_FREE(oglrender->seq_data.ibufs_arr);
928
930
931 if (oglrender->wm_job) { /* exec will not have a job */
932 Depsgraph *depsgraph = oglrender->depsgraph;
933 oglrender->scene->r.cfra = oglrender->cfrao;
935 }
936 else if (oglrender->win) {
937 WM_cursor_modal_restore(oglrender->win);
938 }
939
941 G.is_rendering = false;
942 oglrender->ended = true;
943}
944
946{
948 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
949
950 if (oglrender->is_animation) {
952 }
953
954 screen_opengl_render_end(oglrender);
955 MEM_delete(oglrender);
956}
957
958/* share between invoke and exec */
960{
961 /* initialize animation */
962 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
963 Scene *scene = oglrender->scene;
964 oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
965
966 oglrender->reports = op->reports;
967
969 size_t width, height;
970 int i;
971
973 &scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
974 oglrender->movie_writers.reserve(oglrender->totvideos);
975
976 for (i = 0; i < oglrender->totvideos; i++) {
977 Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
978 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
979 MovieWriter *writer = MOV_write_begin(scene->r.im_format.imtype,
980 scene_eval,
981 &scene->r,
982 oglrender->sizex,
983 oglrender->sizey,
984 oglrender->reports,
985 PRVRANGEON != 0,
986 suffix);
987 if (writer == nullptr) {
988 screen_opengl_render_end(oglrender);
989 MEM_delete(oglrender);
990 return false;
991 }
992 oglrender->movie_writers.append(writer);
993 }
994 }
995
996 G.is_rendering = true;
997 oglrender->cfrao = scene->r.cfra;
998 oglrender->nfra = PSFRA;
999 scene->r.cfra = PSFRA;
1000
1001 return true;
1002}
1003
1008
1009static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
1010{
1011 OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
1012 Scene *scene = &task_data->tmp_scene;
1013 RenderResult *rr = task_data->rr;
1014 const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1015 const int cfra = scene->r.cfra;
1016 bool ok;
1017 /* Don't attempt to write if we've got an error. */
1018 if (!oglrender->pool_ok) {
1020 std::scoped_lock lock(oglrender->task_mutex);
1021 oglrender->num_scheduled_frames--;
1022 oglrender->task_condition.notify_all();
1023 return;
1024 }
1025 /* Construct local thread0safe copy of reports structure which we can
1026 * safely pass to the underlying functions.
1027 */
1029 BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
1030 /* Do actual save logic here, depending on the file format.
1031 *
1032 * NOTE: We have to construct temporary scene with proper scene->r.cfra.
1033 * This is because underlying calls do not use r.cfra but use scene
1034 * for that.
1035 */
1036 if (is_movie) {
1038 rr,
1039 scene,
1040 &scene->r,
1041 oglrender->movie_writers.data(),
1042 oglrender->totvideos,
1043 PRVRANGEON != 0);
1044 }
1045 else {
1046 /* TODO(sergey): We can in theory save some CPU ticks here because we
1047 * calculate file name again here.
1048 */
1049 char filepath[FILE_MAX];
1050 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
1051 const path_templates::VariableMap template_variables =
1054 filepath,
1055 scene->r.pic,
1056 relbase,
1057 &template_variables,
1058 cfra,
1059 &scene->r.im_format,
1060 (scene->r.scemode & R_EXTENSION) != 0,
1061 true,
1062 nullptr);
1063
1064 if (!errors.is_empty()) {
1066 ok = false;
1067 }
1068 else {
1069 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
1070 ok = BKE_image_render_write(nullptr, rr, scene, true, filepath);
1071 }
1072
1073 if (!ok) {
1074 BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", filepath);
1075 }
1076 }
1077 if (reports.list.first != nullptr) {
1078 /* TODO: Should rather use new #BKE_reports_move_to_reports ? */
1079 std::unique_lock lock(oglrender->reports_mutex);
1080 for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
1081 report = report->next)
1082 {
1083 BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
1084 }
1085 }
1087 if (!ok) {
1088 oglrender->pool_ok = false;
1089 }
1091
1092 {
1093 std::unique_lock lock(oglrender->task_mutex);
1094 oglrender->num_scheduled_frames--;
1095 oglrender->task_condition.notify_all();
1096 }
1097}
1098
1099static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
1100{
1101 /* Isolate task so that multithreaded image operations don't cause this thread to start
1102 * writing another frame. If that happens we may reach the MAX_SCHEDULED_FRAMES limit,
1103 * and cause the render thread and writing threads to deadlock waiting for each other. */
1104 WriteTaskData *task_data = (WriteTaskData *)task_data_v;
1105 blender::threading::isolate_task([&] { write_result(pool, task_data); });
1106}
1107
1109{
1110 if (!oglrender->pool_ok) {
1112 return false;
1113 }
1114 Scene *scene = oglrender->scene;
1115 WriteTaskData *task_data = MEM_callocN<WriteTaskData>("write task data");
1116 task_data->rr = rr;
1117 memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
1118 {
1119 std::unique_lock lock(oglrender->task_mutex);
1120 oglrender->num_scheduled_frames++;
1121 if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
1122 oglrender->task_condition.wait(lock);
1123 }
1124 }
1125 BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
1126 return true;
1127}
1128
1130{
1131 Scene *scene = oglrender->scene;
1132 Depsgraph *depsgraph = oglrender->depsgraph;
1133 char filepath[FILE_MAX];
1134 bool ok = false;
1135 const bool view_context = (oglrender->v3d != nullptr);
1136 bool is_movie;
1137 RenderResult *rr;
1138
1139 /* go to next frame */
1140 if (scene->r.cfra < oglrender->nfra) {
1141 scene->r.cfra++;
1142 }
1143 while (scene->r.cfra < oglrender->nfra) {
1145 scene->r.cfra++;
1146 }
1147
1148 is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1149
1150 if (!is_movie) {
1151 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
1152 const path_templates::VariableMap template_variables =
1155 filepath,
1156 scene->r.pic,
1157 relbase,
1158 &template_variables,
1159 scene->r.cfra,
1160 &scene->r.im_format,
1161 (scene->r.scemode & R_EXTENSION) != 0,
1162 true,
1163 nullptr);
1164
1165 if (!errors.is_empty()) {
1166 std::unique_lock lock(oglrender->reports_mutex);
1167 BKE_report_path_template_errors(oglrender->reports, RPT_ERROR, scene->r.pic, errors);
1168 ok = false;
1169 }
1170 else if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(filepath)) {
1171 {
1172 std::unique_lock lock(oglrender->reports_mutex);
1173 BKE_reportf(oglrender->reports, RPT_INFO, "Skipping existing frame \"%s\"", filepath);
1174 }
1175 ok = true;
1176 goto finally;
1177 }
1178 }
1179
1180 if (!oglrender->wm_job && oglrender->win) {
1181 /* When doing blocking animation render without a job from a Python script, show time cursor so
1182 * Blender doesn't appear frozen. */
1183 WM_cursor_time(oglrender->win, scene->r.cfra);
1184 }
1185
1187
1188 if (view_context) {
1189 if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
1190 oglrender->v3d->scenelock)
1191 {
1192 /* since BKE_scene_graph_update_for_newframe() is used rather
1193 * then ED_update_for_newframe() the camera needs to be set */
1194 if (BKE_scene_camera_switch_update(scene)) {
1195 oglrender->v3d->camera = scene->camera;
1196 }
1197 }
1198 }
1199 else {
1201 }
1202
1203 if (oglrender->render_frames == nullptr ||
1204 BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA))
1205 {
1206 /* render into offscreen buffer */
1207 screen_opengl_render_apply(oglrender);
1208 }
1209
1210 /* save to disk */
1211 rr = RE_AcquireResultRead(oglrender->re);
1212 {
1214 RE_ReleaseResult(oglrender->re);
1215
1216 ok = schedule_write_result(oglrender, new_rr);
1217 }
1218
1219finally: /* Step the frame and bail early if needed */
1220
1221 /* go to next frame */
1222 oglrender->nfra += scene->r.frame_step;
1223
1224 /* stop at the end or on error */
1225 if (scene->r.cfra >= PEFRA || !ok) {
1226 return false;
1227 }
1228
1229 return true;
1230}
1231
1233 wmOperator *op,
1234 const wmEvent *event)
1235{
1236 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1237
1238 /* Still render completes immediately, but still modal to show some feedback
1239 * in case render initialization takes a while. */
1240 if (!oglrender->is_animation) {
1241 screen_opengl_render_apply(oglrender);
1242 screen_opengl_render_end(oglrender);
1243 MEM_delete(oglrender);
1244 return OPERATOR_FINISHED;
1245 }
1246
1247 /* no running blender, remove handler and pass through */
1248 if (0 == WM_jobs_test(CTX_wm_manager(C), oglrender->scene, WM_JOB_TYPE_RENDER)) {
1249 screen_opengl_render_end(oglrender);
1250 MEM_delete(oglrender);
1252 }
1253
1254 /* catch escape key. */
1256}
1257
1258static void opengl_render_startjob(void *customdata, wmJobWorkerStatus *worker_status)
1259{
1260 OGLRender *oglrender = static_cast<OGLRender *>(customdata);
1261 Scene *scene = oglrender->scene;
1262
1263 bool canceled = false;
1264 bool finished = false;
1265
1266 while (!finished && !canceled) {
1267 /* Render while blocking main thread, since we use 3D viewport resources. */
1269
1270 if (worker_status->stop || G.is_break) {
1271 canceled = true;
1272 }
1273 else {
1274 finished = !screen_opengl_render_anim_step(oglrender);
1275 worker_status->progress = float(scene->r.cfra - PSFRA + 1) / float(PEFRA - PSFRA + 1);
1276 worker_status->do_update = true;
1277 }
1278
1280
1281 if (worker_status->stop || G.is_break) {
1282 canceled = true;
1283 }
1284 }
1285
1286 if (canceled) {
1287 /* Cancel task pool writing images asynchronously. */
1288 oglrender->pool_ok = false;
1289 }
1290}
1291
1292static void opengl_render_freejob(void *customdata)
1293{
1294 /* End the render here, as the modal handler might be called with the window out of focus. */
1295 OGLRender *oglrender = static_cast<OGLRender *>(customdata);
1296 screen_opengl_render_end(oglrender);
1297}
1298
1300 wmOperator *op,
1301 const wmEvent *event)
1302{
1303 const bool anim = RNA_boolean_get(op->ptr, "animation");
1304
1305 if (!screen_opengl_render_init(C, op)) {
1306 return OPERATOR_CANCELLED;
1307 }
1308
1309 if (anim) {
1311 return OPERATOR_CANCELLED;
1312 }
1313 }
1314
1315 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1316 render_view_open(C, event->xy[0], event->xy[1], op->reports);
1317
1318 /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
1319 oglrender->win = CTX_wm_window(C);
1320
1321 /* Setup animation job. */
1322 if (anim) {
1323 G.is_break = false;
1324
1325 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
1327 oglrender->scene,
1328 "Viewport Render",
1331
1332 oglrender->wm_job = wm_job;
1333
1335 WM_jobs_timer(wm_job, 0.01f, NC_SCENE | ND_RENDER_RESULT, 0);
1336 WM_jobs_callbacks(wm_job, opengl_render_startjob, nullptr, nullptr, nullptr);
1337 WM_jobs_start(CTX_wm_manager(C), wm_job);
1338 }
1339
1341
1343}
1344
1345/* executes blocking render */
1347{
1348 if (!screen_opengl_render_init(C, op)) {
1349 return OPERATOR_CANCELLED;
1350 }
1351
1352 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1353
1354 if (!oglrender->is_animation) { /* same as invoke */
1355 screen_opengl_render_apply(oglrender);
1356 screen_opengl_render_end(oglrender);
1357 MEM_delete(oglrender);
1358
1359 return OPERATOR_FINISHED;
1360 }
1361
1362 bool ret = true;
1363
1365 return OPERATOR_CANCELLED;
1366 }
1367
1368 while (ret) {
1370 }
1371
1372 screen_opengl_render_end(oglrender);
1373 MEM_delete(oglrender);
1374
1375 return OPERATOR_FINISHED;
1376}
1377
1379 wmOperatorType * /*ot*/,
1380 PointerRNA *ptr)
1381{
1382 if (!RNA_boolean_get(ptr, "animation")) {
1383 return "";
1384 }
1385
1386 if (RNA_boolean_get(ptr, "render_keyed_only")) {
1387 return TIP_(
1388 "Render the viewport for the animation range of this scene, but only render keyframes of "
1389 "selected objects");
1390 }
1391
1392 return TIP_("Render the viewport for the animation range of this scene");
1393}
1394
1396{
1397 PropertyRNA *prop;
1398
1399 /* identifiers */
1400 ot->name = "Viewport Render";
1401 ot->description = "Take a snapshot of the active viewport";
1402 ot->idname = "RENDER_OT_opengl";
1403
1404 /* API callbacks. */
1405 ot->get_description = screen_opengl_render_get_description;
1407 ot->exec = screen_opengl_render_exec; /* blocking */
1410
1412
1413 prop = RNA_def_boolean(ot->srna,
1414 "animation",
1415 false,
1416 "Animation",
1417 "Render files from the animation range of this scene");
1419
1420 prop = RNA_def_boolean(ot->srna,
1421 "render_keyed_only",
1422 false,
1423 "Render Keyframes Only",
1424 "Render only those frames where selected objects have a key in their "
1425 "animation data. Only used when rendering animation");
1427
1428 prop = RNA_def_boolean(
1429 ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
1431 prop = RNA_def_boolean(
1432 ot->srna,
1433 "write_still",
1434 false,
1435 "Write Image",
1436 "Save the rendered image to the output path (used only when animation is disabled)");
1438 prop = RNA_def_boolean(ot->srna,
1439 "view_context",
1440 true,
1441 "View Context",
1442 "Use the current 3D view for rendering, else use scene settings");
1444}
Functions for backward compatibility with the legacy Action API.
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
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)
#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:94
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:162
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, unsigned char *rect, float *rectf, int width, int height)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
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)
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)
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_RET_STOP_RECURSION
@ IDWALK_RET_NOP
@ IDWALK_RECURSE
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
void BKE_report_path_template_errors(ReportList *reports, eReportType report_type, blender::StringRef path, blender::Span< blender::bke::path_templates::Error > errors)
blender::bke::path_templates::VariableMap BKE_build_template_variables_for_render_path(const RenderData *render_data)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_reports_free(ReportList *reports)
Definition report.cc:70
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:55
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2927
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2623
int BKE_scene_multiview_num_views_get(const RenderData *rd)
Definition scene.cc:2952
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:3000
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3166
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2267
bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
Definition scene.cc:2983
void BKE_scene_multiview_videos_dimensions_get(const RenderData *rd, size_t width, size_t height, size_t *r_width, size_t *r_height)
Definition scene.cc:3207
int BKE_scene_multiview_num_videos_get(const RenderData *rd)
Definition scene.cc:3227
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2697
#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:373
#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
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
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:546
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:531
TaskPool * BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority)
Definition task_pool.cc:512
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:480
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:517
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:522
#define UNUSED_FUNCTION(x)
#define TIP_(msgid)
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_IP
@ ID_GR
@ ID_SPK
@ ID_MB
@ ID_LT
@ ID_OB
@ ID_GP
@ ID_PA
@ ID_PT
@ ID_PC
@ IMA_SHOW_STEREO
@ IMA_TYPE_R_RESULT
eDrawType
@ OB_SOLID
Object is a sort of wrapper for general info.
#define R_STAMP_ALL
#define PSFRA
#define V3D_CAMERA_SCENE(scene, v3d)
eImageFormatDepth
@ R_IMF_CHAN_DEPTH_32
@ R_NO_OVERWRITE
@ R_STAMP_DRAW
@ R_MULTIVIEW
@ R_EXTENSION
@ R_ADDSKY
@ R_ALPHAPREMUL
#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)
eGPUBackendType GPU_backend_get_type()
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat 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:87
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
@ GPU_RGBA16F
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.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
#define C
Definition RandGen.cpp:29
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1728
@ WM_JOB_EXCL_RENDER
Definition WM_api.hh:1715
@ WM_JOB_PROGRESS
Definition WM_api.hh:1716
@ WM_JOB_PRIORITY
Definition WM_api.hh:1710
#define ND_RENDER_RESULT
Definition WM_types.hh:443
#define NC_SCENE
Definition WM_types.hh:375
ReportList * reports
Definition WM_types.hh:1025
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
#define offsetof(t, d)
#define printf(...)
#define MEM_SAFE_FREE(v)
#define GS(a)
void RE_SetOverrideCamera(Render *re, Object *cam_ob)
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)
MovieWriter * MOV_write_begin(const char imtype, const Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix)
void MOV_write_end(MovieWriter *writer)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
void render_new_render_data(Main *bmain, Depsgraph *depsgraph, Scene *scene, int rectx, int recty, int preview_render_size, int for_render, RenderData *r_context)
Definition render.cc:206
ImBuf * render_give_ibuf(const RenderData *context, float timeline_frame, int chanshown)
Definition render.cc:2001
void isolate_task(const Function &function)
Definition BLI_task.hh:248
std::mutex Mutex
Definition BLI_mutex.hh:47
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:404
char name[66]
Definition DNA_ID.h:415
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
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 OGLRender::@172170245213032040145015203167207346226106211161 seq_data
struct ImageFormatData im_format
char pic[1024]
Scene * current_scene
ListBase views
struct ImBuf * ibuf
Definition RE_pipeline.h:44
struct RenderView * prev
Definition RE_pipeline.h:38
struct RenderView * next
Definition RE_pipeline.h:38
char name[64]
Definition RE_pipeline.h:39
struct Report * next
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:754
int xy[2]
Definition WM_types.hh:758
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:4226
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_jobs_timer(wmJob *wm_job, double time_step, uint note, uint endnote)
Definition wm_jobs.cc:353
void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
Definition wm_jobs.cc:456
void WM_jobs_kill_type(wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:598
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:190
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:365
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:589
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:224
void WM_job_main_thread_lock_acquire(wmJob *wm_job)
Definition wm_jobs.cc:140
void WM_jobs_customdata_set(wmJob *wm_job, void *customdata, void(*free)(void *customdata))
Definition wm_jobs.cc:337
void WM_job_main_thread_lock_release(wmJob *wm_job)
Definition wm_jobs.cc:145
void wmOrtho2(float x1, float x2, float y1, float y2)