Blender  V3.3
render_opengl.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
8 #include <cmath>
9 #include <cstddef>
10 #include <cstring>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_bitmap.h"
15 #include "BLI_blenlib.h"
16 #include "BLI_math.h"
17 #include "BLI_math_color_blend.h"
18 #include "BLI_task.h"
19 #include "BLI_task.hh"
20 #include "BLI_threads.h"
21 #include "BLI_utildefines.h"
22 #include "DNA_camera_types.h"
23 
24 #include "DNA_action_types.h"
25 #include "DNA_anim_types.h"
26 #include "DNA_curve_types.h"
27 #include "DNA_gpencil_types.h"
28 #include "DNA_object_types.h"
29 #include "DNA_scene_types.h"
30 
31 #include "BKE_anim_data.h"
32 #include "BKE_camera.h"
33 #include "BKE_context.h"
34 #include "BKE_customdata.h"
35 #include "BKE_fcurve.h"
36 #include "BKE_global.h"
37 #include "BKE_image.h"
38 #include "BKE_image_format.h"
39 #include "BKE_image_save.h"
40 #include "BKE_lib_query.h"
41 #include "BKE_main.h"
42 #include "BKE_report.h"
43 #include "BKE_scene.h"
44 #include "BKE_writeavi.h"
45 
46 #include "DEG_depsgraph.h"
47 #include "DEG_depsgraph_query.h"
48 
49 #include "DRW_engine.h"
50 
51 #include "WM_api.h"
52 #include "WM_types.h"
53 
54 #include "ED_gpencil.h"
55 #include "ED_screen.h"
56 #include "ED_view3d.h"
57 #include "ED_view3d_offscreen.h"
58 
59 #include "IMB_colormanagement.h"
60 #include "IMB_imbuf.h"
61 #include "IMB_imbuf_types.h"
62 
63 #include "RE_pipeline.h"
64 
65 #include "BLT_translation.h"
66 
67 #include "RNA_access.h"
68 #include "RNA_define.h"
69 
70 #include "SEQ_render.h"
71 
72 #include "GPU_framebuffer.h"
73 #include "GPU_matrix.h"
74 
75 #include "render_intern.hh"
76 
77 /* Define this to get timing information. */
78 // #define DEBUG_TIME
79 
80 #ifdef DEBUG_TIME
81 # include "PIL_time.h"
82 #endif
83 
84 /* TODO(sergey): Find better approximation of the scheduled frames.
85  * For really high-resolution renders it might fail still. */
86 #define MAX_SCHEDULED_FRAMES 8
87 
88 struct OGLRender {
95 
99 
102 
103  int views_len; /* multi-view views */
104 
107  struct {
110 
113 
115  int sizex, sizey;
117 
120  int cfrao, nfra;
121 
123 
124  /* For only rendering frames that have a key in animation data. */
126 
127  /* quick lookup */
128  int view_id;
129 
130  /* wm vars for timer and progress cursor */
133 
136 
138 
140  bool pool_ok;
142 
148 
149 #ifdef DEBUG_TIME
150  double time_start;
151 #endif
152 };
153 
154 static bool screen_opengl_is_multiview(OGLRender *oglrender)
155 {
156  View3D *v3d = oglrender->v3d;
157  RegionView3D *rv3d = oglrender->rv3d;
158  RenderData *rd = &oglrender->scene->r;
159 
160  if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
161  return false;
162  }
163 
164  return (rd->scemode & R_MULTIVIEW) &&
165  ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
166 }
167 
168 static void screen_opengl_views_setup(OGLRender *oglrender)
169 {
170  RenderResult *rr;
171  RenderView *rv;
172  SceneRenderView *srv;
173  bool is_multiview;
174  Object *camera;
175  View3D *v3d = oglrender->v3d;
176 
177  RenderData *rd = &oglrender->scene->r;
178 
179  rr = RE_AcquireResultWrite(oglrender->re);
180 
181  is_multiview = screen_opengl_is_multiview(oglrender);
182 
183  if (!is_multiview) {
184  /* we only have one view when multiview is off */
185  rv = static_cast<RenderView *>(rr->views.first);
186 
187  if (rv == nullptr) {
188  rv = MEM_cnew<RenderView>("new opengl render view");
189  BLI_addtail(&rr->views, rv);
190  }
191 
192  while (rv->next) {
193  RenderView *rv_del = rv->next;
194  BLI_remlink(&rr->views, rv_del);
195 
196  if (rv_del->rectf) {
197  MEM_freeN(rv_del->rectf);
198  }
199 
200  if (rv_del->rectz) {
201  MEM_freeN(rv_del->rectz);
202  }
203 
204  if (rv_del->rect32) {
205  MEM_freeN(rv_del->rect32);
206  }
207 
208  MEM_freeN(rv_del);
209  }
210  }
211  else {
212  if (v3d) {
213  RE_SetOverrideCamera(oglrender->re, V3D_CAMERA_SCENE(oglrender->scene, v3d));
214  }
215 
216  /* remove all the views that are not needed */
217  rv = static_cast<RenderView *>(rr->views.last);
218  while (rv) {
219  srv = static_cast<SceneRenderView *>(
220  BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)));
222  rv = rv->prev;
223  }
224  else {
225  RenderView *rv_del = rv;
226  rv = rv_del->prev;
227 
228  BLI_remlink(&rr->views, rv_del);
229 
230  if (rv_del->rectf) {
231  MEM_freeN(rv_del->rectf);
232  }
233 
234  if (rv_del->rectz) {
235  MEM_freeN(rv_del->rectz);
236  }
237 
238  if (rv_del->rect32) {
239  MEM_freeN(rv_del->rect32);
240  }
241 
242  MEM_freeN(rv_del);
243  }
244  }
245 
246  /* create all the views that are needed */
247  for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) {
248  if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
249  continue;
250  }
251 
252  rv = static_cast<RenderView *>(
253  BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
254 
255  if (rv == nullptr) {
256  rv = MEM_cnew<RenderView>("new opengl render view");
257  BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
258  BLI_addtail(&rr->views, rv);
259  }
260  }
261  }
262 
263  if (!(is_multiview && BKE_scene_multiview_is_stereo3d(rd))) {
264  oglrender->iuser.flag &= ~IMA_SHOW_STEREO;
265  }
266 
267  /* will only work for non multiview correctly */
268  if (v3d) {
269  camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, "new opengl render view");
270  BKE_render_result_stamp_info(oglrender->scene, camera, rr, false);
271  }
272  else {
273  BKE_render_result_stamp_info(oglrender->scene, oglrender->scene->camera, rr, false);
274  }
275 
276  RE_ReleaseResult(oglrender->re);
277 }
278 
279 static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, RenderResult *rr)
280 {
282  Scene *scene = oglrender->scene;
283  ARegion *region = oglrender->region;
284  View3D *v3d = oglrender->v3d;
285  RegionView3D *rv3d = oglrender->rv3d;
286  Object *camera = nullptr;
287  int sizex = oglrender->sizex;
288  int sizey = oglrender->sizey;
289  const short view_context = (v3d != nullptr);
290  bool draw_sky = (scene->r.alphamode == R_ADDSKY);
291  float *rectf = nullptr;
292  uchar *rect = nullptr;
293  const char *viewname = RE_GetActiveRenderView(oglrender->re);
294  ImBuf *ibuf_result = nullptr;
295 
296  if (oglrender->is_sequencer) {
297  SpaceSeq *sseq = oglrender->sseq;
298  struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
299 
300  /* use pre-calculated ImBuf (avoids deadlock), see: */
301  ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
302 
303  if (ibuf) {
304  ImBuf *out = IMB_dupImBuf(ibuf);
305  IMB_freeImBuf(ibuf);
306  /* OpenGL render is considered to be preview and should be
307  * as fast as possible. So currently we're making sure sequencer
308  * result is always byte to simplify color management pipeline.
309  *
310  * TODO(sergey): In the case of output to float container (EXR)
311  * it actually makes sense to keep float buffer instead.
312  */
313  if (out->rect_float != nullptr) {
316  }
317  BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
320  }
321  else if (gpd) {
322  /* If there are no strips, Grease Pencil still needs a buffer to draw on */
323  ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
326  }
327 
328  if (gpd) {
329  int i;
330  uchar *gp_rect;
331  uchar *render_rect = (uchar *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
332 
334  GPU_offscreen_bind(oglrender->ofs, true);
335 
336  GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
337  GPU_clear_depth(1.0f);
338 
340  wmOrtho2(0, scene->r.xsch, 0, scene->r.ysch);
342 
344  ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
346 
347  gp_rect = static_cast<uchar *>(
348  MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
349  GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
350 
351  for (i = 0; i < sizex * sizey * 4; i += 4) {
352  blend_color_mix_byte(&render_rect[i], &render_rect[i], &gp_rect[i]);
353  }
354  GPU_offscreen_unbind(oglrender->ofs, true);
356 
357  MEM_freeN(gp_rect);
358  }
359  }
360  else {
361  /* shouldn't suddenly give errors mid-render but possible */
362  char err_out[256] = "unknown";
363  ImBuf *ibuf_view;
364  const int alpha_mode = (draw_sky) ? R_ADDSKY : R_ALPHAPREMUL;
365  if (view_context) {
367  scene,
368  static_cast<eDrawType>(v3d->shading.type),
369  v3d,
370  region,
371  sizex,
372  sizey,
373  IB_rectfloat,
374  alpha_mode,
375  viewname,
376  true,
377  oglrender->ofs,
378  err_out);
379 
380  /* for stamp only */
381  if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
382  camera = BKE_camera_multiview_render(oglrender->scene, v3d->camera, viewname);
383  }
384  }
385  else {
387  scene,
388  nullptr,
389  OB_SOLID,
390  scene->camera,
391  oglrender->sizex,
392  oglrender->sizey,
393  IB_rectfloat,
395  alpha_mode,
396  viewname,
397  oglrender->ofs,
398  err_out);
399  camera = scene->camera;
400  }
401 
402  if (ibuf_view) {
403  ibuf_result = ibuf_view;
404  if (ibuf_view->rect_float) {
405  rectf = ibuf_view->rect_float;
406  }
407  else {
408  rect = (uchar *)ibuf_view->rect;
409  }
410  }
411  else {
412  fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out);
413  }
414  }
415 
416  if (ibuf_result != nullptr) {
417  if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
418  BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4);
419  }
420  RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
421  IMB_freeImBuf(ibuf_result);
422  }
423 }
424 
425 static void screen_opengl_render_write(OGLRender *oglrender)
426 {
427  Scene *scene = oglrender->scene;
428  RenderResult *rr;
429  bool ok;
430  char name[FILE_MAX];
431 
432  rr = RE_AcquireResultRead(oglrender->re);
433 
435  scene->r.pic,
436  BKE_main_blendfile_path(oglrender->bmain),
437  scene->r.cfra,
438  &scene->r.im_format,
439  (scene->r.scemode & R_EXTENSION) != 0,
440  false,
441  nullptr);
442 
443  /* write images as individual images or stereo */
445  ok = BKE_image_render_write(oglrender->reports, rr, scene, false, name);
446 
447  RE_ReleaseResultImage(oglrender->re);
448 
449  if (ok) {
450  printf("OpenGL Render written to '%s'\n", name);
451  }
452  else {
453  printf("OpenGL Render failed to write '%s'\n", name);
454  }
455 }
456 
457 static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4])
458 {
459  /* `d = s + (1-alpha_s)d` */
460  float mul;
461 
462  mul = 1.0f - source[3];
463 
464  dest[0] = (mul * dest[0]) + source[0];
465  dest[1] = (mul * dest[1]) + source[1];
466  dest[2] = (mul * dest[2]) + source[2];
467  dest[3] = (mul * dest[3]) + source[3];
468 }
469 
470 static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
471 {
472  RenderResult *rr;
473  RenderView *rv;
474  int view_id;
475  ImBuf *ibuf;
476  void *lock;
477 
478  if (oglrender->is_sequencer) {
479  Scene *scene = oglrender->scene;
480 
482  SpaceSeq *sseq = oglrender->sseq;
483  int chanshown = sseq ? sseq->chanshown : 0;
484 
486  oglrender->depsgraph,
487  scene,
488  oglrender->sizex,
489  oglrender->sizey,
491  false,
492  &context);
493 
494  for (view_id = 0; view_id < oglrender->views_len; view_id++) {
495  context.view_id = view_id;
496  context.gpu_offscreen = oglrender->ofs;
497  oglrender->seq_data.ibufs_arr[view_id] = SEQ_render_give_ibuf(
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;
504  rv = rv->next, view_id++) {
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(C, 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) {
522  screen_opengl_render_write(oglrender);
523  }
524 }
525 
526 static 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 
536  LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
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. */
545  int key_index = BKE_fcurve_bezt_binarysearch_index(
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 *id_self = cb_data->id_self;
593  const int cb_flag = cb_data->cb_flag;
594  if (cb_flag == IDWALK_CB_LOOPBACK || id == id_self) {
595  /* IDs may end up referencing themselves one way or the other, and those
596  * (the id_self 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  case ID_SIM: /* Simulation */
630  break;
631 
632  /* Blacklist: */
633  case ID_SCE: /* Scene */
634  case ID_LI: /* Library */
635  case ID_OB: /* Object */
636  case ID_IP: /* Ipo (depreciated, replaced by FCurves) */
637  case ID_WO: /* World */
638  case ID_SCR: /* Screen */
639  case ID_GR: /* Group */
640  case ID_AC: /* bAction */
641  case ID_BR: /* Brush */
642  case ID_WM: /* WindowManager */
643  case ID_LS: /* FreestyleLineStyle */
644  case ID_PAL: /* Palette */
645  case ID_PC: /* PaintCurve */
646  case ID_CF: /* CacheFile */
647  case ID_WS: /* WorkSpace */
648  /* Only follow pointers to specific datablocks, to avoid ending up in
649  * unrelated datablocks and exploding the number of blocks we follow. If the
650  * frames of the animation of certain objects should be taken into account,
651  * they should have been selected by the user. */
653 
654  /* Special cases: */
655  case ID_GD: /* bGPdata, (Grease Pencil) */
656  /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation
657  * system that requires specific handling here. */
659  break;
660  }
661 
664 
665  return IDWALK_RET_NOP;
666 }
667 
675 static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
676 {
677  Scene *scene = oglrender->scene;
678  int frame_start = PSFRA;
679  int frame_end = PEFRA;
680 
681  /* Will be freed in screen_opengl_render_end(). */
682  oglrender->render_frames = BLI_BITMAP_NEW(frame_end - frame_start + 1,
683  "OGLRender::render_frames");
684 
685  /* The first frame should always be rendered, otherwise there is nothing to write to file. */
686  BLI_BITMAP_ENABLE(oglrender->render_frames, 0);
687 
688  CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
689  ID *id = &ob->id;
690 
691  /* Gather the frames from the object animation data. */
694 
695  /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
697  nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
698  }
699  CTX_DATA_END;
700 }
701 
703 {
704  /* new render clears all callbacks */
706  wmWindow *win = CTX_wm_window(C);
707  WorkSpace *workspace = CTX_wm_workspace(C);
708 
710  ScrArea *prevsa = CTX_wm_area(C);
711  ARegion *prevar = CTX_wm_region(C);
712  GPUOffScreen *ofs;
713  OGLRender *oglrender;
714  int sizex, sizey;
715  bool is_view_context = RNA_boolean_get(op->ptr, "view_context");
716  const bool is_animation = RNA_boolean_get(op->ptr, "animation");
717  const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
718  const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
719  const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
720  const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
722  char err_out[256] = "unknown";
723 
724  if (G.background) {
725  BKE_report(
726  op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)");
727  return false;
728  }
729 
730  /* only one render job at a time */
732  return false;
733  }
734 
735  if (is_sequencer) {
736  is_view_context = false;
737  }
738  else {
739  /* ensure we have a 3d view */
741  RNA_boolean_set(op->ptr, "view_context", false);
742  is_view_context = false;
743  }
744 
745  if (!is_view_context && scene->camera == nullptr) {
746  BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
747  return false;
748  }
749  }
750 
751  if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
752  BKE_report(
753  op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected");
754  return false;
755  }
756 
757  /* stop all running jobs, except screen one. currently previews frustrate Render */
759 
760  /* create offscreen buffer */
761  BKE_render_resolution(&scene->r, false, &sizex, &sizey);
762 
763  /* corrects render size with actual size, not every card supports non-power-of-two dimensions */
764  DRW_opengl_context_enable(); /* Off-screen creation needs to be done in DRW context. */
765  ofs = GPU_offscreen_create(sizex, sizey, true, GPU_RGBA16F, err_out);
767 
768  if (!ofs) {
769  BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out);
770  return false;
771  }
772 
773  /* allocate opengl render */
774  oglrender = MEM_new<OGLRender>("OGLRender");
775  op->customdata = oglrender;
776 
777  oglrender->ofs = ofs;
778  oglrender->sizex = sizex;
779  oglrender->sizey = sizey;
780  oglrender->bmain = CTX_data_main(C);
781  oglrender->scene = scene;
782  oglrender->workspace = workspace;
783  oglrender->view_layer = CTX_data_view_layer(C);
784  /* NOTE: The depsgraph is not only used to update scene for a new frames, but also to initialize
785  * output video handles, which does need evaluated scene. */
787  oglrender->cfrao = scene->r.cfra;
788 
789  oglrender->write_still = is_write_still && !is_animation;
790  oglrender->is_animation = is_animation;
791  oglrender->color_depth = color_depth;
792 
794 
795  oglrender->is_sequencer = is_sequencer;
796  if (is_sequencer) {
797  oglrender->sseq = CTX_wm_space_seq(C);
798  ImBuf **ibufs_arr = static_cast<ImBuf **>(
799  MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
800  oglrender->seq_data.ibufs_arr = ibufs_arr;
801  }
802 
803  oglrender->prevsa = prevsa;
804  oglrender->prevar = prevar;
805 
806  if (is_view_context) {
807  /* so quad view renders camera */
808  ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region);
809 
810  oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
811 
812  /* MUST be cleared on exit */
813  memset(&oglrender->scene->customdata_mask_modal,
814  0,
815  sizeof(oglrender->scene->customdata_mask_modal));
817  C, oglrender->scene, oglrender->v3d, &oglrender->scene->customdata_mask_modal);
818 
819  /* apply immediately in case we're rendering from a script,
820  * running notifiers again will overwrite */
822  &oglrender->scene->customdata_mask_modal);
823  }
824 
825  /* create render */
826  oglrender->re = RE_NewSceneRender(scene);
827 
828  /* create image and image user */
829  oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
830  BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
831  BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
832 
833  oglrender->iuser.scene = scene;
834 
835  /* create render result */
836  RE_InitState(
837  oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
838 
839  /* create render views */
840  screen_opengl_views_setup(oglrender);
841 
842  /* wm vars */
843  oglrender->wm = wm;
844  oglrender->win = win;
845 
846  oglrender->totvideos = 0;
847  oglrender->mh = nullptr;
848  oglrender->movie_ctx_arr = nullptr;
849 
850  if (is_animation) {
851  if (is_render_keyed_only) {
852  gather_frames_to_render(C, oglrender);
853  }
854 
857  }
858  else {
859  oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_HIGH);
860  }
861  oglrender->pool_ok = true;
862  BLI_spin_init(&oglrender->reports_lock);
863  }
864  else {
865  oglrender->task_pool = nullptr;
866  }
867  oglrender->num_scheduled_frames = 0;
868  BLI_mutex_init(&oglrender->task_mutex);
869  BLI_condition_init(&oglrender->task_condition);
870 
871 #ifdef DEBUG_TIME
872  oglrender->time_start = PIL_check_seconds_timer();
873 #endif
874 
875  return true;
876 }
877 
878 static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
879 {
880  Scene *scene = oglrender->scene;
881  int i;
882 
883  if (oglrender->is_animation) {
884  /* Trickery part for movie output:
885  *
886  * We MUST write frames in an exact order, so we only let background
887  * thread to work on that, and main thread is simply waits for that
888  * thread to do all the dirty work.
889  *
890  * After this loop is done work_and_wait() will have nothing to do,
891  * so we don't run into wrong order of frames written to the stream.
892  */
894  BLI_mutex_lock(&oglrender->task_mutex);
895  while (oglrender->num_scheduled_frames > 0) {
896  BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
897  }
898  BLI_mutex_unlock(&oglrender->task_mutex);
899  }
901  BLI_task_pool_free(oglrender->task_pool);
902  BLI_spin_end(&oglrender->reports_lock);
903  }
904  BLI_mutex_end(&oglrender->task_mutex);
905  BLI_condition_end(&oglrender->task_condition);
906 
907 #ifdef DEBUG_TIME
908  printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
909 #endif
910 
911  MEM_SAFE_FREE(oglrender->render_frames);
912 
913  if (oglrender->mh) {
915  for (i = 0; i < oglrender->totvideos; i++) {
916  oglrender->mh->end_movie(oglrender->movie_ctx_arr[i]);
917  oglrender->mh->context_free(oglrender->movie_ctx_arr[i]);
918  }
919  }
920 
921  if (oglrender->movie_ctx_arr) {
922  MEM_freeN(oglrender->movie_ctx_arr);
923  }
924  }
925 
926  if (oglrender->timer) { /* exec will not have a timer */
927  Depsgraph *depsgraph = oglrender->depsgraph;
928  scene->r.cfra = oglrender->cfrao;
930 
931  WM_event_remove_timer(oglrender->wm, oglrender->win, oglrender->timer);
932  }
933 
934  WM_cursor_modal_restore(oglrender->win);
935 
937 
939  GPU_offscreen_free(oglrender->ofs);
941 
942  if (oglrender->is_sequencer) {
943  MEM_freeN(oglrender->seq_data.ibufs_arr);
944  }
945 
946  memset(&oglrender->scene->customdata_mask_modal,
947  0,
948  sizeof(oglrender->scene->customdata_mask_modal));
949 
950  CTX_wm_area_set(C, oglrender->prevsa);
951  CTX_wm_region_set(C, oglrender->prevar);
952 
953  MEM_delete(oglrender);
954 }
955 
957 {
958  screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
959 }
960 
961 /* share between invoke and exec */
963 {
964  /* initialize animation */
965  OGLRender *oglrender;
966  Scene *scene;
967 
968  oglrender = static_cast<OGLRender *>(op->customdata);
969  scene = oglrender->scene;
971 
972  oglrender->reports = op->reports;
973 
975  size_t width, height;
976  int i;
977 
979  &scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
981 
982  if (oglrender->mh == nullptr) {
983  BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
984  screen_opengl_render_end(C, oglrender);
985  return false;
986  }
987 
988  oglrender->movie_ctx_arr = static_cast<void **>(
989  MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"));
990 
991  for (i = 0; i < oglrender->totvideos; i++) {
992  Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
993  const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, i);
994 
995  oglrender->movie_ctx_arr[i] = oglrender->mh->context_create();
996  if (!oglrender->mh->start_movie(oglrender->movie_ctx_arr[i],
997  scene_eval,
998  &scene->r,
999  oglrender->sizex,
1000  oglrender->sizey,
1001  oglrender->reports,
1002  PRVRANGEON != 0,
1003  suffix)) {
1004  screen_opengl_render_end(C, oglrender);
1005  return false;
1006  }
1007  }
1008  }
1009 
1010  oglrender->cfrao = scene->r.cfra;
1011  oglrender->nfra = PSFRA;
1012  scene->r.cfra = PSFRA;
1013 
1014  return true;
1015 }
1016 
1020 };
1021 
1022 static void write_result(TaskPool *__restrict pool, WriteTaskData *task_data)
1023 {
1025  Scene *scene = &task_data->tmp_scene;
1026  RenderResult *rr = task_data->rr;
1028  const int cfra = scene->r.cfra;
1029  bool ok;
1030  /* Don't attempt to write if we've got an error. */
1031  if (!oglrender->pool_ok) {
1032  RE_FreeRenderResult(rr);
1033  BLI_mutex_lock(&oglrender->task_mutex);
1034  oglrender->num_scheduled_frames--;
1036  BLI_mutex_unlock(&oglrender->task_mutex);
1037  return;
1038  }
1039  /* Construct local thread0safe copy of reports structure which we can
1040  * safely pass to the underlying functions.
1041  */
1042  ReportList reports;
1043  BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
1044  /* Do actual save logic here, depending on the file format.
1045  *
1046  * NOTE: We have to construct temporary scene with proper scene->r.cfra.
1047  * This is because underlying calls do not use r.cfra but use scene
1048  * for that.
1049  */
1050  if (is_movie) {
1051  ok = RE_WriteRenderViewsMovie(&reports,
1052  rr,
1053  scene,
1054  &scene->r,
1055  oglrender->mh,
1056  oglrender->movie_ctx_arr,
1057  oglrender->totvideos,
1058  PRVRANGEON != 0);
1059  }
1060  else {
1061  /* TODO(sergey): We can in theory save some CPU ticks here because we
1062  * calculate file name again here.
1063  */
1064  char name[FILE_MAX];
1066  scene->r.pic,
1067  BKE_main_blendfile_path(oglrender->bmain),
1068  cfra,
1069  &scene->r.im_format,
1070  (scene->r.scemode & R_EXTENSION) != 0,
1071  true,
1072  nullptr);
1073 
1075  ok = BKE_image_render_write(nullptr, rr, scene, true, name);
1076  if (!ok) {
1077  BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
1078  }
1079  }
1080  if (reports.list.first != nullptr) {
1081  BLI_spin_lock(&oglrender->reports_lock);
1082  for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
1083  report = report->next) {
1084  BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
1085  }
1086  BLI_spin_unlock(&oglrender->reports_lock);
1087  }
1088  if (!ok) {
1089  oglrender->pool_ok = false;
1090  }
1091  RE_FreeRenderResult(rr);
1092  BLI_mutex_lock(&oglrender->task_mutex);
1093  oglrender->num_scheduled_frames--;
1095  BLI_mutex_unlock(&oglrender->task_mutex);
1096 }
1097 
1098 static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
1099 {
1100  /* Isolate task so that multithreaded image operations don't cause this thread to start
1101  * writing another frame. If that happens we may reach the MAX_SCHEDULED_FRAMES limit,
1102  * and cause the render thread and writing threads to deadlock waiting for each other. */
1103  WriteTaskData *task_data = (WriteTaskData *)task_data_v;
1104  blender::threading::isolate_task([&] { write_result(pool, task_data); });
1105 }
1106 
1107 static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
1108 {
1109  if (!oglrender->pool_ok) {
1110  RE_FreeRenderResult(rr);
1111  return false;
1112  }
1113  Scene *scene = oglrender->scene;
1114  WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data");
1115  task_data->rr = rr;
1116  memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene));
1117  BLI_mutex_lock(&oglrender->task_mutex);
1118  oglrender->num_scheduled_frames++;
1119  if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) {
1120  BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
1121  }
1122  BLI_mutex_unlock(&oglrender->task_mutex);
1123  BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
1124  return true;
1125 }
1126 
1128 {
1129  OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1130  Scene *scene = oglrender->scene;
1131  Depsgraph *depsgraph = oglrender->depsgraph;
1132  char name[FILE_MAX];
1133  bool ok = false;
1134  const bool view_context = (oglrender->v3d != nullptr);
1135  bool is_movie;
1136  RenderResult *rr;
1137 
1138  /* go to next frame */
1139  if (scene->r.cfra < oglrender->nfra) {
1140  scene->r.cfra++;
1141  }
1142  while (scene->r.cfra < oglrender->nfra) {
1144  scene->r.cfra++;
1145  }
1146 
1148 
1149  if (!is_movie) {
1151  scene->r.pic,
1152  BKE_main_blendfile_path(oglrender->bmain),
1153  scene->r.cfra,
1154  &scene->r.im_format,
1155  (scene->r.scemode & R_EXTENSION) != 0,
1156  true,
1157  nullptr);
1158 
1159  if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
1160  BLI_spin_lock(&oglrender->reports_lock);
1161  BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
1162  BLI_spin_unlock(&oglrender->reports_lock);
1163  ok = true;
1164  goto finally;
1165  }
1166  }
1167 
1168  WM_cursor_time(oglrender->win, scene->r.cfra);
1169 
1171 
1172  if (view_context) {
1173  if (oglrender->rv3d->persp == RV3D_CAMOB && oglrender->v3d->camera &&
1174  oglrender->v3d->scenelock) {
1175  /* since BKE_scene_graph_update_for_newframe() is used rather
1176  * then ED_update_for_newframe() the camera needs to be set */
1178  oglrender->v3d->camera = scene->camera;
1179  }
1180  }
1181  }
1182  else {
1184  }
1185 
1186  if (oglrender->render_frames == nullptr ||
1187  BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA)) {
1188  /* render into offscreen buffer */
1189  screen_opengl_render_apply(C, oglrender);
1190  }
1191 
1192  /* save to disk */
1193  rr = RE_AcquireResultRead(oglrender->re);
1194  {
1195  RenderResult *new_rr = RE_DuplicateRenderResult(rr);
1196  RE_ReleaseResult(oglrender->re);
1197 
1198  ok = schedule_write_result(oglrender, new_rr);
1199  }
1200 
1201 finally: /* Step the frame and bail early if needed */
1202 
1203  /* go to next frame */
1204  oglrender->nfra += scene->r.frame_step;
1205 
1206  /* stop at the end or on error */
1207  if (scene->r.cfra >= PEFRA || !ok) {
1208  screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1209  return false;
1210  }
1211 
1212  return true;
1213 }
1214 
1215 static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
1216 {
1217  OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
1218  const bool anim = RNA_boolean_get(op->ptr, "animation");
1219  bool ret;
1220 
1221  switch (event->type) {
1222  case EVT_ESCKEY:
1223  /* cancel */
1224  oglrender->pool_ok = false; /* Flag pool for cancel. */
1225  screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1226  return OPERATOR_FINISHED;
1227  case TIMER:
1228  /* render frame? */
1229  if (oglrender->timer == event->customdata) {
1230  break;
1231  }
1233  default:
1234  /* nothing to do */
1235  return OPERATOR_RUNNING_MODAL;
1236  }
1237 
1238  /* run first because screen_opengl_render_anim_step can free oglrender */
1240 
1241  if (anim == 0) {
1242  screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
1243  screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1244  return OPERATOR_FINISHED;
1245  }
1246 
1248 
1249  /* stop at the end or on error */
1250  if (ret == false) {
1251  return OPERATOR_FINISHED;
1252  }
1253 
1254  return OPERATOR_RUNNING_MODAL;
1255 }
1256 
1258 {
1259  OGLRender *oglrender;
1260  const bool anim = RNA_boolean_get(op->ptr, "animation");
1261 
1262  if (!screen_opengl_render_init(C, op)) {
1263  return OPERATOR_CANCELLED;
1264  }
1265 
1266  if (anim) {
1267  if (!screen_opengl_render_anim_init(C, op)) {
1268  return OPERATOR_CANCELLED;
1269  }
1270  }
1271 
1272  oglrender = static_cast<OGLRender *>(op->customdata);
1273  render_view_open(C, event->xy[0], event->xy[1], op->reports);
1274 
1275  /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
1276  oglrender->win = CTX_wm_window(C);
1277 
1279  oglrender->timer = WM_event_add_timer(oglrender->wm, oglrender->win, TIMER, 0.01f);
1280 
1281  return OPERATOR_RUNNING_MODAL;
1282 }
1283 
1284 /* executes blocking render */
1286 {
1287  const bool is_animation = RNA_boolean_get(op->ptr, "animation");
1288 
1289  if (!screen_opengl_render_init(C, op)) {
1290  return OPERATOR_CANCELLED;
1291  }
1292 
1293  if (!is_animation) { /* same as invoke */
1294  /* render image */
1295  screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
1296  screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
1297 
1298  return OPERATOR_FINISHED;
1299  }
1300 
1301  bool ret = true;
1302 
1303  if (!screen_opengl_render_anim_init(C, op)) {
1304  return OPERATOR_CANCELLED;
1305  }
1306 
1307  while (ret) {
1309  }
1310 
1311  /* no redraw needed, we leave state as we entered it */
1312  // ED_update_for_newframe(C);
1314 
1315  return OPERATOR_FINISHED;
1316 }
1317 
1319  struct wmOperatorType *UNUSED(ot),
1320  struct PointerRNA *ptr)
1321 {
1322  if (!RNA_boolean_get(ptr, "animation")) {
1323  return nullptr;
1324  }
1325 
1326  if (RNA_boolean_get(ptr, "render_keyed_only")) {
1327  return BLI_strdup(TIP_(
1328  "Render the viewport for the animation range of this scene, but only render keyframes of "
1329  "selected objects"));
1330  }
1331 
1332  return BLI_strdup(TIP_("Render the viewport for the animation range of this scene"));
1333 }
1334 
1336 {
1337  PropertyRNA *prop;
1338 
1339  /* identifiers */
1340  ot->name = "Viewport Render";
1341  ot->description = "Take a snapshot of the active viewport";
1342  ot->idname = "RENDER_OT_opengl";
1343 
1344  /* api callbacks */
1347  ot->exec = screen_opengl_render_exec; /* blocking */
1350 
1352 
1353  prop = RNA_def_boolean(ot->srna,
1354  "animation",
1355  false,
1356  "Animation",
1357  "Render files from the animation range of this scene");
1359 
1360  prop = RNA_def_boolean(ot->srna,
1361  "render_keyed_only",
1362  false,
1363  "Render Keyframes Only",
1364  "Render only those frames where selected objects have a key in their "
1365  "animation data. Only used when rendering animation");
1367 
1368  prop = RNA_def_boolean(
1369  ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
1371  prop = RNA_def_boolean(
1372  ot->srna,
1373  "write_still",
1374  false,
1375  "Write Image",
1376  "Save rendered the image to the output path (used only when animation is disabled)");
1378  prop = RNA_def_boolean(ot->srna,
1379  "view_context",
1380  true,
1381  "View Context",
1382  "Use the current 3D view for rendering, else use scene settings");
1384 }
struct AnimData * BKE_animdata_from_id(const struct ID *id)
Camera data-block and utility functions.
struct Object * BKE_camera_multiview_render(const struct Scene *scene, struct Object *camera, const char *viewname)
struct WorkSpace * CTX_wm_workspace(const bContext *C)
Definition: context.c:728
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:1009
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct SpaceSeq * CTX_wm_space_seq(const bContext *C)
Definition: context.c:851
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:997
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
#define CTX_DATA_END
Definition: BKE_context.h:278
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
CustomData interface, see also DNA_customdata_types.h.
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition: customdata.cc:77
int BKE_fcurve_bezt_binarysearch_index(const struct BezTriple array[], float frame, int arraylen, bool *r_replace)
Definition: fcurve.c:561
@ G_FLAG_RENDER_VIEWPORT
Definition: BKE_global.h:148
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot)
void BKE_image_partial_update_mark_full_update(struct Image *image)
Mark the whole image to be updated.
struct Image * BKE_image_ensure_viewer(struct Main *bmain, int type, const char *name)
#define IMA_SIGNAL_FREE
Definition: BKE_image.h:130
void BKE_image_signal(struct Main *bmain, struct Image *ima, struct ImageUser *iuser, int signal)
void BKE_render_result_stamp_info(struct Scene *scene, struct Object *camera, struct RenderResult *rr, bool allocate_only)
void BKE_image_stamp_buf(struct Scene *scene, struct Object *camera, const struct StampData *stamp_data_template, unsigned char *rect, float *rectf, int width, int height, int channels)
void BKE_image_path_from_imformat(char *string, const char *base, const char *relbase, int frame, const struct ImageFormatData *im_format, bool use_ext, bool use_frames, const char *suffix)
bool BKE_imtype_is_movie(char imtype)
bool BKE_image_render_write(struct ReportList *reports, struct RenderResult *rr, const struct Scene *scene, const bool stamp, const char *filepath_basis)
void BKE_library_foreach_ID_link(struct Main *bmain, struct ID *id, LibraryIDLinkCallback callback, void *user_data, int flag)
Definition: lib_query.c:350
@ IDWALK_RECURSE
@ IDWALK_CB_LOOPBACK
Definition: BKE_lib_query.h:54
@ IDWALK_RET_STOP_RECURSION
Definition: BKE_lib_query.h:87
@ IDWALK_RET_NOP
Definition: BKE_lib_query.h:83
const char * BKE_main_blendfile_path(const struct Main *bmain) ATTR_NONNULL()
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
void BKE_reports_init(ReportList *reports, int flag)
Definition: report.c:50
bool BKE_scene_multiview_is_stereo3d(const struct RenderData *rd)
int BKE_scene_multiview_num_videos_get(const struct RenderData *rd)
bool BKE_scene_multiview_is_render_view_active(const struct RenderData *rd, const struct SceneRenderView *srv)
void BKE_render_resolution(const struct RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition: scene.cc:2960
bool BKE_scene_camera_switch_update(struct Scene *scene)
Definition: scene.cc:2295
void BKE_scene_graph_update_for_newframe(struct Depsgraph *depsgraph)
Definition: scene.cc:2728
int BKE_scene_multiview_num_views_get(const struct RenderData *rd)
const char * BKE_scene_multiview_view_id_suffix_get(const struct RenderData *rd, int view_id)
void BKE_scene_multiview_videos_dimensions_get(const struct RenderData *rd, size_t width, size_t height, size_t *r_width, size_t *r_height)
bMovieHandle * BKE_movie_handle_get(char imtype)
Definition: writeavi.c:98
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
#define BLI_BITMAP_TEST_BOOL(_bitmap, _index)
Definition: BLI_bitmap.h:74
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
#define ATTR_FALLTHROUGH
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:314
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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 * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
@ TASK_PRIORITY_HIGH
Definition: BLI_task.h:57
void * BLI_task_pool_user_data(TaskPool *pool)
Definition: task_pool.cc:525
void BLI_task_pool_work_and_wait(TaskPool *pool)
Definition: task_pool.cc:480
TaskPool * BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority)
Definition: task_pool.cc:435
TaskPool * BLI_task_pool_create(void *userdata, eTaskPriority priority)
Definition: task_pool.cc:390
void BLI_task_pool_free(TaskPool *pool)
Definition: task_pool.cc:440
void BLI_task_pool_push(TaskPool *pool, TaskRunFunction run, void *taskdata, bool free_taskdata, TaskFreeFunction freedata)
Definition: task_pool.cc:459
void BLI_condition_notify_all(ThreadCondition *cond)
Definition: threads.cc:594
pthread_spinlock_t SpinLock
Definition: BLI_threads.h:110
void BLI_mutex_end(ThreadMutex *mutex)
Definition: threads.cc:388
void BLI_condition_wait(ThreadCondition *cond, ThreadMutex *mutex)
Definition: threads.cc:579
void BLI_mutex_init(ThreadMutex *mutex)
Definition: threads.cc:368
pthread_cond_t ThreadCondition
Definition: BLI_threads.h:150
void BLI_condition_end(ThreadCondition *cond)
Definition: threads.cc:599
void BLI_condition_init(ThreadCondition *cond)
Definition: threads.cc:574
void BLI_mutex_lock(ThreadMutex *mutex)
Definition: threads.cc:373
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition: threads.cc:378
void BLI_spin_init(SpinLock *spin)
Definition: threads.cc:419
void BLI_spin_unlock(SpinLock *spin)
Definition: threads.cc:452
void BLI_spin_lock(SpinLock *spin)
Definition: threads.cc:433
pthread_mutex_t ThreadMutex
Definition: BLI_threads.h:82
void BLI_spin_end(SpinLock *spin)
Definition: threads.cc:467
#define UNUSED_FUNCTION(x)
#define UNUSED(x)
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
ID_Type
Definition: DNA_ID_enums.h:44
@ ID_WM
Definition: DNA_ID_enums.h:72
@ ID_CA
Definition: DNA_ID_enums.h:56
@ ID_AR
Definition: DNA_ID_enums.h:66
@ ID_MC
Definition: DNA_ID_enums.h:73
@ ID_CF
Definition: DNA_ID_enums.h:78
@ ID_LI
Definition: DNA_ID_enums.h:46
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_VO
Definition: DNA_ID_enums.h:83
@ ID_WS
Definition: DNA_ID_enums.h:79
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_KE
Definition: DNA_ID_enums.h:58
@ ID_TXT
Definition: DNA_ID_enums.h:62
@ ID_SO
Definition: DNA_ID_enums.h:64
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_LS
Definition: DNA_ID_enums.h:75
@ ID_MSK
Definition: DNA_ID_enums.h:74
@ ID_GD
Definition: DNA_ID_enums.h:71
@ ID_CV
Definition: DNA_ID_enums.h:81
@ ID_PAL
Definition: DNA_ID_enums.h:76
@ ID_BR
Definition: DNA_ID_enums.h:69
@ ID_LP
Definition: DNA_ID_enums.h:80
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_SIM
Definition: DNA_ID_enums.h:84
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_AC
Definition: DNA_ID_enums.h:67
@ ID_SCR
Definition: DNA_ID_enums.h:60
@ ID_CU_LEGACY
Definition: DNA_ID_enums.h:49
@ ID_VF
Definition: DNA_ID_enums.h:61
@ ID_ME
Definition: DNA_ID_enums.h:48
@ ID_IP
Definition: DNA_ID_enums.h:57
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_SPK
Definition: DNA_ID_enums.h:63
@ ID_MB
Definition: DNA_ID_enums.h:50
@ ID_LT
Definition: DNA_ID_enums.h:54
@ ID_OB
Definition: DNA_ID_enums.h:47
@ ID_PA
Definition: DNA_ID_enums.h:70
@ ID_PT
Definition: DNA_ID_enums.h:82
@ ID_PC
Definition: DNA_ID_enums.h:77
@ IMA_TYPE_R_RESULT
#define IMA_SHOW_STEREO
eDrawType
@ OB_SOLID
Object is a sort of wrapper for general info.
#define R_STAMP_ALL
#define R_EXTENSION
#define R_MULTIVIEW
#define PSFRA
#define R_NO_OVERWRITE
#define V3D_CAMERA_SCENE(scene, v3d)
#define R_STAMP_DRAW
eImageFormatDepth
@ R_IMF_CHAN_DEPTH_32
@ R_ADDSKY
@ R_ALPHAPREMUL
#define PRVRANGEON
#define PEFRA
@ SEQ_RENDER_SIZE_SCENE
@ SPACE_SEQ
@ SEQ_PREVIEW_SHOW_GPENCIL
@ V3D_OFSDRAW_SHOW_ANNOTATION
#define RV3D_CAMOB
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void DRW_opengl_context_enable(void)
void DRW_opengl_context_disable(void)
bool ED_operator_screenactive(struct bContext *C)
Definition: screen_ops.c:119
bool ED_view3d_context_activate(struct bContext *C)
Definition: view3d_utils.c:219
bool ED_view3d_context_user_region(struct bContext *C, struct View3D **r_v3d, struct ARegion **r_region)
Definition: space_view3d.c:98
void ED_view3d_datamask(const struct bContext *C, const struct Scene *scene, const struct View3D *v3d, struct CustomData_MeshMasks *r_cddata_masks)
struct ImBuf * ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph, struct Scene *scene, eDrawType drawtype, struct View3D *v3d, struct ARegion *region, int sizex, int sizey, eImBufFlags imbuf_flag, int alpha_mode, const char *viewname, bool restore_rv3d_mats, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1831
struct ImBuf * ED_view3d_draw_offscreen_imbuf_simple(struct Depsgraph *depsgraph, struct Scene *scene, struct View3DShading *shading_override, eDrawType drawtype, struct Object *camera, int width, int height, eImBufFlags imbuf_flags, eV3DOffscreenDrawFlag draw_flags, int alpha_mode, const char *viewname, struct GPUOffScreen *ofs, char err_out[256])
Definition: view3d_draw.c:1980
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
void GPU_matrix_reset(void)
Definition: gpu_matrix.cc:86
void GPU_matrix_translate_2f(float x, float y)
Definition: gpu_matrix.cc:174
@ GPU_DATA_UBYTE
Definition: GPU_texture.h:174
void imb_freerectfloatImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:80
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:696
Contains defines and structs used throughout the imbuf module.
@ IB_DISPLAY_BUFFER_INVALID
@ IB_rectfloat
@ IB_rect
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 Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise 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
Platform independent time functions.
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
#define C
Definition: RandGen.cpp:25
@ WM_JOB_TYPE_RENDER
Definition: WM_api.h:1349
#define ND_RENDER_RESULT
Definition: WM_types.h:394
#define NC_SCENE
Definition: WM_types.h:328
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)
Scene scene
const Depsgraph * depsgraph
SyclQueue void * dest
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img GPU_RGBA16F
void GPU_offscreen_free(GPUOffScreen *ofs)
void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
GPUOffScreen * GPU_offscreen_create(int width, int height, bool depth, eGPUTextureFormat format, char err_out[256])
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat format, void *pixels)
void GPU_clear_color(float red, float green, float blue, float alpha)
void GPU_clear_depth(float depth)
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
void RE_SetOverrideCamera(Render *re, Object *cam_ob)
Definition: initrender.c:156
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
void isolate_task(const Function &function)
Definition: BLI_task.hh:125
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
RenderResult * RE_AcquireResultRead(Render *re)
Definition: pipeline.c:314
void RE_ReleaseResultImage(Render *re)
Definition: pipeline.c:474
bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh, void **movie_ctx_arr, const int totvideos, bool preview)
Definition: pipeline.c:1954
void RE_FreeRenderResult(RenderResult *rr)
Definition: pipeline.c:233
Render * RE_NewSceneRender(const Scene *scene)
Definition: pipeline.c:558
void RE_InitState(Render *re, Render *source, RenderData *rd, ListBase *render_layers, ViewLayer *single_layer, int winx, int winy, rcti *disprect)
Definition: pipeline.c:728
void RE_ReleaseResult(Render *re)
Definition: pipeline.c:351
const char * RE_GetActiveRenderView(Render *re)
Definition: pipeline.c:1671
RenderResult * RE_AcquireResultWrite(Render *re)
Definition: pipeline.c:324
void RE_SetActiveRenderView(Render *re, const char *viewname)
Definition: pipeline.c:1666
return ret
ImBuf * SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown)
Definition: render.c:1925
void SEQ_render_new_render_data(Main *bmain, struct Depsgraph *depsgraph, Scene *scene, int rectx, int recty, int preview_render_size, int for_render, SeqRenderData *r_context)
Definition: render.c:205
struct ScrArea * render_view_open(struct bContext *C, int mx, int my, struct ReportList *reports)
Definition: render_view.cc:120
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 screen_opengl_render_end(bContext *C, OGLRender *oglrender)
static void UNUSED_FUNCTION() addAlphaOverFloat(float dest[4], const float source[4])
static int screen_opengl_render_exec(bContext *C, wmOperator *op)
static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define MAX_SCHEDULED_FRAMES
static char * screen_opengl_render_description(struct bContext *UNUSED(C), struct wmOperatorType *UNUSED(ot), struct PointerRNA *ptr)
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)
RenderView * RE_RenderViewGetById(RenderResult *rr, const int view_id)
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)
Definition: rna_access.c:4874
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
static bool is_movie(wmDrag *drag)
void * regiondata
bAction * action
float vec[3][3]
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
int userflags
unsigned int * rect
float * rect_float
struct Scene * scene
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
Main * bmain
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
WorkSpace * workspace
wmWindowManager * wm
bool is_animation
void ** movie_ctx_arr
ScrArea * prevsa
ARegion * region
ReportList * reports
bMovieHandle * mh
ImageUser iuser
eImageFormatDepth color_depth
struct OGLRender::@505 seq_data
Image * ima
GPUOffScreen * ofs
SpaceSeq * sseq
View3D * v3d
wmWindow * win
bool is_sequencer
struct ImageFormatData im_format
char pic[1024]
ListBase views
ListBase views
Definition: RE_pipeline.h:125
struct RenderView * prev
Definition: RE_pipeline.h:50
float * rectf
Definition: RE_pipeline.h:54
float * rectz
Definition: RE_pipeline.h:56
int * rect32
Definition: RE_pipeline.h:58
struct RenderView * next
Definition: RE_pipeline.h:50
char name[64]
Definition: RE_pipeline.h:51
struct Report * next
struct SceneRenderView * next
struct CustomData_MeshMasks customdata_mask
struct RenderData r
ListBase view_layers
struct CustomData_MeshMasks customdata_mask_modal
struct Object * camera
short chanshown
struct bGPdata * gpd
struct Object * camera
short scenelock
View3DShading shading
RenderResult * rr
Definition: IMB_anim.h:71
ListBase curves
ListBase layers
struct AnimData * adt
void(* end_movie)(void *context_v)
Definition: BKE_writeavi.h:38
int(* start_movie)(void *context_v, const struct Scene *scene, struct RenderData *rd, int rectx, int recty, struct ReportList *reports, bool preview, const char *suffix)
Definition: BKE_writeavi.h:21
void(* context_free)(void *context_v)
Definition: BKE_writeavi.h:47
void *(* context_create)(void)
Definition: BKE_writeavi.h:46
int xy[2]
Definition: WM_types.h:682
short type
Definition: WM_types.h:678
void * customdata
Definition: WM_types.h:715
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
char *(* get_description)(struct bContext *C, struct wmOperatorType *, struct PointerRNA *)
Definition: WM_types.h:966
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
double PIL_check_seconds_timer(void)
Definition: time.c:64
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:200
void WM_cursor_time(wmWindow *win, int nr)
Definition: wm_cursors.c:317
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.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner)
Definition: wm_jobs.c:563
bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type)
Definition: wm_jobs.c:214
void wmOrtho2(float x1, float x2, float y1, float y2)
Definition: wm_subwindow.c:84
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1682
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1630