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 true,
353 err_out);
354
355 /* for stamp only */
356 if (oglrender->rv3d->persp == RV3D_CAMOB && v3d->camera) {
357 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
358 }
359 }
360 else {
362 scene,
363 nullptr,
364 OB_SOLID,
365 scene->camera,
366 sizex,
367 sizey,
370 alpha_mode,
371 viewname,
372 oglrender->ofs,
373 oglrender->viewport,
374 err_out);
375 camera = scene->camera;
376 }
377
378 if (ibuf_view) {
379 ibuf_result = ibuf_view;
380 }
381 else {
382 fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
383 }
384 }
385
386 if (ibuf_result != nullptr) {
387 if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
388 float *rectf = nullptr;
389 uchar *rect = nullptr;
390 if (ibuf_result->float_buffer.data) {
391 rectf = ibuf_result->float_buffer.data;
392 }
393 else {
394 rect = ibuf_result->byte_buffer.data;
395 }
396 BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty);
397 }
398 RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
399 IMB_freeImBuf(ibuf_result);
400 }
401
402 /* Perform render step between renders to allow
403 * flushing of freed GPUBackend resources. */
406 GPU_flush();
407 }
408 GPU_render_step(true);
410}
411
413{
414 Scene *scene = oglrender->scene;
415 RenderResult *rr;
416 bool ok;
417 char filepath[FILE_MAX];
418
419 rr = RE_AcquireResultRead(oglrender->re);
420
421 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
422 const path_templates::VariableMap template_variables =
425 filepath,
426 scene->r.pic,
427 relbase,
428 &template_variables,
429 scene->r.cfra,
430 &scene->r.im_format,
431 (scene->r.scemode & R_EXTENSION) != 0,
432 false,
433 nullptr);
434
435 if (!errors.is_empty()) {
436 std::unique_lock lock(oglrender->reports_mutex);
437 BKE_report_path_template_errors(oglrender->reports, RPT_ERROR, scene->r.pic, errors);
438 ok = false;
439 }
440 else {
441 /* write images as individual images or stereo */
442 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
443 ok = BKE_image_render_write(oglrender->reports, rr, scene, false, filepath);
444
445 RE_ReleaseResultImage(oglrender->re);
446 }
447
448 if (ok) {
449 printf("OpenGL Render written to '%s'\n", filepath);
450 }
451 else {
452 printf("OpenGL Render failed to write '%s'\n", filepath);
453 }
454}
455
456static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
457{
458 /* `d = s + (1-alpha_s)d` */
459 float mul;
460
461 mul = 1.0f - source[3];
462
463 dest[0] = (mul * dest[0]) + source[0];
464 dest[1] = (mul * dest[1]) + source[1];
465 dest[2] = (mul * dest[2]) + source[2];
466 dest[3] = (mul * dest[3]) + source[3];
467}
468
470{
471 RenderResult *rr;
472 RenderView *rv;
473 int view_id;
474 ImBuf *ibuf;
475 void *lock;
476
477 if (oglrender->is_sequencer) {
478 Scene *scene = oglrender->scene;
479
481 SpaceSeq *sseq = oglrender->sseq;
482 int chanshown = sseq ? sseq->chanshown : 0;
483
485 oglrender->depsgraph,
486 scene,
487 oglrender->sizex,
488 oglrender->sizey,
490 false,
491 &context);
492
493 for (view_id = 0; view_id < oglrender->views_len; view_id++) {
494 context.view_id = view_id;
495 context.gpu_offscreen = oglrender->ofs;
496 context.gpu_viewport = oglrender->viewport;
498 &context, scene->r.cfra, chanshown);
499 }
500 }
501
502 rr = RE_AcquireResultRead(oglrender->re);
503 for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv; rv = rv->next, view_id++)
504 {
505 BLI_assert(view_id < oglrender->views_len);
506 RE_SetActiveRenderView(oglrender->re, rv->name);
507 oglrender->view_id = view_id;
508 /* render composite */
509 screen_opengl_render_doit(oglrender, rr);
510 }
511
512 RE_ReleaseResult(oglrender->re);
513
514 ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
515 if (ibuf) {
517 }
518 BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
520
521 if (oglrender->write_still) {
523 }
524}
525
526static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
527{
528 if (adt == nullptr || adt->action == nullptr) {
529 return;
530 }
531
532 Scene *scene = oglrender->scene;
533 int frame_start = PSFRA;
534 int frame_end = PEFRA;
535
537 if (fcu->driver != nullptr || fcu->fpt != nullptr) {
538 /* Drivers have values for any point in time, so to get "the keyed frames" they are
539 * useless. Same for baked FCurves, they also have keys for every frame, which is not
540 * useful for rendering the keyed subset of the frames. */
541 continue;
542 }
543
544 bool found = false; /* Not interesting, we just want a starting point for the for-loop. */
546 fcu->bezt, frame_start, fcu->totvert, &found);
547 for (; key_index < fcu->totvert; key_index++) {
548 BezTriple *bezt = &fcu->bezt[key_index];
549 /* The frame range to render uses integer frame numbers, and the frame
550 * step is also an integer, so we always render on the frame. */
551 int frame_nr = round_fl_to_int(bezt->vec[1][0]);
552
553 /* (frame_nr < frame_start) cannot happen because of the binary search above. */
554 BLI_assert(frame_nr >= frame_start);
555 if (frame_nr > frame_end) {
556 break;
557 }
558 BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
559 }
560 }
561}
562
564 const bGPdata *gp)
565{
566 if (gp == nullptr) {
567 return;
568 }
569
570 Scene *scene = oglrender->scene;
571 int frame_start = PSFRA;
572 int frame_end = PEFRA;
573
574 LISTBASE_FOREACH (const bGPDlayer *, gp_layer, &gp->layers) {
575 LISTBASE_FOREACH (const bGPDframe *, gp_frame, &gp_layer->frames) {
576 if (gp_frame->framenum < frame_start || gp_frame->framenum > frame_end) {
577 continue;
578 }
579 BLI_BITMAP_ENABLE(oglrender->render_frames, gp_frame->framenum - frame_start);
580 }
581 }
582}
583
585{
586 ID **id_p = cb_data->id_pointer;
587 if (*id_p == nullptr) {
588 return IDWALK_RET_NOP;
589 }
590 ID *id = *id_p;
591
592 ID *self_id = cb_data->self_id;
593 const LibraryForeachIDCallbackFlag cb_flag = cb_data->cb_flag;
594 if (cb_flag == IDWALK_CB_LOOPBACK || id == self_id) {
595 /* IDs may end up referencing themselves one way or the other, and those
596 * (the self_id ones) have always already been processed. */
598 }
599
600 OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
601
602 /* Whitelist of datablocks to follow pointers into. */
603 const ID_Type id_type = GS(id->name);
604 switch (id_type) {
605 /* Whitelist: */
606 case ID_ME: /* Mesh */
607 case ID_CU_LEGACY: /* Curve */
608 case ID_MB: /* MetaBall */
609 case ID_MA: /* Material */
610 case ID_TE: /* Tex (Texture) */
611 case ID_IM: /* Image */
612 case ID_LT: /* Lattice */
613 case ID_LA: /* Light */
614 case ID_CA: /* Camera */
615 case ID_KE: /* Key (shape key) */
616 case ID_VF: /* VFont (Vector Font) */
617 case ID_TXT: /* Text */
618 case ID_SPK: /* Speaker */
619 case ID_SO: /* Sound */
620 case ID_AR: /* bArmature */
621 case ID_NT: /* bNodeTree */
622 case ID_PA: /* ParticleSettings */
623 case ID_MC: /* MovieClip */
624 case ID_MSK: /* Mask */
625 case ID_LP: /* LightProbe */
626 case ID_CV: /* Curves */
627 case ID_PT: /* PointCloud */
628 case ID_VO: /* Volume */
629 break;
630
631 /* Blacklist: */
632 case ID_SCE: /* Scene */
633 case ID_LI: /* Library */
634 case ID_OB: /* Object */
635 case ID_IP: /* Ipo (depreciated, replaced by FCurves) */
636 case ID_WO: /* World */
637 case ID_SCR: /* Screen */
638 case ID_GR: /* Group */
639 case ID_AC: /* bAction */
640 case ID_BR: /* Brush */
641 case ID_WM: /* WindowManager */
642 case ID_LS: /* FreestyleLineStyle */
643 case ID_PAL: /* Palette */
644 case ID_PC: /* PaintCurve */
645 case ID_CF: /* CacheFile */
646 case ID_WS: /* WorkSpace */
647 /* Only follow pointers to specific datablocks, to avoid ending up in
648 * unrelated datablocks and exploding the number of blocks we follow. If the
649 * frames of the animation of certain objects should be taken into account,
650 * they should have been selected by the user. */
652
653 /* Special cases: */
654 case ID_GD_LEGACY: /* bGPdata, (Grease Pencil) */
655 /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation
656 * system that requires specific handling here. */
658 break;
659 case ID_GP:
660 /* TODO: gather frames. */
661 break;
662 }
663
665 gather_frames_to_render_for_adt(oglrender, adt);
666
667 return IDWALK_RET_NOP;
668}
669
678{
679 Scene *scene = oglrender->scene;
680 int frame_start = PSFRA;
681 int frame_end = PEFRA;
682
683 /* Will be freed in screen_opengl_render_end(). */
684 oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
685 "OGLRender::render_frames");
686
687 /* The first frame should always be rendered, otherwise there is nothing to write to file. */
688 BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
689
690 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
691 ID *id = &ob->id;
692
693 /* Gather the frames from the object animation data. */
695 gather_frames_to_render_for_adt(oglrender, adt);
696
697 /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
699 nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
700 }
702}
703
705{
706 /* new render clears all callbacks */
708 wmWindow *win = CTX_wm_window(C);
709 WorkSpace *workspace = CTX_wm_workspace(C);
710
711 Scene *scene = CTX_data_scene(C);
712 ScrArea *prev_area = CTX_wm_area(C);
713 ARegion *prev_region = CTX_wm_region(C);
714 GPUOffScreen *ofs;
715 OGLRender *oglrender;
716 int sizex, sizey;
717 bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
718 const bool is_animation = RNA_boolean_get(op->ptr, "animation");
719 const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
720 const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
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,
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 oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
966
967 oglrender->reports = op->reports;
968
970 size_t width, height;
971 int i;
972
974 &scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
975 oglrender->movie_writers.reserve(oglrender->totvideos);
976
977 for (i = 0; i < oglrender->totvideos; i++) {
978 Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
979 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
980 MovieWriter *writer = MOV_write_begin(scene->r.im_format.imtype,
981 scene_eval,
982 &scene->r,
983 oglrender->sizex,
984 oglrender->sizey,
985 oglrender->reports,
986 PRVRANGEON != 0,
987 suffix);
988 if (writer == nullptr) {
989 screen_opengl_render_end(oglrender);
990 MEM_delete(oglrender);
991 return false;
992 }
993 oglrender->movie_writers.append(writer);
994 }
995 }
996
997 G.is_rendering = true;
998 oglrender->cfrao = scene->r.cfra;
999 oglrender->nfra = PSFRA;
1000 scene->r.cfra = PSFRA;
1001
1002 return true;
1003}
1004
1009
1010static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
1011{
1012 OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
1013 Scene *scene = &task_data->tmp_scene;
1014 RenderResult *rr = task_data->rr;
1015 const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1016 const int cfra = scene->r.cfra;
1017 bool ok;
1018 /* Don't attempt to write if we've got an error. */
1019 if (!oglrender->pool_ok) {
1021 std::scoped_lock lock(oglrender->task_mutex);
1022 oglrender->num_scheduled_frames--;
1023 oglrender->task_condition.notify_all();
1024 return;
1025 }
1026 /* Construct local thread0safe copy of reports structure which we can
1027 * safely pass to the underlying functions.
1028 */
1030 BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
1031 /* Do actual save logic here, depending on the file format.
1032 *
1033 * NOTE: We have to construct temporary scene with proper scene->r.cfra.
1034 * This is because underlying calls do not use r.cfra but use scene
1035 * for that.
1036 */
1037 if (is_movie) {
1039 rr,
1040 scene,
1041 &scene->r,
1042 oglrender->movie_writers.data(),
1043 oglrender->totvideos,
1044 PRVRANGEON != 0);
1045 }
1046 else {
1047 /* TODO(sergey): We can in theory save some CPU ticks here because we
1048 * calculate file name again here.
1049 */
1050 char filepath[FILE_MAX];
1051 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
1052 const path_templates::VariableMap template_variables =
1055 filepath,
1056 scene->r.pic,
1057 relbase,
1058 &template_variables,
1059 cfra,
1060 &scene->r.im_format,
1061 (scene->r.scemode & R_EXTENSION) != 0,
1062 true,
1063 nullptr);
1064
1065 if (!errors.is_empty()) {
1067 ok = false;
1068 }
1069 else {
1070 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
1071 ok = BKE_image_render_write(nullptr, rr, scene, true, filepath);
1072 }
1073
1074 if (!ok) {
1075 BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", filepath);
1076 }
1077 }
1078 if (reports.list.first != nullptr) {
1079 /* TODO: Should rather use new #BKE_reports_move_to_reports ? */
1080 std::unique_lock lock(oglrender->reports_mutex);
1081 for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
1082 report = report->next)
1083 {
1084 BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
1085 }
1086 }
1088 if (!ok) {
1089 oglrender->pool_ok = false;
1090 }
1092
1093 {
1094 std::unique_lock lock(oglrender->task_mutex);
1095 oglrender->num_scheduled_frames--;
1096 oglrender->task_condition.notify_all();
1097 }
1098}
1099
1100static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
1101{
1102 /* Isolate task so that multithreaded image operations don't cause this thread to start
1103 * writing another frame. If that happens we may reach the MAX_SCHEDULED_FRAMES limit,
1104 * and cause the render thread and writing threads to deadlock waiting for each other. */
1105 WriteTaskData *task_data = (WriteTaskData *)task_data_v;
1106 blender::threading::isolate_task([&] { write_result(pool, task_data); });
1107}
1108
1110{
1111 if (!oglrender->pool_ok) {
1113 return false;
1114 }
1115 Scene *scene = oglrender->scene;
1116 WriteTaskData *task_data = MEM_callocN<WriteTaskData>("write task data");
1117 task_data->rr = rr;
1118 memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
1119 {
1120 std::unique_lock lock(oglrender->task_mutex);
1121 oglrender->num_scheduled_frames++;
1122 if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
1123 oglrender->task_condition.wait(lock);
1124 }
1125 }
1126 BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
1127 return true;
1128}
1129
1131{
1132 Scene *scene = oglrender->scene;
1133 Depsgraph *depsgraph = oglrender->depsgraph;
1134 char filepath[FILE_MAX];
1135 bool ok = false;
1136 const bool view_context = (oglrender->v3d != nullptr);
1137 bool is_movie;
1138 RenderResult *rr;
1139
1140 /* go to next frame */
1141 if (scene->r.cfra < oglrender->nfra) {
1142 scene->r.cfra++;
1143 }
1144 while (scene->r.cfra < oglrender->nfra) {
1146 scene->r.cfra++;
1147 }
1148
1149 is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1150
1151 if (!is_movie) {
1152 const char *relbase = BKE_main_blendfile_path(oglrender->bmain);
1153 const path_templates::VariableMap template_variables =
1156 filepath,
1157 scene->r.pic,
1158 relbase,
1159 &template_variables,
1160 scene->r.cfra,
1161 &scene->r.im_format,
1162 (scene->r.scemode & R_EXTENSION) != 0,
1163 true,
1164 nullptr);
1165
1166 if (!errors.is_empty()) {
1167 std::unique_lock lock(oglrender->reports_mutex);
1168 BKE_report_path_template_errors(oglrender->reports, RPT_ERROR, scene->r.pic, errors);
1169 ok = false;
1170 }
1171 else if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(filepath)) {
1172 {
1173 std::unique_lock lock(oglrender->reports_mutex);
1174 BKE_reportf(oglrender->reports, RPT_INFO, "Skipping existing frame \"%s\"", filepath);
1175 }
1176 ok = true;
1177 goto finally;
1178 }
1179 }
1180
1181 if (!oglrender->wm_job && oglrender->win) {
1182 /* When doing blocking animation render without a job from a Python script, show time cursor so
1183 * Blender doesn't appear frozen. */
1184 WM_cursor_time(oglrender->win, scene->r.cfra);
1185 }
1186
1188
1189 if (view_context) {
1190 if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
1191 oglrender->v3d->scenelock)
1192 {
1193 /* since BKE_scene_graph_update_for_newframe() is used rather
1194 * then ED_update_for_newframe() the camera needs to be set */
1195 if (BKE_scene_camera_switch_update(scene)) {
1196 oglrender->v3d->camera = scene->camera;
1197 }
1198 }
1199 }
1200 else {
1202 }
1203
1204 if (oglrender->render_frames == nullptr ||
1205 BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA))
1206 {
1207 /* render into offscreen buffer */
1208 screen_opengl_render_apply(oglrender);
1209 }
1210
1211 /* save to disk */
1212 rr = RE_AcquireResultRead(oglrender->re);
1213 {
1215 RE_ReleaseResult(oglrender->re);
1216
1217 ok = schedule_write_result(oglrender, new_rr);
1218 }
1219
1220finally: /* Step the frame and bail early if needed */
1221
1222 /* go to next frame */
1223 oglrender->nfra += scene->r.frame_step;
1224
1225 /* stop at the end or on error */
1226 if (scene->r.cfra >= PEFRA || !ok) {
1227 return false;
1228 }
1229
1230 return true;
1231}
1232
1234 wmOperator *op,
1235 const wmEvent *event)
1236{
1237 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1238
1239 /* Still render completes immediately, but still modal to show some feedback
1240 * in case render initialization takes a while. */
1241 if (!oglrender->is_animation) {
1242 screen_opengl_render_apply(oglrender);
1243 screen_opengl_render_end(oglrender);
1244 MEM_delete(oglrender);
1245 return OPERATOR_FINISHED;
1246 }
1247
1248 /* no running blender, remove handler and pass through */
1249 if (0 == WM_jobs_test(CTX_wm_manager(C), oglrender->scene, WM_JOB_TYPE_RENDER)) {
1250 screen_opengl_render_end(oglrender);
1251 MEM_delete(oglrender);
1253 }
1254
1255 /* catch escape key. */
1257}
1258
1259static void opengl_render_startjob(void *customdata, wmJobWorkerStatus *worker_status)
1260{
1261 OGLRender *oglrender = static_cast<OGLRender *>(customdata);
1262 Scene *scene = oglrender->scene;
1263
1264 bool canceled = false;
1265 bool finished = false;
1266
1267 while (!finished && !canceled) {
1268 /* Render while blocking main thread, since we use 3D viewport resources. */
1270
1271 if (worker_status->stop || G.is_break) {
1272 canceled = true;
1273 }
1274 else {
1275 finished = !screen_opengl_render_anim_step(oglrender);
1276 worker_status->progress = float(scene->r.cfra - PSFRA + 1) / float(PEFRA - PSFRA + 1);
1277 worker_status->do_update = true;
1278 }
1279
1281
1282 if (worker_status->stop || G.is_break) {
1283 canceled = true;
1284 }
1285 }
1286
1287 if (canceled) {
1288 /* Cancel task pool writing images asynchronously. */
1289 oglrender->pool_ok = false;
1290 }
1291}
1292
1293static void opengl_render_freejob(void *customdata)
1294{
1295 /* End the render here, as the modal handler might be called with the window out of focus. */
1296 OGLRender *oglrender = static_cast<OGLRender *>(customdata);
1297 screen_opengl_render_end(oglrender);
1298}
1299
1301 wmOperator *op,
1302 const wmEvent *event)
1303{
1304 const bool anim = RNA_boolean_get(op->ptr, "animation");
1305
1306 if (!screen_opengl_render_init(C, op)) {
1307 return OPERATOR_CANCELLED;
1308 }
1309
1310 if (anim) {
1312 return OPERATOR_CANCELLED;
1313 }
1314 }
1315
1316 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1317 render_view_open(C, event->xy[0], event->xy[1], op->reports);
1318
1319 /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
1320 oglrender->win = CTX_wm_window(C);
1321
1322 /* Setup animation job. */
1323 if (anim) {
1324 G.is_break = false;
1325
1326 wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
1328 oglrender->scene,
1329 "Viewport Render",
1332
1333 oglrender->wm_job = wm_job;
1334
1336 WM_jobs_timer(wm_job, 0.01f, NC_SCENE | ND_RENDER_RESULT, 0);
1337 WM_jobs_callbacks(wm_job, opengl_render_startjob, nullptr, nullptr, nullptr);
1338 WM_jobs_start(CTX_wm_manager(C), wm_job);
1339 }
1340
1342
1344}
1345
1346/* executes blocking render */
1348{
1349 if (!screen_opengl_render_init(C, op)) {
1350 return OPERATOR_CANCELLED;
1351 }
1352
1353 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1354
1355 if (!oglrender->is_animation) { /* same as invoke */
1356 screen_opengl_render_apply(oglrender);
1357 screen_opengl_render_end(oglrender);
1358 MEM_delete(oglrender);
1359
1360 return OPERATOR_FINISHED;
1361 }
1362
1363 bool ret = true;
1364
1366 return OPERATOR_CANCELLED;
1367 }
1368
1369 while (ret) {
1371 }
1372
1373 screen_opengl_render_end(oglrender);
1374 MEM_delete(oglrender);
1375
1376 return OPERATOR_FINISHED;
1377}
1378
1380 wmOperatorType * /*ot*/,
1381 PointerRNA *ptr)
1382{
1383 if (!RNA_boolean_get(ptr, "animation")) {
1384 return "";
1385 }
1386
1387 if (RNA_boolean_get(ptr, "render_keyed_only")) {
1388 return TIP_(
1389 "Render the viewport for the animation range of this scene, but only render keyframes of "
1390 "selected objects");
1391 }
1392
1393 return TIP_("Render the viewport for the animation range of this scene");
1394}
1395
1397{
1398 PropertyRNA *prop;
1399
1400 /* identifiers */
1401 ot->name = "Viewport Render";
1402 ot->description = "Take a snapshot of the active viewport";
1403 ot->idname = "RENDER_OT_opengl";
1404
1405 /* API callbacks. */
1406 ot->get_description = screen_opengl_render_get_description;
1408 ot->exec = screen_opengl_render_exec; /* blocking */
1411
1413
1414 prop = RNA_def_boolean(ot->srna,
1415 "animation",
1416 false,
1417 "Animation",
1418 "Render files from the animation range of this scene");
1420
1421 prop = RNA_def_boolean(ot->srna,
1422 "render_keyed_only",
1423 false,
1424 "Render Keyframes Only",
1425 "Render only those frames where selected objects have a key in their "
1426 "animation data. Only used when rendering animation");
1428
1429 prop = RNA_def_boolean(
1430 ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
1432 prop = RNA_def_boolean(
1433 ot->srna,
1434 "write_still",
1435 false,
1436 "Write Image",
1437 "Save the rendered image to the output path (used only when animation is disabled)");
1439 prop = RNA_def_boolean(ot->srna,
1440 "view_context",
1441 true,
1442 "View Context",
1443 "Use the current 3D view for rendering, else use scene settings");
1445}
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:877
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
@ R_STAMP_DRAW
#define PSFRA
#define V3D_CAMERA_SCENE(scene, v3d)
@ R_ADDSKY
@ R_ALPHAPREMUL
eImageFormatDepth
@ R_IMF_CHAN_DEPTH_32
@ R_NO_OVERWRITE
@ 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, bool use_camera_view_bounds, 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:205
ImBuf * render_give_ibuf(const RenderData *context, float timeline_frame, int chanshown)
Definition render.cc:2002
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
struct OGLRender::@270161071014062000127067061266331015136162354030 seq_data
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: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:4227
wmOperatorType * ot
Definition wm_files.cc:4226
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)