Blender V4.3
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
9#include <cmath>
10#include <cstddef>
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_bitmap.h"
16#include "BLI_blenlib.h"
18#include "BLI_task.h"
19#include "BLI_task.hh"
20#include "BLI_threads.h"
21#include "BLI_utildefines.h"
22
23#include "DNA_action_types.h"
24#include "DNA_anim_types.h"
25#include "DNA_curve_types.h"
27#include "DNA_object_types.h"
28#include "DNA_scene_types.h"
29
30#include "BKE_anim_data.hh"
31#include "BKE_camera.h"
32#include "BKE_context.hh"
33#include "BKE_customdata.hh"
34#include "BKE_fcurve.hh"
35#include "BKE_global.hh"
36#include "BKE_image.hh"
37#include "BKE_image_format.hh"
38#include "BKE_image_save.hh"
39#include "BKE_lib_query.hh"
40#include "BKE_main.hh"
41#include "BKE_report.hh"
42#include "BKE_scene.hh"
43#include "BKE_writemovie.hh"
44
45#include "DEG_depsgraph.hh"
47
48#include "DRW_engine.hh"
49
50#include "WM_api.hh"
51#include "WM_types.hh"
52
53#include "ED_gpencil_legacy.hh"
54#include "ED_screen.hh"
55#include "ED_view3d.hh"
57
58#include "IMB_imbuf.hh"
59#include "IMB_imbuf_types.hh"
60
61#include "RE_pipeline.h"
62
63#include "BLT_translation.hh"
64
65#include "RNA_access.hh"
66#include "RNA_define.hh"
67
68#include "SEQ_render.hh"
69
70#include "ANIM_action_legacy.hh"
71
72#include "GPU_framebuffer.hh"
73#include "GPU_matrix.hh"
74#include "GPU_viewport.hh"
75
76#include "render_intern.hh"
77
78/* Define this to get timing information. */
79// #define DEBUG_TIME
80
81#ifdef DEBUG_TIME
82# include "BLI_time.h"
83#endif
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 {
95 Depsgraph *depsgraph;
96
100
103
104 int views_len; /* multi-view views */
105
108 struct {
111
114
118
120
124
126
127 /* For only rendering frames that have a key in animation data. */
129
130 /* quick lookup */
132
133 /* wm vars for timer and progress cursor */
136
139
141
145
151
152#ifdef DEBUG_TIME
153 double time_start;
154#endif
155};
156
158{
159 View3D *v3d = oglrender->v3d;
160 RegionView3D *rv3d = oglrender->rv3d;
161 RenderData *rd = &oglrender->scene->r;
162
163 if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
164 return false;
165 }
166
167 return (rd->scemode & R_MULTIVIEW) &&
168 ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
169}
170
172{
173 RenderResult *rr;
174 RenderView *rv;
175 SceneRenderView *srv;
176 bool is_multiview;
177 Object *camera;
178 View3D *v3d = oglrender->v3d;
179
180 RenderData *rd = &oglrender->scene->r;
181
182 rr = RE_AcquireResultWrite(oglrender->re);
183
184 is_multiview = screen_opengl_is_multiview(oglrender);
185
186 if (!is_multiview) {
187 /* we only have one view when multiview is off */
188 rv = static_cast<RenderView *>(rr->views.first);
189
190 if (rv == nullptr) {
191 rv = MEM_cnew<RenderView>("new opengl render view");
192 BLI_addtail(&rr->views, rv);
193 }
194
195 while (rv->next) {
196 RenderView *rv_del = rv->next;
197 BLI_remlink(&rr->views, rv_del);
198
199 IMB_freeImBuf(rv_del->ibuf);
200
201 MEM_freeN(rv_del);
202 }
203 }
204 else {
205 if (v3d) {
206 RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
207 }
208
209 /* remove all the views that are not needed */
210 rv = static_cast<RenderView *>(rr->views.last);
211 while (rv) {
212 srv = static_cast<SceneRenderView *>(
215 rv = rv->prev;
216 }
217 else {
218 RenderView *rv_del = rv;
219 rv = rv_del->prev;
220
221 BLI_remlink(&rr->views, rv_del);
222
223 IMB_freeImBuf(rv_del->ibuf);
224
225 MEM_freeN(rv_del);
226 }
227 }
228
229 /* create all the views that are needed */
230 LISTBASE_FOREACH (SceneRenderView *, srv, &rd->views) {
231 if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
232 continue;
233 }
234
235 rv = static_cast<RenderView *>(
236 BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
237
238 if (rv == nullptr) {
239 rv = MEM_cnew<RenderView>("new opengl render view");
240 STRNCPY(rv->name, srv->name);
241 BLI_addtail(&rr->views, rv);
242 }
243 }
244 }
245
246 if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) {
247 oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
248 }
249
250 /* will only work for non multiview correctly */
251 if (v3d) {
252 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
253 BKE_render_result_stamp_info(oglrender->scene, camera, rr, false);
254 }
255 else {
256 BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false);
257 }
258
259 RE_ReleaseResult(oglrender->re);
260}
261
262static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr)
263{
264 Scene *scene = oglrender->scene;
265 Object *camera = nullptr;
266 int sizex = oglrender->sizex;
267 int sizey = oglrender->sizey;
268 ImBuf *ibuf_result = nullptr;
269
270 if (oglrender->is_sequencer) {
271 SpaceSeq *sseq = oglrender->sseq;
272 bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
273
274 /* use pre-calculated ImBuf (avoids deadlock), see: */
275 ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
276
277 if (ibuf) {
278 ibuf_result = IMB_dupImBuf(ibuf);
279 IMB_freeImBuf(ibuf);
280 /* OpenGL render is considered to be preview and should be
281 * as fast as possible. So currently we're making sure sequencer
282 * result is always byte to simplify color management pipeline.
283 *
284 * TODO(sergey): In the case of output to float container (EXR)
285 * it actually makes sense to keep float buffer instead.
286 */
287 if (ibuf_result->float_buffer.data != nullptr) {
288 IMB_rect_from_float(ibuf_result);
289 imb_freerectfloatImBuf(ibuf_result);
290 }
291 BLI_assert((sizex == ibuf->x) && (sizey == ibuf->y));
292 }
293 else if (gpd) {
294 /* If there are no strips, Grease Pencil still needs a buffer to draw on */
295 ibuf_result = IMB_allocImBuf(sizex, sizey, 32, IB_rect);
296 }
297
298 if (gpd) {
299 int i;
300 uchar *gp_rect;
301 uchar *render_rect = ibuf_result->byte_buffer.data;
302
304 GPU_offscreen_bind(oglrender->ofs, true);
305
306 GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
307 GPU_clear_depth(1.0f);
308
310 wmOrtho2(0, scene->r.xsch, 0, scene->r.ysch);
311 GPU_matrix_translate_2f(scene->r.xsch / 2, scene->r.ysch / 2);
312
314 ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
315 G.f &= ~G_FLAG_RENDER_VIEWPORT;
316
317 gp_rect = static_cast<uchar *>(
318 MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
319 GPU_offscreen_read_color(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
320
321 for (i = 0; i < sizex * sizey * 4; i += 4) {
322 blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
323 }
324 GPU_offscreen_unbind(oglrender->ofs, true);
326
327 MEM_freeN(gp_rect);
328 }
329 }
330 else {
331 /* shouldn't suddenly give errors mid-render but possible */
333 char err_out[256] = "unknown";
334 ImBuf *ibuf_view;
335 bool draw_sky = (scene->r.alphamode == R_ADDSKY);
336 const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
337 const char *viewname = RE_GetActiveRenderView(oglrender->re);
338 View3D *v3d = oglrender->v3d;
339
340 if (v3d != nullptr) {
341 ARegion *region = oglrender->region;
343 scene,
344 static_cast<eDrawType>(v3d->shading.type),
345 v3d,
346 region,
347 sizex,
348 sizey,
350 alpha_mode,
351 viewname,
352 true,
353 oglrender->ofs,
354 oglrender->viewport,
355 err_out);
356
357 /* for stamp only */
358 if (oglrender->rv3d->persp == RV3D_CAMOB && v3d->camera) {
359 camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
360 }
361 }
362 else {
364 scene,
365 nullptr,
366 OB_SOLID,
367 scene->camera,
368 sizex,
369 sizey,
372 alpha_mode,
373 viewname,
374 oglrender->ofs,
375 oglrender->viewport,
376 err_out);
377 camera = scene->camera;
378 }
379
380 if (ibuf_view) {
381 ibuf_result = ibuf_view;
382 }
383 else {
384 fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
385 }
386 }
387
388 if (ibuf_result != nullptr) {
389 if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
390 float *rectf = nullptr;
391 uchar *rect = nullptr;
392 if (ibuf_result->float_buffer.data) {
393 rectf = ibuf_result->float_buffer.data;
394 }
395 else {
396 rect = ibuf_result->byte_buffer.data;
397 }
398 BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty);
399 }
400 RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
401 IMB_freeImBuf(ibuf_result);
402 }
403}
404
406{
407 Scene *scene = oglrender->scene;
408 RenderResult *rr;
409 bool ok;
410 char filepath[FILE_MAX];
411
412 rr = RE_AcquireResultRead(oglrender->re);
413
415 scene->r.pic,
416 BKE_main_blendfile_path(oglrender->bmain),
417 scene->r.cfra,
418 &scene->r.im_format,
419 (scene->r.scemode & R_EXTENSION) != 0,
420 false,
421 nullptr);
422
423 /* write images as individual images or stereo */
424 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
425 ok = BKE_image_render_write(oglrender->reports, rr, scene, false, filepath);
426
427 RE_ReleaseResultImage(oglrender->re);
428
429 if (ok) {
430 printf("OpenGL Render written to '%s'\n", filepath);
431 }
432 else {
433 printf("OpenGL Render failed to write '%s'\n", filepath);
434 }
435}
436
437static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
438{
439 /* `d = s + (1-alpha_s)d` */
440 float mul;
441
442 mul = 1.0f - source[3];
443
444 dest[0] = (mul * dest[0]) + source[0];
445 dest[1] = (mul * dest[1]) + source[1];
446 dest[2] = (mul * dest[2]) + source[2];
447 dest[3] = (mul * dest[3]) + source[3];
448}
449
450static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
451{
452 RenderResult *rr;
453 RenderView *rv;
454 int view_id;
455 ImBuf *ibuf;
456 void *lock;
457
458 if (oglrender->is_sequencer) {
459 Scene *scene = oglrender->scene;
460
461 SeqRenderData context;
462 SpaceSeq *sseq = oglrender->sseq;
463 int chanshown = sseq ? sseq->chanshown : 0;
464
466 oglrender->depsgraph,
467 scene,
468 oglrender->sizex,
469 oglrender->sizey,
471 false,
472 &context);
473
474 for (view_id = 0; view_id < oglrender->views_len; view_id++) {
475 context.view_id = view_id;
476 context.gpu_offscreen = oglrender->ofs;
477 context.gpu_viewport = oglrender->viewport;
478 oglrender->seq_data.ibufs_arr[view_id] = SEQ_render_give_ibuf(
479 &context, scene->r.cfra, chanshown);
480 }
481 }
482
483 rr = RE_AcquireResultRead(oglrender->re);
484 for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv; rv = rv->next, view_id++)
485 {
486 BLI_assert(view_id < oglrender->views_len);
487 RE_SetActiveRenderView(oglrender->re, rv->name);
488 oglrender->view_id = view_id;
489 /* render composite */
490 screen_opengl_render_doit(C, oglrender, rr);
491 }
492
493 RE_ReleaseResult(oglrender->re);
494
495 ibuf = BKE_image_acquire_ibuf(oglrender->ima, &oglrender->iuser, &lock);
496 if (ibuf) {
498 }
499 BKE_image_release_ibuf(oglrender->ima, ibuf, lock);
501
502 if (oglrender->write_still) {
504 }
505}
506
507static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
508{
509 if (adt == nullptr || adt->action == nullptr) {
510 return;
511 }
512
513 Scene *scene = oglrender->scene;
514 int frame_start = PSFRA;
515 int frame_end = PEFRA;
516
518 if (fcu->driver != nullptr || fcu->fpt != nullptr) {
519 /* Drivers have values for any point in time, so to get "the keyed frames" they are
520 * useless. Same for baked FCurves, they also have keys for every frame, which is not
521 * useful for rendering the keyed subset of the frames. */
522 continue;
523 }
524
525 bool found = false; /* Not interesting, we just want a starting point for the for-loop. */
527 fcu->bezt, frame_start, fcu->totvert, &found);
528 for (; key_index < fcu->totvert; key_index++) {
529 BezTriple *bezt = &fcu->bezt[key_index];
530 /* The frame range to render uses integer frame numbers, and the frame
531 * step is also an integer, so we always render on the frame. */
532 int frame_nr = round_fl_to_int(bezt->vec[1][0]);
533
534 /* (frame_nr < frame_start) cannot happen because of the binary search above. */
535 BLI_assert(frame_nr >= frame_start);
536 if (frame_nr > frame_end) {
537 break;
538 }
539 BLI_BITMAP_ENABLE(oglrender->render_frames, frame_nr - frame_start);
540 }
541 }
542}
543
545 const bGPdata *gp)
546{
547 if (gp == nullptr) {
548 return;
549 }
550
551 Scene *scene = oglrender->scene;
552 int frame_start = PSFRA;
553 int frame_end = PEFRA;
554
555 LISTBASE_FOREACH (const bGPDlayer *, gp_layer, &gp->layers) {
556 LISTBASE_FOREACH (const bGPDframe *, gp_frame, &gp_layer->frames) {
557 if (gp_frame->framenum < frame_start || gp_frame->framenum > frame_end) {
558 continue;
559 }
560 BLI_BITMAP_ENABLE(oglrender->render_frames, gp_frame->framenum - frame_start);
561 }
562 }
563}
564
566{
567 ID **id_p = cb_data->id_pointer;
568 if (*id_p == nullptr) {
569 return IDWALK_RET_NOP;
570 }
571 ID *id = *id_p;
572
573 ID *self_id = cb_data->self_id;
574 const int cb_flag = cb_data->cb_flag;
575 if (cb_flag == IDWALK_CB_LOOPBACK || id == self_id) {
576 /* IDs may end up referencing themselves one way or the other, and those
577 * (the self_id ones) have always already been processed. */
579 }
580
581 OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
582
583 /* Whitelist of datablocks to follow pointers into. */
584 const ID_Type id_type = GS(id->name);
585 switch (id_type) {
586 /* Whitelist: */
587 case ID_ME: /* Mesh */
588 case ID_CU_LEGACY: /* Curve */
589 case ID_MB: /* MetaBall */
590 case ID_MA: /* Material */
591 case ID_TE: /* Tex (Texture) */
592 case ID_IM: /* Image */
593 case ID_LT: /* Lattice */
594 case ID_LA: /* Light */
595 case ID_CA: /* Camera */
596 case ID_KE: /* Key (shape key) */
597 case ID_VF: /* VFont (Vector Font) */
598 case ID_TXT: /* Text */
599 case ID_SPK: /* Speaker */
600 case ID_SO: /* Sound */
601 case ID_AR: /* bArmature */
602 case ID_NT: /* bNodeTree */
603 case ID_PA: /* ParticleSettings */
604 case ID_MC: /* MovieClip */
605 case ID_MSK: /* Mask */
606 case ID_LP: /* LightProbe */
607 case ID_CV: /* Curves */
608 case ID_PT: /* PointCloud */
609 case ID_VO: /* Volume */
610 break;
611
612 /* Blacklist: */
613 case ID_SCE: /* Scene */
614 case ID_LI: /* Library */
615 case ID_OB: /* Object */
616 case ID_IP: /* Ipo (depreciated, replaced by FCurves) */
617 case ID_WO: /* World */
618 case ID_SCR: /* Screen */
619 case ID_GR: /* Group */
620 case ID_AC: /* bAction */
621 case ID_BR: /* Brush */
622 case ID_WM: /* WindowManager */
623 case ID_LS: /* FreestyleLineStyle */
624 case ID_PAL: /* Palette */
625 case ID_PC: /* PaintCurve */
626 case ID_CF: /* CacheFile */
627 case ID_WS: /* WorkSpace */
628 /* Only follow pointers to specific datablocks, to avoid ending up in
629 * unrelated datablocks and exploding the number of blocks we follow. If the
630 * frames of the animation of certain objects should be taken into account,
631 * they should have been selected by the user. */
633
634 /* Special cases: */
635 case ID_GD_LEGACY: /* bGPdata, (Grease Pencil) */
636 /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation
637 * system that requires specific handling here. */
639 break;
640 case ID_GP:
641 /* TODO: gather frames. */
642 break;
643 }
644
646 gather_frames_to_render_for_adt(oglrender, adt);
647
648 return IDWALK_RET_NOP;
649}
650
658static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
659{
660 Scene *scene = oglrender->scene;
661 int frame_start = PSFRA;
662 int frame_end = PEFRA;
663
664 /* Will be freed in screen_opengl_render_end(). */
665 oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
666 "OGLRender::render_frames");
667
668 /* The first frame should always be rendered, otherwise there is nothing to write to file. */
669 BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
670
671 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
672 ID *id = &ob->id;
673
674 /* Gather the frames from the object animation data. */
676 gather_frames_to_render_for_adt(oglrender, adt);
677
678 /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
680 nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
681 }
683}
684
686{
687 /* new render clears all callbacks */
689 wmWindow *win = CTX_wm_window(C);
690 WorkSpace *workspace = CTX_wm_workspace(C);
691
692 Scene *scene = CTX_data_scene(C);
693 ScrArea *prevsa = CTX_wm_area(C);
694 ARegion *prevar = CTX_wm_region(C);
695 GPUOffScreen *ofs;
696 OGLRender *oglrender;
697 int sizex, sizey;
698 bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
699 const bool is_animation = RNA_boolean_get(op->ptr, "animation");
700 const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
701 const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
702 const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
703 const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
704 (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
705 char err_out[256] = "unknown";
706
707 if (G.background) {
709 op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
710 return false;
711 }
712
713 /* only one render job at a time */
714 if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) {
715 return false;
716 }
717
718 if (is_sequencer) {
719 is_view_context = false;
720 }
721 else {
722 /* ensure we have a 3d view */
724 RNA_boolean_set(op->ptr, "view_context", false);
725 is_view_context = false;
726 }
727
728 if (!is_view_context && scene->camera == nullptr) {
729 BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
730 return false;
731 }
732 }
733
734 if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
736 op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
737 return false;
738 }
739
740 /* stop all running jobs, except screen one. currently previews frustrate Render */
742
743 /* create offscreen buffer */
744 BKE_render_resolution(&scene->r, false, &sizex, &sizey);
745
746 /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
747 DRW_gpu_context_enable(); /* Off-screen creation needs to be done in DRW context. */
748 ofs = GPU_offscreen_create(sizex,
749 sizey,
750 true,
753 err_out);
755
756 if (!ofs) {
757 BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
758 return false;
759 }
760
761 /* allocate opengl render */
762 oglrender = MEM_new<OGLRender>("OGLRender");
763 op->customdata = oglrender;
764
765 oglrender->ofs = ofs;
766 oglrender->sizex = sizex;
767 oglrender->sizey = sizey;
768 oglrender->viewport = GPU_viewport_create();
769 oglrender->bmain = CTX_data_main(C);
770 oglrender->scene = scene;
771 oglrender->workspace = workspace;
772 oglrender->view_layer = CTX_data_view_layer(C);
773 /* NOTE: The depsgraph is not only used to update scene for a new frames, but also to initialize
774 * output video handles, which does need evaluated scene. */
776 oglrender->cfrao = scene->r.cfra;
777
778 oglrender->write_still = is_write_still && !is_animation;
779 oglrender->is_animation = is_animation;
780 oglrender->color_depth = color_depth;
781
782 oglrender->views_len = BKE_scene_multiview_num_views_get(&scene->r);
783
784 oglrender->is_sequencer = is_sequencer;
785 if (is_sequencer) {
786 oglrender->sseq = CTX_wm_space_seq(C);
787 ImBuf **ibufs_arr = static_cast<ImBuf **>(
788 MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
789 oglrender->seq_data.ibufs_arr = ibufs_arr;
790 }
791
792 oglrender->prevsa = prevsa;
793 oglrender->prevar = prevar;
794
795 if (is_view_context) {
796 /* Prefer rendering camera in quad view if possible. */
797 if (!ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region)) {
798 /* If not get region activated by ED_view3d_context_activate earlier. */
799 oglrender->v3d = CTX_wm_view3d(C);
800 oglrender->region = CTX_wm_region(C);
801 }
802
803 oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
804
805 /* MUST be cleared on exit */
806 memset(&oglrender->scene->customdata_mask_modal,
807 0,
808 sizeof(oglrender->scene->customdata_mask_modal));
809 ED_view3d_datamask(oglrender->scene,
810 oglrender->view_layer,
811 oglrender->v3d,
812 &oglrender->scene->customdata_mask_modal);
813
814 /* apply immediately in case we're rendering from a script,
815 * running notifiers again will overwrite */
817 &oglrender->scene->customdata_mask_modal);
818 }
819
820 /* create render */
821 oglrender->re = RE_NewSceneRender(scene);
822
823 /* create image and image user */
824 oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
825 BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
826 BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
827
828 oglrender->iuser.scene = scene;
829
830 /* create render result */
832 oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
833
834 /* create render views */
835 screen_opengl_views_setup(oglrender);
836
837 /* wm vars */
838 oglrender->wm = wm;
839 oglrender->win = win;
840
841 oglrender->totvideos = 0;
842 oglrender->mh = nullptr;
843 oglrender->movie_ctx_arr = nullptr;
844
845 if (is_animation) {
846 if (is_render_keyed_only) {
847 gather_frames_to_render(C, oglrender);
848 }
849
850 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
852 }
853 else {
854 oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_HIGH);
855 }
856 oglrender->pool_ok = true;
857 BLI_spin_init(&oglrender->reports_lock);
858 }
859 else {
860 oglrender->task_pool = nullptr;
861 }
862 oglrender->num_scheduled_frames = 0;
863 BLI_mutex_init(&oglrender->task_mutex);
865
866#ifdef DEBUG_TIME
867 oglrender->time_start = BLI_time_now_seconds();
868#endif
869
870 return true;
871}
872
873static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
874{
875 Scene *scene = oglrender->scene;
876 int i;
877
878 if (oglrender->is_animation) {
879 /* Trickery part for movie output:
880 *
881 * We MUST write frames in an exact order, so we only let background
882 * thread to work on that, and main thread is simply waits for that
883 * thread to do all the dirty work.
884 *
885 * After this loop is done work_and_wait() will have nothing to do,
886 * so we don't run into wrong order of frames written to the stream.
887 */
888 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
889 BLI_mutex_lock(&oglrender->task_mutex);
890 while (oglrender->num_scheduled_frames > 0) {
891 BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
892 }
893 BLI_mutex_unlock(&oglrender->task_mutex);
894 }
896 BLI_task_pool_free(oglrender->task_pool);
897 BLI_spin_end(&oglrender->reports_lock);
898 }
899 BLI_mutex_end(&oglrender->task_mutex);
901
902#ifdef DEBUG_TIME
903 printf("Total render time: %f\n", BLI_time_now_seconds() - oglrender->time_start);
904#endif
905
906 MEM_SAFE_FREE(oglrender->render_frames);
907
908 if (oglrender->mh) {
909 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
910 for (i = 0; i < oglrender->totvideos; i++) {
911 oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
912 oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
913 }
914 }
915
916 if (oglrender->movie_ctx_arr) {
917 MEM_freeN(oglrender->movie_ctx_arr);
918 }
919 }
920
921 if (oglrender->timer) { /* exec will not have a timer */
922 Depsgraph *depsgraph = oglrender->depsgraph;
923 scene->r.cfra = oglrender->cfrao;
925
926 WM_event_timer_remove(oglrender->wm, oglrender->win, oglrender->timer);
927 }
928
929 WM_cursor_modal_restore(oglrender->win);
930
932
934 GPU_offscreen_free(oglrender->ofs);
935 GPU_viewport_free(oglrender->viewport);
937
938 if (oglrender->is_sequencer) {
939 MEM_freeN(oglrender->seq_data.ibufs_arr);
940 }
941
942 memset(&oglrender->scene->customdata_mask_modal,
943 0,
944 sizeof(oglrender->scene->customdata_mask_modal));
945
946 CTX_wm_area_set(C, oglrender->prevsa);
947 CTX_wm_region_set(C, oglrender->prevar);
948
949 MEM_delete(oglrender);
950 G.is_rendering = false;
951}
952
954{
955 screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
956}
957
958/* share between invoke and exec */
960{
961 /* initialize animation */
962 OGLRender *oglrender;
963 Scene *scene;
964
965 oglrender = static_cast<OGLRender *>(op->customdata);
966 scene = oglrender->scene;
967 oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
968
969 oglrender->reports = op->reports;
970
971 if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
972 size_t width, height;
973 int i;
974
976 &scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
977 oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
978
979 if (oglrender->mh == nullptr) {
980 BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
981 screen_opengl_render_end(C, oglrender);
982 return false;
983 }
984
985 oglrender->movie_ctx_arr = static_cast<void **>(
986 MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"));
987
988 for (i = 0; i < oglrender->totvideos; i++) {
989 Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
990 const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
991
992 oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
993 if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i],
994 scene_eval,
995 &scene->r,
996 oglrender->sizex,
997 oglrender->sizey,
998 oglrender->reports,
999 PRVRANGEON != 0,
1000 suffix))
1001 {
1002 screen_opengl_render_end(C, oglrender);
1003 return false;
1004 }
1005 }
1006 }
1007
1008 G.is_rendering = true;
1009 oglrender->cfrao = scene->r.cfra;
1010 oglrender->nfra = PSFRA;
1011 scene->r.cfra = PSFRA;
1012
1013 return true;
1014}
1015
1020
1021static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
1022{
1023 OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
1024 Scene *scene = &task_data->tmp_scene;
1025 RenderResult *rr = task_data->rr;
1026 const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
1027 const int cfra = scene->r.cfra;
1028 bool ok;
1029 /* Don't attempt to write if we've got an error. */
1030 if (!oglrender->pool_ok) {
1032 BLI_mutex_lock(&oglrender->task_mutex);
1033 oglrender->num_scheduled_frames--;
1035 BLI_mutex_unlock(&oglrender->task_mutex);
1036 return;
1037 }
1038 /* Construct local thread0safe copy of reports structure which we can
1039 * safely pass to the underlying functions.
1040 */
1041 ReportList reports;
1042 BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
1043 /* Do actual save logic here, depending on the file format.
1044 *
1045 * NOTE: We have to construct temporary scene with proper scene->r.cfra.
1046 * This is because underlying calls do not use r.cfra but use scene
1047 * for that.
1048 */
1049 if (is_movie) {
1050 ok = RE_WriteRenderViewsMovie(&reports,
1051 rr,
1052 scene,
1053 &scene->r,
1054 oglrender->mh,
1055 oglrender->movie_ctx_arr,
1056 oglrender->totvideos,
1057 PRVRANGEON != 0);
1058 }
1059 else {
1060 /* TODO(sergey): We can in theory save some CPU ticks here because we
1061 * calculate file name again here.
1062 */
1063 char filepath[FILE_MAX];
1065 scene->r.pic,
1066 BKE_main_blendfile_path(oglrender->bmain),
1067 cfra,
1068 &scene->r.im_format,
1069 (scene->r.scemode & R_EXTENSION) != 0,
1070 true,
1071 nullptr);
1072
1073 BKE_render_result_stamp_info(scene, scene->camera, rr, false);
1074 ok = BKE_image_render_write(nullptr, rr, scene, true, filepath);
1075 if (!ok) {
1076 BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", filepath);
1077 }
1078 }
1079 if (reports.list.first != nullptr) {
1080 /* TODO: Should rather use new #BKE_reports_move_to_reports ? */
1081 BLI_spin_lock(&oglrender->reports_lock);
1082 for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
1083 report = report->next)
1084 {
1085 BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
1086 }
1087 BLI_spin_unlock(&oglrender->reports_lock);
1088 }
1089 BKE_reports_free(&reports);
1090 if (!ok) {
1091 oglrender->pool_ok = false;
1092 }
1094 BLI_mutex_lock(&oglrender->task_mutex);
1095 oglrender->num_scheduled_frames--;
1097 BLI_mutex_unlock(&oglrender->task_mutex);
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_cnew<WriteTaskData>("write task data");
1117 task_data->rr = rr;
1118 memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
1119 BLI_mutex_lock(&oglrender->task_mutex);
1120 oglrender->num_scheduled_frames++;
1121 if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
1122 BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
1123 }
1124 BLI_mutex_unlock(&oglrender->task_mutex);
1125 BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
1126 return true;
1127}
1128
1130{
1131 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
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) {
1153 scene->r.pic,
1154 BKE_main_blendfile_path(oglrender->bmain),
1155 scene->r.cfra,
1156 &scene->r.im_format,
1157 (scene->r.scemode & R_EXTENSION) != 0,
1158 true,
1159 nullptr);
1160
1161 if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(filepath)) {
1162 BLI_spin_lock(&oglrender->reports_lock);
1163 BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", filepath);
1164 BLI_spin_unlock(&oglrender->reports_lock);
1165 ok = true;
1166 goto finally;
1167 }
1168 }
1169
1170 WM_cursor_time(oglrender->win, scene->r.cfra);
1171
1173
1174 if (view_context) {
1175 if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
1176 oglrender->v3d->scenelock)
1177 {
1178 /* since BKE_scene_graph_update_for_newframe() is used rather
1179 * then ED_update_for_newframe() the camera needs to be set */
1180 if (BKE_scene_camera_switch_update(scene)) {
1181 oglrender->v3d->camera = scene->camera;
1182 }
1183 }
1184 }
1185 else {
1187 }
1188
1189 if (oglrender->render_frames == nullptr ||
1190 BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA))
1191 {
1192 /* render into offscreen buffer */
1193 screen_opengl_render_apply(C, oglrender);
1194 }
1195
1196 /* save to disk */
1197 rr = RE_AcquireResultRead(oglrender->re);
1198 {
1200 RE_ReleaseResult(oglrender->re);
1201
1202 ok = schedule_write_result(oglrender, new_rr);
1203 }
1204
1205finally: /* Step the frame and bail early if needed */
1206
1207 /* go to next frame */
1208 oglrender->nfra += scene->r.frame_step;
1209
1210 /* stop at the end or on error */
1211 if (scene->r.cfra >= PEFRA || !ok) {
1212 screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1213 return false;
1214 }
1215
1216 return true;
1217}
1218
1220{
1221 OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1222 const bool anim = RNA_boolean_get(op->ptr, "animation");
1223 bool ret;
1224
1225 switch (event->type) {
1226 case EVT_ESCKEY:
1227 /* cancel */
1228 oglrender->pool_ok = false; /* Flag pool for cancel. */
1229 screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1230 return OPERATOR_FINISHED;
1231 case TIMER:
1232 /* render frame? */
1233 if (oglrender->timer == event->customdata) {
1234 break;
1235 }
1237 default:
1238 /* nothing to do */
1240 }
1241
1242 /* run first because screen_opengl_render_anim_step can free oglrender */
1244
1245 if (anim == 0) {
1246 screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
1247 screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1248 return OPERATOR_FINISHED;
1249 }
1250
1252
1253 /* stop at the end or on error */
1254 if (ret == false) {
1255 return OPERATOR_FINISHED;
1256 }
1257
1259}
1260
1262{
1263 OGLRender *oglrender;
1264 const bool anim = RNA_boolean_get(op->ptr, "animation");
1265
1266 if (!screen_opengl_render_init(C, op)) {
1267 return OPERATOR_CANCELLED;
1268 }
1269
1270 if (anim) {
1271 if (!screen_opengl_render_anim_init(C, op)) {
1272 return OPERATOR_CANCELLED;
1273 }
1274 }
1275
1276 oglrender = static_cast<OGLRender *>(op->customdata);
1277 render_view_open(C, event->xy[0], event->xy[1], op->reports);
1278
1279 /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
1280 oglrender->win = CTX_wm_window(C);
1281
1283 oglrender->timer = WM_event_timer_add(oglrender->wm, oglrender->win, TIMER, 0.01f);
1284
1286}
1287
1288/* executes blocking render */
1290{
1291 const bool is_animation = RNA_boolean_get(op->ptr, "animation");
1292
1293 if (!screen_opengl_render_init(C, op)) {
1294 return OPERATOR_CANCELLED;
1295 }
1296
1297 if (!is_animation) { /* same as invoke */
1298 /* render image */
1299 screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
1300 screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1301
1302 return OPERATOR_FINISHED;
1303 }
1304
1305 bool ret = true;
1306
1307 if (!screen_opengl_render_anim_init(C, op)) {
1308 return OPERATOR_CANCELLED;
1309 }
1310
1311 while (ret) {
1313 }
1314
1315 /* no redraw needed, we leave state as we entered it */
1316 // ED_update_for_newframe(C);
1318
1319 return OPERATOR_FINISHED;
1320}
1321
1323 wmOperatorType * /*ot*/,
1324 PointerRNA *ptr)
1325{
1326 if (!RNA_boolean_get(ptr, "animation")) {
1327 return "";
1328 }
1329
1330 if (RNA_boolean_get(ptr, "render_keyed_only")) {
1331 return TIP_(
1332 "Render the viewport for the animation range of this scene, but only render keyframes of "
1333 "selected objects");
1334 }
1335
1336 return TIP_("Render the viewport for the animation range of this scene");
1337}
1338
1340{
1341 PropertyRNA *prop;
1342
1343 /* identifiers */
1344 ot->name = "Viewport Render";
1345 ot->description = "Take a snapshot of the active viewport";
1346 ot->idname = "RENDER_OT_opengl";
1347
1348 /* api callbacks */
1351 ot->exec = screen_opengl_render_exec; /* blocking */
1354
1356
1357 prop = RNA_def_boolean(ot->srna,
1358 "animation",
1359 false,
1360 "Animation",
1361 "Render files from the animation range of this scene");
1363
1364 prop = RNA_def_boolean(ot->srna,
1365 "render_keyed_only",
1366 false,
1367 "Render Keyframes Only",
1368 "Render only those frames where selected objects have a key in their "
1369 "animation data. Only used when rendering animation");
1371
1372 prop = RNA_def_boolean(
1373 ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
1375 prop = RNA_def_boolean(
1376 ot->srna,
1377 "write_still",
1378 false,
1379 "Write Image",
1380 "Save the rendered image to the output path (used only when animation is disabled)");
1382 prop = RNA_def_boolean(ot->srna,
1383 "view_context",
1384 true,
1385 "View Context",
1386 "Use the current 3D view for rendering, else use scene settings");
1388}
Functions for backward compatibility with the legacy Action API.
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
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:91
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:138
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.
void BKE_image_path_from_imformat(char *filepath, const char *base, const char *relbase, 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)
@ IDWALK_RET_STOP_RECURSION
@ IDWALK_RET_NOP
@ IDWALK_CB_LOOPBACK
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, int flag)
Definition lib_query.cc:416
@ IDWALK_RECURSE
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_reports_free(ReportList *reports)
Definition report.cc:69
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:54
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2877
int BKE_scene_multiview_num_views_get(const RenderData *rd)
Definition scene.cc:2928
bool BKE_scene_multiview_is_render_view_active(const RenderData *rd, const SceneRenderView *srv)
Definition scene.cc:2976
const char * BKE_scene_multiview_view_id_suffix_get(const RenderData *rd, int view_id)
Definition scene.cc:3142
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2213
bool BKE_scene_multiview_is_stereo3d(const RenderData *rd)
Definition scene.cc:2959
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:3183
int BKE_scene_multiview_num_videos_get(const RenderData *rd)
Definition scene.cc:3203
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2647
bMovieHandle * BKE_movie_handle_get(char imtype)
Definition writemovie.cc:58
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition BLI_bitmap.h:75
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
#define ATTR_FALLTHROUGH
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
MINLINE int round_fl_to_int(float a)
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
#define FILE_MAX
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned char uchar
unsigned int uint
@ TASK_PRIORITY_HIGH
Definition BLI_task.h:57
void * BLI_task_pool_user_data(TaskPool *pool)
Definition task_pool.cc:516
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition task_pool.cc:471
TaskPool * BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority)
Definition task_pool.cc:426
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition task_pool.cc:394
void BLI_task_pool_free(TaskPool *pool)
Definition task_pool.cc:431
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition task_pool.cc:450
void BLI_condition_notify_all(ThreadCondition *cond)
Definition threads.cc:597
pthread_spinlock_t SpinLock
void BLI_mutex_end(ThreadMutex *mutex)
Definition threads.cc:360
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
Definition threads.cc:582
void BLI_mutex_init(ThreadMutex *mutex)
Definition threads.cc:340
pthread_cond_t ThreadCondition
void BLI_condition_end(ThreadCondition *cond)
Definition threads.cc:602
void BLI_condition_init(ThreadCondition *cond)
Definition threads.cc:577
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
void BLI_spin_init(SpinLock *spin)
Definition threads.cc:391
void BLI_spin_unlock(SpinLock *spin)
Definition threads.cc:430
void BLI_spin_lock(SpinLock *spin)
Definition threads.cc:405
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:83
void BLI_spin_end(SpinLock *spin)
Definition threads.cc:445
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#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_TYPE_R_RESULT
eDrawType
@ OB_SOLID
Object is a sort of wrapper for general info.
#define R_STAMP_ALL
@ R_MULTIVIEW
@ R_EXTENSION
@ R_STAMP_DRAW
#define PSFRA
#define V3D_CAMERA_SCENE(scene, v3d)
@ R_ADDSKY
@ R_ALPHAPREMUL
@ R_NO_OVERWRITE
eImageFormatDepth
@ R_IMF_CHAN_DEPTH_32
#define PRVRANGEON
#define PEFRA
@ SEQ_RENDER_SIZE_SCENE
@ SPACE_SEQ
@ SEQ_PREVIEW_SHOW_GPENCIL
@ V3D_OFSDRAW_SHOW_ANNOTATION
@ RV3D_CAMOB
@ OPERATOR_RUNNING_MODAL
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])
GPUOffScreen * GPU_offscreen_create(int width, int height, bool with_depth_buffer, eGPUTextureFormat format, eGPUTextureUsage usage, char err_out[256])
void GPU_offscreen_bind(GPUOffScreen *offscreen, bool save)
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)
@ GPU_DATA_UBYTE
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_TEXTURE_USAGE_HOST_READ
GPUViewport * GPU_viewport_create()
void GPU_viewport_free(GPUViewport *viewport)
void imb_freerectfloatImBuf(ImBuf *ibuf)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
Contains defines and structs used throughout the imbuf module.
@ IB_rectfloat
@ IB_rect
@ IB_DISPLAY_BUFFER_INVALID
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ WM_JOB_TYPE_RENDER
Definition WM_api.hh:1578
#define ND_RENDER_RESULT
Definition WM_types.hh:413
#define NC_SCENE
Definition WM_types.hh:345
void ED_annotation_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype)
volatile int lock
static void mul(btAlignedObjectArray< T > &items, const Q &value)
#define printf
const Depsgraph * depsgraph
#define offsetof(t, d)
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
void RE_SetOverrideCamera(Render *re, Object *cam_ob)
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
void isolate_task(const Function &function)
Definition BLI_task.hh:226
return ret
void SEQ_render_new_render_data(Main *bmain, Depsgraph *depsgraph, Scene *scene, int rectx, int recty, int preview_render_size, int for_render, SeqRenderData *r_context)
Definition render.cc:220
ImBuf * SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown)
Definition render.cc:2078
ScrArea * render_view_open(bContext *C, int mx, int my, ReportList *reports)
static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr)
static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
static void UNUSED_FUNCTION addAlphaOverFloat(float dest[4], const float source[4])
static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
static int screen_opengl_render_exec(bContext *C, wmOperator *op)
static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
static std::string screen_opengl_render_get_description(bContext *, wmOperatorType *, PointerRNA *ptr)
static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define MAX_SCHEDULED_FRAMES
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 write_result_func(TaskPool *__restrict pool, void *task_data_v)
static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
static void screen_opengl_render_write(OGLRender *oglrender)
static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
void RENDER_OT_opengl(wmOperatorType *ot)
static bool screen_opengl_is_multiview(OGLRender *oglrender)
static bool screen_opengl_render_init(bContext *C, 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)
static bool is_movie(wmDrag *drag)
void RE_ReleaseResultImage(Render *re)
bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh, void **movie_ctx_arr, const int totvideos, bool preview)
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)
void RE_SetActiveRenderView(Render *re, const char *viewname)
void * regiondata
bAction * action
float vec[3][3]
Definition DNA_ID.h:413
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
struct Scene * scene
void * last
void * first
TaskPool * task_pool
wmTimer * timer
BLI_bitmap * render_frames
ViewLayer * view_layer
SpinLock reports_lock
Render * re
ImBuf ** ibufs_arr
uint num_scheduled_frames
ThreadMutex task_mutex
ARegion * prevar
Depsgraph * depsgraph
RegionView3D * rv3d
Scene * scene
ThreadCondition task_condition
GPUViewport * viewport
WorkSpace * workspace
wmWindowManager * wm
void ** movie_ctx_arr
ScrArea * prevsa
ARegion * region
ReportList * reports
bMovieHandle * mh
ImageUser iuser
eImageFormatDepth color_depth
struct OGLRender::@466 seq_data
GPUOffScreen * ofs
SpaceSeq * sseq
View3D * v3d
wmWindow * win
ListBase views
struct ImBuf * ibuf
Definition RE_pipeline.h:52
struct RenderView * prev
Definition RE_pipeline.h:46
struct RenderView * next
Definition RE_pipeline.h:46
char name[64]
Definition RE_pipeline.h:47
RenderData r
struct CustomData_MeshMasks customdata_mask
struct RenderData r
struct CustomData_MeshMasks customdata_mask_modal
struct Object * camera
struct bGPdata * gpd
struct Object * camera
short scenelock
View3DShading shading
RenderResult * rr
void(* end_movie)(void *context_v)
bool(* start_movie)(void *context_v, const Scene *scene, RenderData *rd, int rectx, int recty, ReportList *reports, bool preview, const char *suffix)
void(* context_free)(void *context_v)
void *(* context_create)()
int xy[2]
Definition WM_types.hh:726
short type
Definition WM_types.hh:722
void * customdata
Definition WM_types.hh:772
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
std::string(* get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr)
Definition WM_types.hh:1074
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct PointerRNA * ptr
void WM_cursor_modal_restore(wmWindow *win)
void WM_cursor_time(wmWindow *win, int nr)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ TIMER
@ EVT_ESCKEY
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:588
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition wm_jobs.cc:223
void wmOrtho2(float x1, float x2, float y1, float y2)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)