From c0ef4e9b788b8db433bf3e92bd19ee00f86f9866 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Thu, 26 Mar 2015 14:49:59 +0100 Subject: Fix T44122, rendering OpenGL preview movie with audio has wrong audio range and extra frames. Issue here is that the movie backend would unconditionally use the start frame of the scene instead of the preview frame. Solved by passing an explicit "preview" argument. Strictly speaking, the preview argument is part of the renderdata struct, that is also passed to the code, but when rendering the final result we want to unconditionally render the full range regardless of the preview setting of the render structure. However, OpenGL rendering does use the preview range so we need to account for that when making those exports. This is also a nice chance to correct the filenames, which still used the full range. --- source/blender/render/intern/source/pipeline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index b397db7c31b..fe51696b16c 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3025,7 +3025,8 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri height = re->recty; } - if (!mh->start_movie(scene, &re->r, width, height, re->reports)) + /* last argument here depends on users really, but no users using preview have been found so far */ + if (!mh->start_movie(scene, &re->r, width, height, re->reports, false)) G.is_break = true; } -- cgit v1.2.3 From 59b578e320313958be69400f34fe3d0dd2ae865c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 28 Mar 2015 02:36:00 +1100 Subject: Cleanup: use const char for stats arg --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index fe51696b16c..b18edd4c61e 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1956,7 +1956,7 @@ static void ntree_render_scenes(Render *re) } /* bad call... need to think over proper method still */ -static void render_composit_stats(void *UNUSED(arg), char *str) +static void render_composit_stats(void *UNUSED(arg), const char *str) { R.i.infostr = str; R.stats_draw(R.sdh, &R.i); -- cgit v1.2.3 From f87d7c605dcfb1a439635f6856cbbd50904ae0b6 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Thu, 2 Apr 2015 09:08:25 -0300 Subject: Fix error messages for RE_layer_load_from_file() and RE_layer_load_from_file() --- source/blender/render/intern/source/pipeline.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index b18edd4c61e..49119505cab 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3261,25 +3261,25 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char IMB_freeImBuf(ibuf_clip); } else { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to allocate clip buffer '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: failed to allocate clip buffer '%s'", filename); } } else { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: incorrect dimensions for partial copy '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: incorrect dimensions for partial copy '%s'", filename); } } IMB_freeImBuf(ibuf); } else { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: failed to load '%s'", filename); } } void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename) { if (!render_result_exr_file_read_path(result, NULL, filename)) { - BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "RE_result_load_from_file: failed to load '%s'", filename); return; } } -- cgit v1.2.3 From 64fed6841a48d6d8f1dfdee65bb3bbfb38654026 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 2 Apr 2015 14:51:37 +0200 Subject: Cleanup: followup to rBf87d7c605dcfb - use __func__ instead of literal func name in string. Since we are already using BKE_reportf... This way, no more issue if/when we copy/paste or rename that! --- source/blender/render/intern/source/pipeline.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 49119505cab..4bde3dddaff 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3261,25 +3261,25 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char IMB_freeImBuf(ibuf_clip); } else { - BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: failed to allocate clip buffer '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filename); } } else { - BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: incorrect dimensions for partial copy '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: incorrect dimensions for partial copy '%s'", __func__, filename); } } IMB_freeImBuf(ibuf); } else { - BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: failed to load '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename); } } void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename) { if (!render_result_exr_file_read_path(result, NULL, filename)) { - BKE_reportf(reports, RPT_ERROR, "RE_result_load_from_file: failed to load '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename); return; } } -- cgit v1.2.3 From d5f1b9c2223333e03f2e4994171ad9df8c1c4f21 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 6 Apr 2015 10:40:12 -0300 Subject: Multi-View and Stereo 3D Official Documentation: http://www.blender.org/manual/render/workflows/multiview.html Implemented Features ==================== Builtin Stereo Camera * Convergence Mode * Interocular Distance * Convergence Distance * Pivot Mode Viewport * Cameras * Plane * Volume Compositor * View Switch Node * Image Node Multi-View OpenEXR support Sequencer * Image/Movie Strips 'Use Multiview' UV/Image Editor * Option to see Multi-View images in Stereo-3D or its individual images * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images I/O * Save/Open Multi-View (OpenEXR, Stereo3D, individual views) images Scene Render Views * Ability to have an arbitrary number of views in the scene Missing Bits ============ First rule of Multi-View bug report: If something is not working as it should *when Views is off* this is a severe bug, do mention this in the report. Second rule is, if something works *when Views is off* but doesn't (or crashes) when *Views is on*, this is a important bug. Do mention this in the report. Everything else is likely small todos, and may wait until we are sure none of the above is happening. Apart from that there are those known issues: * Compositor Image Node poorly working for Multi-View OpenEXR (this was working prefectly before the 'Use Multi-View' functionality) * Selecting camera from Multi-View when looking from camera is problematic * Animation Playback (ctrl+F11) doesn't support stereo formats * Wrong filepath when trying to play back animated scene * Viewport Rendering doesn't support Multi-View * Overscan Rendering * Fullscreen display modes need to warn the user * Object copy should be aware of views suffix Acknowledgments =============== * Francesco Siddi for the help with the original feature specs and design * Brecht Van Lommel for the original review of the code and design early on * Blender Foundation for the Development Fund to support the project wrap up Final patch reviewers: * Antony Riakiotakis (psy-fi) * Campbell Barton (ideasman42) * Julian Eisel (Severin) * Sergey Sharybin (nazgul) * Thomas Dinged (dingto) Code contributors of the original branch in github: * Alexey Akishin * Gabriel Caraballo --- source/blender/render/intern/source/pipeline.c | 1099 +++++++++++++++++------- 1 file changed, 806 insertions(+), 293 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 4bde3dddaff..25adb4db4f7 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -70,6 +70,7 @@ #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */ +#include "BKE_object.h" #include "PIL_time.h" #include "IMB_colormanagement.h" @@ -131,7 +132,7 @@ Render R; /* ********* alloc and free ******** */ -static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override); +static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override); static volatile int g_break = 0; static int thread_break(void *UNUSED(arg)) @@ -190,14 +191,23 @@ void RE_FreeRenderResult(RenderResult *res) render_result_free(res); } -float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) +float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname) { RenderPass *rpass; - - for (rpass = rl->passes.first; rpass; rpass = rpass->next) - if (rpass->passtype == passtype) - return rpass->rect; - return NULL; + float *rect = NULL; + + for (rpass = rl->passes.last; rpass; rpass = rpass->prev) { + if (rpass->passtype == passtype) { + rect = rpass->rect; + + if (viewname == NULL) + break; + else if (strcmp(rpass->view, viewname) == 0) + break; + } + } + + return rect; } RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) @@ -307,8 +317,69 @@ Scene *RE_GetScene(Render *re) return NULL; } +/** + * Same as #RE_AcquireResultImage but creating the necessary views to store the result + * fill provided result struct with a copy of thew views of what is done so far the + * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews +*/ +void RE_AcquireResultImageViews(Render *re, RenderResult *rr) +{ + memset(rr, 0, sizeof(RenderResult)); + + if (re) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ); + + if (re->result) { + RenderLayer *rl; + RenderView *rv, *rview; + + rr->rectx = re->result->rectx; + rr->recty = re->result->recty; + + /* creates a temporary duplication of views */ + render_result_views_shallowcopy(rr, re->result); + + rv = rr->views.first; + + rr->have_combined = (rv->rectf != NULL); + + /* active layer */ + rl = render_get_active_layer(re, re->result); + + if (rl) { + if (rv->rectf == NULL) { + for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) { + rview->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rview->name); + } + } + + if (rv->rectz == NULL) { + for (rview = (RenderView *)rr->views.first; rview; rview = rview->next) { + rview->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rview->name); + } + } + } + + rr->layers = re->result->layers; + rr->xof = re->disprect.xmin; + rr->yof = re->disprect.ymin; + } + } +} + +/* clear temporary renderresult struct */ +void RE_ReleaseResultImageViews(Render *re, RenderResult *rr) +{ + if (re) { + if (rr) { + render_result_views_shallowdelete(rr); + } + BLI_rw_mutex_unlock(&re->resultmutex); + } +} + /* fill provided result struct with what's currently active or done */ -void RE_AcquireResultImage(Render *re, RenderResult *rr) +void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) { memset(rr, 0, sizeof(RenderResult)); @@ -317,27 +388,35 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr) if (re->result) { RenderLayer *rl; + RenderView *rv; rr->rectx = re->result->rectx; rr->recty = re->result->recty; - rr->rectf = re->result->rectf; - rr->rectz = re->result->rectz; - rr->rect32 = re->result->rect32; - + /* actview view */ + rv = BLI_findlink(&re->result->views, view_id); + if (rv == NULL) + rv = (RenderView *)re->result->views.first; + + rr->rectf = rv ? rv->rectf : NULL; + rr->rectz = rv ? rv->rectz : NULL; + rr->rect32 = rv ? rv->rect32 : NULL; + /* active layer */ rl = render_get_active_layer(re, re->result); - if (rl) { - if (rr->rectf == NULL) - rr->rectf = rl->rectf; - if (rr->rectz == NULL) - rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z); + if (rl && rv) { + if (rv->rectf == NULL) + rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name); + + if (rv->rectz == NULL) + rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name); } - rr->have_combined = (re->result->rectf != NULL); + rr->have_combined = rv ? (rv->rectf != NULL) : false; rr->layers = re->result->layers; - + rr->views = re->result->views; + rr->xof = re->disprect.xmin; rr->yof = re->disprect.ymin; } @@ -354,17 +433,18 @@ void RE_ReleaseResultImage(Render *re) void RE_ResultGet32(Render *re, unsigned int *rect) { RenderResult rres; - - RE_AcquireResultImage(re, &rres); - render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); + const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname); + + RE_AcquireResultImage(re, &rres, view_id); + render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, 0); RE_ReleaseResultImage(re); } /* caller is responsible for allocating rect in correct size! */ /* Only for acquired results, for lock */ -void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect) +void RE_AcquiredResultGet32(Render *re, RenderResult *result, unsigned int *rect, const int view_id) { - render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings); + render_result_rect_get_pixels(result, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id); } RenderStats *RE_GetStats(Render *re) @@ -683,6 +763,8 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, RE_init_threadcount(re); } +/* This function is only called by view3d rendering, which doesn't support + * multiview at the moment. so handle only one view here */ static void render_result_rescale(Render *re) { RenderResult *result = re->result; @@ -694,7 +776,7 @@ static void render_result_rescale(Render *re) if (src_rectf == NULL) { RenderLayer *rl = render_get_active_layer(re, re->result); if (rl != NULL) { - src_rectf = rl->rectf; + src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); } } @@ -704,7 +786,8 @@ static void render_result_rescale(Render *re) &re->disprect, 0, RR_USE_MEM, - RR_ALL_LAYERS); + RR_ALL_LAYERS, + ""); if (re->result != NULL) { dst_rectf = re->result->rectf; @@ -712,7 +795,7 @@ static void render_result_rescale(Render *re) RenderLayer *rl; rl = render_get_active_layer(re, re->result); if (rl != NULL) { - dst_rectf = rl->rectf; + dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); } } @@ -910,9 +993,9 @@ static void *do_part_thread(void *pa_v) if (R.test_break(R.tbh) == 0) { if (!R.sss_points && (R.r.scemode & R_FULL_SAMPLE)) - pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM); + pa->result = render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM, R.viewname); else - pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS); + pa->result = render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM, RR_ALL_LAYERS, R.viewname); /* Copy EXR tile settings, so pipeline knows whether this is a result * for Save Buffers enabled rendering. @@ -935,7 +1018,7 @@ static void *do_part_thread(void *pa_v) /* merge too on break! */ if (R.result->do_exr_tile) { - render_result_exr_file_merge(R.result, pa->result); + render_result_exr_file_merge(R.result, pa->result, R.viewname); } else if (render_display_update_enabled(&R)) { /* on break, don't merge in result for preview renders, looks nicer */ @@ -1115,16 +1198,23 @@ static void *do_render_thread(void *thread_v) return NULL; } -static void threaded_tile_processor(Render *re) +static void main_render_result_end(Render *re) +{ + if (re->result->do_exr_tile) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_end(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } + + if (re->r.scemode & R_EXR_CACHE_FILE) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_cache_write(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } +} + +static void main_render_result_new(Render *re) { - RenderThread thread[BLENDER_MAX_THREADS]; - ThreadQueue *workqueue, *donequeue; - ListBase threads; - RenderPart *pa; - rctf viewplane = re->viewplane; - double lastdraw, elapsed, redrawtime = 1.0f; - int totpart = 0, minx = 0, slice = 0, a, wait; - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); /* first step; free the entire render result, make new, and/or prepare exr buffer saving */ @@ -1132,25 +1222,35 @@ static void threaded_tile_processor(Render *re) render_result_free(re->result); if (re->sss_points && render_display_update_enabled(re)) - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); else if (re->r.scemode & R_FULL_SAMPLE) - re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR); + re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR, RR_ALL_VIEWS); else re->result = render_result_new(re, &re->disprect, 0, - (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS); + (re->r.scemode & R_EXR_TILE_FILE) ? RR_USE_EXR : RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); + + if (re->result->do_exr_tile) + render_result_exr_file_begin(re); +} + +static void threaded_tile_processor(Render *re) +{ + RenderThread thread[BLENDER_MAX_THREADS]; + ThreadQueue *workqueue, *donequeue; + ListBase threads; + RenderPart *pa; + rctf viewplane = re->viewplane; + double lastdraw, elapsed, redrawtime = 1.0f; + int totpart = 0, minx = 0, slice = 0, a, wait; if (re->result == NULL) return; /* warning; no return here without closing exr file */ - RE_parts_init(re, true); - - if (re->result->do_exr_tile) - render_result_exr_file_begin(re); /* assuming no new data gets added to dbase... */ R = *re; @@ -1256,18 +1356,6 @@ static void threaded_tile_processor(Render *re) BLI_thread_queue_free(donequeue); BLI_thread_queue_free(workqueue); - if (re->result->do_exr_tile) { - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - render_result_exr_file_end(re); - BLI_rw_mutex_unlock(&re->resultmutex); - } - - if (re->r.scemode & R_EXR_CACHE_FILE) { - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - render_result_exr_file_cache_write(re); - BLI_rw_mutex_unlock(&re->resultmutex); - } - /* unset threadsafety */ g_break = 0; BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); @@ -1284,6 +1372,7 @@ static void free_all_freestyle_renders(void); /* currently only called by preview renders and envmap */ void RE_TileProcessor(Render *re) { + main_render_result_new(re); threaded_tile_processor(re); re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -1309,6 +1398,7 @@ void RE_TileProcessor(Render *re) static void do_render_3d(Render *re) { + RenderView *rv; int cfra_backup; re->current_scene_update(re->suh, re->scene); @@ -1325,40 +1415,49 @@ static void do_render_3d(Render *re) BKE_scene_frame_set(re->scene, (double)re->scene->r.cfra + (double)re->mblur_offs + (double)re->field_offs); - /* lock drawing in UI during data phase */ - if (re->draw_lock) - re->draw_lock(re->dlh, 1); - - /* make render verts/faces/halos/lamps */ - if (render_scene_needs_vector(re)) { - RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); - } - else { - RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); - RE_Database_Preprocess(re); - } + /* init main render result */ + main_render_result_new(re); + + /* we need a new database for each view */ + for (rv = re->result->views.first; rv; rv = rv->next) { + RE_SetActiveRenderView(re, rv->name); + + /* lock drawing in UI during data phase */ + if (re->draw_lock) + re->draw_lock(re->dlh, 1); + + /* make render verts/faces/halos/lamps */ + if (render_scene_needs_vector(re)) + RE_Database_FromScene_Vectors(re, re->main, re->scene, re->lay); + else { + RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); + RE_Database_Preprocess(re); + } - /* clear UI drawing locks */ - if (re->draw_lock) - re->draw_lock(re->dlh, 0); + /* clear UI drawing locks */ + if (re->draw_lock) + re->draw_lock(re->dlh, 0); - threaded_tile_processor(re); + threaded_tile_processor(re); #ifdef WITH_FREESTYLE - /* Freestyle */ - if (re->r.mode & R_EDGE_FRS) - if (!re->test_break(re->tbh)) - add_freestyle(re, 1); + /* Freestyle */ + if (re->r.mode & R_EDGE_FRS) + if (!re->test_break(re->tbh)) + add_freestyle(re, 1); #endif - /* do left-over 3d post effects (flares) */ - if (re->flag & R_HALO) - if (!re->test_break(re->tbh)) - add_halo_flare(re); - - /* free all render verts etc */ - RE_Database_Free(re); - + /* do left-over 3d post effects (flares) */ + if (re->flag & R_HALO) + if (!re->test_break(re->tbh)) + add_halo_flare(re); + + /* free all render verts etc */ + RE_Database_Free(re); + } + + main_render_result_end(re); + re->scene->r.cfra = cfra_backup; re->scene->r.subframe = 0.f; } @@ -1431,19 +1530,13 @@ static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float b rl1 = brr->layers.first; for (rl = rr->layers.first; rl && rl1; rl = rl->next, rl1 = rl1->next) { - - /* combined */ - if (rl->rectf && rl1->rectf) { - if (key_alpha) - addblur_rect_key(rr, rl->rectf, rl1->rectf, blurfac); - else - addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4); - } - /* passes are allocated in sync */ rpass1 = rl1->passes.first; for (rpass = rl->passes.first; rpass && rpass1; rpass = rpass->next, rpass1 = rpass1->next) { - addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels); + if ((rpass->passtype & SCE_PASS_COMBINED) && key_alpha) + addblur_rect_key(rr, rpass->rect, rpass1->rect, blurfac); + else + addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels); } } } @@ -1456,7 +1549,7 @@ static void do_render_blur_3d(Render *re) int blur = re->r.mblur_samples; /* create accumulation render result */ - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* do the blur steps */ while (blur--) { @@ -1518,10 +1611,6 @@ static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, Rende rl2 = rr2->layers.first; for (rl = rr->layers.first; rl && rl1 && rl2; rl = rl->next, rl1 = rl1->next, rl2 = rl2->next) { - /* combined */ - if (rl->rectf && rl1->rectf && rl2->rectf) - interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4); - /* passes are allocated in sync */ rpass1 = rl1->passes.first; rpass2 = rl2->passes.first; @@ -1589,7 +1678,7 @@ static void do_render_fields_3d(Render *re) re->disprect.ymax *= 2; BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); if (rr2) { if (re->r.mode & R_ODDFIELD) @@ -1661,7 +1750,7 @@ static void do_render_fields_blur_3d(Render *re) /* weak is: it chances disprect from border */ render_result_disprect_to_full_resolution(re); - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); render_result_merge(rres, re->result); render_result_free(re->result); @@ -2068,11 +2157,14 @@ static void free_all_freestyle_renders(void) } #endif -/* reads all buffers, calls optional composite, merges in first result->rectf */ +/* reads all buffers, calls optional composite, merges in first result->views rectf */ static void do_merge_fullsample(Render *re, bNodeTree *ntree) { + ListBase *rectfs; + RenderView *rv; float *rectf, filt[3][3]; int x, y, sample; + int nr, numviews; /* interaction callbacks */ if (ntree) { @@ -2087,9 +2179,18 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* filtmask needs it */ R = *re; - /* we accumulate in here */ - rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); - + /* temporary storage of the acccumulation buffers */ + rectfs = MEM_callocN(sizeof(ListBase), "fullsample accumulation buffers"); + + numviews = BLI_listbase_count(&re->result->views); + for (nr = 0; nr < numviews; nr++) { + rv = MEM_callocN(sizeof(RenderView), "fullsample renderview"); + + /* we accumulate in here */ + rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); + BLI_addtail(rectfs, rv); + } + for (sample = 0; sample < re->r.osa; sample++) { Scene *sce; Render *re1; @@ -2126,54 +2227,70 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) if (ntree) { ntreeCompositTagRender(re->scene); ntreeCompositTagAnimated(ntree); - - ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings); + + for (rv = re->result->views.first; rv; rv = rv->next) { + ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); + } } - - /* ensure we get either composited result or the active layer */ - RE_AcquireResultImage(re, &rres); - - /* accumulate with filter, and clip */ - mask = (1 << sample); - mask_array(mask, filt); - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; - float *col = rres.rectf + 4 * y * re->rectx; - - for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { - /* clamping to 1.0 is needed for correct AA */ - if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f; - if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f; - if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f; + for (nr = 0, rv = re->result->views.first; rv; rv = rv->next, nr++) { + rectf = rv->rectf; + + /* ensure we get either composited result or the active layer */ + RE_AcquireResultImage(re, &rres, nr); + + /* accumulate with filter, and clip */ + mask = (1 << sample); + mask_array(mask, filt); + + for (y = 0; y < re->recty; y++) { + float *rf = rectf + 4 * y * re->rectx; + float *col = rres.rectf + 4 * y * re->rectx; - add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { + /* clamping to 1.0 is needed for correct AA */ + if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f; + if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f; + if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f; + + add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + } } - } - RE_ReleaseResultImage(re); + RE_ReleaseResultImage(re); - /* show stuff */ - if (sample != re->osa - 1) { - /* weak... the display callback wants an active renderlayer pointer... */ - re->result->renlay = render_get_active_layer(re, re->result); - re->display_update(re->duh, re->result, NULL); + /* show stuff */ + if (sample != re->osa - 1) { + /* weak... the display callback wants an active renderlayer pointer... */ + re->result->renlay = render_get_active_layer(re, re->result); + RE_SetActiveRenderView(re, rv->name); + re->display_update(re->duh, re->result, NULL); + } } - - if (re->test_break(re->tbh)) - break; } - /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; + for (nr = 0; nr < numviews; nr++) { + rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf; + + /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ + for (y = 0; y < re->recty; y++) { + float *rf = rectf + 4 * y * re->rectx; - for (x = 0; x < re->rectx; x++, rf += 4) { - rf[0] = MAX2(rf[0], 0.0f); - rf[1] = MAX2(rf[1], 0.0f); - rf[2] = MAX2(rf[2], 0.0f); - CLAMP(rf[3], 0.0f, 1.0f); + for (x = 0; x < re->rectx; x++, rf += 4) { + rf[0] = MAX2(rf[0], 0.0f); + rf[1] = MAX2(rf[1], 0.0f); + rf[2] = MAX2(rf[2], 0.0f); + CLAMP(rf[3], 0.0f, 1.0f); + } } + + /* store the final result */ + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + rv = BLI_findlink(&re->result->views, nr); + if (rv->rectf) + MEM_freeN(rv->rectf); + rv->rectf = rectf; + BLI_rw_mutex_unlock(&re->resultmutex); } /* clear interaction callbacks */ @@ -2186,12 +2303,14 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* disable full sample print */ R.i.curfsa = 0; - - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - if (re->result->rectf) - MEM_freeN(re->result->rectf); - re->result->rectf = rectf; - BLI_rw_mutex_unlock(&re->resultmutex); + + /* garbage collection */ + while (rectfs->first) { + RenderView *rv = rectfs->first; + BLI_remlink(rectfs, rv); + MEM_freeN(rv); + } + MEM_freeN(rectfs); } /* called externally, via compositor */ @@ -2267,7 +2386,11 @@ static void do_render_composite_fields_blur_3d(Render *re) if (composite_needs_render(re->scene, 1)) { /* save memory... free all cached images */ ntreeFreeCache(ntree); - + + /* render the frames + * it could be optimized to render only the needed view + * but what if a scene has a different number of views + * than the main scene? */ do_render_fields_blur_3d(re); } else { @@ -2280,7 +2403,7 @@ static void do_render_composite_fields_blur_3d(Render *re) if ((re->r.mode & R_CROP) == 0) { render_result_disprect_to_full_resolution(re); } - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS); + re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); @@ -2325,7 +2448,10 @@ static void do_render_composite_fields_blur_3d(Render *re) if (re->r.scemode & R_FULL_SAMPLE) do_merge_fullsample(re, ntree); else { - ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings); + RenderView *rv; + for (rv = re->result->views.first; rv; rv = rv->next) { + ntreeCompositExecTree(re->scene, ntree, &re->r, true, G.background == 0, &re->scene->view_settings, &re->scene->display_settings, rv->name); + } } ntree->stats_draw = NULL; @@ -2350,13 +2476,17 @@ static void do_render_composite_fields_blur_3d(Render *re) static void renderresult_stampinfo(Render *re) { RenderResult rres; + RenderView *rv; + int nr; /* this is the basic trick to get the displayed float or char rect from render result */ - RE_AcquireResultImage(re, &rres); - BKE_image_stamp_buf( - re->scene, RE_GetCamera(re), - (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4); - RE_ReleaseResultImage(re); + nr = 0; + for (rv = re->result->views.first;rv;rv = rv->next, nr++) { + RE_SetActiveRenderView(re, rv->name); + RE_AcquireResultImage(re, &rres, nr); + BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rv->rect32, rv->rectf, rres.rectx, rres.recty, 4); + RE_ReleaseResultImage(re); + } } int RE_seq_render_active(Scene *scene, RenderData *rd) @@ -2380,10 +2510,12 @@ int RE_seq_render_active(Scene *scene, RenderData *rd) static void do_render_seq(Render *re) { static int recurs_depth = 0; - struct ImBuf *ibuf, *out; + struct ImBuf *out; RenderResult *rr; /* don't assign re->result here as it might change during give_ibuf_seq */ int cfra = re->r.cfra; SeqRenderData context; + size_t view_id, tot_views; + struct ImBuf **ibuf_arr; int re_x, re_y; re->i.cfra = cfra; @@ -2406,45 +2538,67 @@ static void do_render_seq(Render *re) re_y = re->result->recty; } + tot_views = BKE_scene_multiview_num_views_get(&re->r); + ibuf_arr = MEM_mallocN(sizeof(ImBuf *) * tot_views, "Sequencer Views ImBufs"); + BKE_sequencer_new_render_data( re->eval_ctx, re->main, re->scene, re_x, re_y, 100, &context); - out = BKE_sequencer_give_ibuf(&context, cfra, 0); + /* the renderresult gets destroyed during the rendering, so we first collect all ibufs + * and then we populate the final renderesult */ - if (out) { - ibuf = IMB_dupImBuf(out); - IMB_freeImBuf(out); - BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf); - } - else { - ibuf = NULL; - } + for (view_id = 0; view_id < tot_views; view_id++) { + context.view_id = view_id; + out = BKE_sequencer_give_ibuf(&context, cfra, 0); - recurs_depth--; + if (out) { + ibuf_arr[view_id] = IMB_dupImBuf(out); + IMB_freeImBuf(out); + BKE_sequencer_imbuf_from_sequencer_space(re->scene, ibuf_arr[view_id]); + } + else { + ibuf_arr[view_id] = NULL; + } + } rr = re->result; - + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_views_new(rr, &re->r); + BLI_rw_mutex_unlock(&re->resultmutex); - if (ibuf) { - /* copy ibuf into combined pixel rect */ - render_result_rect_from_ibuf(rr, &re->r, ibuf); - - if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */ - Editing *ed = re->scene->ed; - if (ed) - BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true); + for (view_id = 0; view_id < tot_views; view_id++) { + RenderView *rv = BLI_findlink(&rr->views, view_id); + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + + if (ibuf_arr[view_id]) { + /* copy ibuf into combined pixel rect */ + render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id); + + if (recurs_depth == 0) { /* with nested scenes, only free on toplevel... */ + Editing *ed = re->scene->ed; + if (ed) + BKE_sequencer_free_imbuf(re->scene, &ed->seqbase, true); + } + IMB_freeImBuf(ibuf_arr[view_id]); } - IMB_freeImBuf(ibuf); - } - else { - /* render result is delivered empty in most cases, nevertheless we handle all cases */ - render_result_rect_fill_zero(rr); + else { + /* render result is delivered empty in most cases, nevertheless we handle all cases */ + render_result_rect_fill_zero(rr, view_id); + } + + BLI_rw_mutex_unlock(&re->resultmutex); + + /* would mark display buffers as invalid */ + RE_SetActiveRenderView(re, rv->name); + re->display_update(re->duh, re->result, NULL); } - BLI_rw_mutex_unlock(&re->resultmutex); + MEM_freeN(ibuf_arr); + + recurs_depth--; /* just in case this flag went missing at some point */ re->r.scemode |= R_DOSEQ; @@ -2454,9 +2608,6 @@ static void do_render_seq(Render *re) re->progress(re->prh, (float)(cfra - re->r.sfra) / (re->r.efra - re->r.sfra)); else re->progress(re->prh, 1.0f); - - /* would mark display buffers as invalid */ - re->display_update(re->duh, re->result, NULL); } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ @@ -2543,11 +2694,50 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override } } +static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportList *reports) +{ + SceneRenderView *srv; + bool active_view = false; + + if ((scene->r.scemode & R_MULTIVIEW) == 0) + return true; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (BKE_scene_multiview_is_render_view_active(&scene->r, srv)) { + active_view = true; + + if (scene->r.views_format == SCE_VIEWS_FORMAT_MULTIVIEW) { + Object *view_camera; + view_camera = BKE_camera_multiview_render(scene, camera, srv->name); + + if (view_camera == camera) { + /* if the suffix is not in the camera, means we are using the fallback camera */ + if (!BLI_str_endswith(view_camera->id.name + 2, srv->suffix)) { + BKE_reportf(reports, RPT_ERROR, "Camera \"%s\" is not a multi-view camera", + camera->id.name + 2); + return false; + } + } + } + } + } + + if (!active_view) { + BKE_reportf(reports, RPT_ERROR, "No active view found in scene \"%s\"", scene->id.name + 2); + return false; + } + + return true; +} + static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports) { if (camera_override == NULL && scene->camera == NULL) scene->camera = BKE_scene_camera_find(scene); + if (!check_valid_camera_multiview(scene, scene->camera, reports)) + return false; + if (RE_seq_render_active(scene, &scene->r)) { if (scene->ed) { Sequence *seq = scene->ed->seqbase.first; @@ -2565,6 +2755,8 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList } } } + else if (!check_valid_camera_multiview(seq->scene, seq->scene_camera, reports)) + return false; } seq = seq->next; @@ -2729,6 +2921,17 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init) BKE_ptcache_bake(&baker); } + +void RE_SetActiveRenderView(Render *re, const char *viewname) +{ + BLI_strncpy(re->viewname, viewname, sizeof(re->viewname)); +} + +const char *RE_GetActiveRenderView(Render *re) +{ + return re->viewname; +} + /* evaluating scene options for general Blender render */ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int anim, int anim_init) @@ -2764,7 +2967,8 @@ static int render_initialize_from_main(Render *re, RenderData *rd, Main *bmain, re->lay = lay_override ? lay_override : scene->lay; re->layer_override = lay_override; re->i.localview = (re->lay & 0xFF000000) != 0; - + re->viewname[0] = '\0'; + /* not too nice, but it survives anim-border render */ if (anim) { render_update_anim_renderdata(re, &scene->r); @@ -2838,10 +3042,10 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr char name[FILE_MAX]; BKE_image_path_from_imformat( name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false); + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, NULL); /* reports only used for Movie */ - do_write_image_or_movie(re, bmain, scene, NULL, name); + do_write_image_or_movie(re, bmain, scene, NULL, 0, name); } } @@ -2879,96 +3083,269 @@ void RE_RenderFreestyleExternal(Render *re) } #endif -static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override) +bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, struct Object *camera, const bool stamp, char *name) { - char name[FILE_MAX]; - RenderResult rres; - Object *camera = RE_GetCamera(re); - double render_time; - int ok = 1; - - RE_AcquireResultImage(re, &rres); + bool is_mono; + bool ok = true; + RenderData *rd = &scene->r; - /* write movie or image */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - bool do_free = false; - ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); + if (!rr) + return false; - /* note; the way it gets 32 bits rects is weak... */ - if (ibuf->rect == NULL) { - ibuf->rect = MEM_mapallocN(sizeof(int) * rres.rectx * rres.recty, "temp 32 bits rect"); - ibuf->mall |= IB_rect; - RE_AcquiredResultGet32(re, &rres, ibuf->rect); - do_free = true; - } + is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + if (ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) && + rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW) + { + RE_WriteRenderResult(reports, rr, name, &rd->im_format, true, NULL); + printf("Saved: %s\n", name); + } - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); + /* mono, legacy code */ + else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) + { + RenderView *rv; + size_t view_id; + char filepath[FILE_MAX]; - ok = mh->append_movie(&re->r, scene->r.sfra, scene->r.cfra, (int *) ibuf->rect, - ibuf->x, ibuf->y, re->reports); - if (do_free) { - MEM_freeN(ibuf->rect); - ibuf->rect = NULL; - ibuf->mall &= ~IB_rect; - } + BLI_strncpy(filepath, name, sizeof(filepath)); - /* imbuf knows which rects are not part of ibuf */ - IMB_freeImBuf(ibuf); + for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) { + BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); - printf("Append frame %d", scene->r.cfra); - } - else { - if (name_override) - BLI_strncpy(name, name_override, sizeof(name)); - else - BKE_image_path_from_imformat( - name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); - - if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - if (re->result) { - RE_WriteRenderResult(re->reports, re->result, name, scene->r.im_format.exr_codec); - printf("Saved: %s", name); + if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + + RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name); + printf("Saved: %s\n", name); } + else { + ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id); + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &rd->im_format); + + if (stamp) { + /* writes the name of the individual cameras */ + Object *view_camera = BKE_camera_multiview_render(scene, camera, rv->name); + ok = BKE_imbuf_write_stamp(scene, view_camera, ibuf, name, &rd->im_format); + } + else { + ok = BKE_imbuf_write(ibuf, name, &rd->im_format); + } + + if (ok == false) { + printf("Render error: cannot save %s\n", name); + } + else printf("Saved: %s\n", name); + + /* optional preview images for exr */ + if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { + ImageFormatData imf = rd->im_format; + imf.imtype = R_IMF_IMTYPE_JPEG90; + + if (BLI_testextensie(name, ".exr")) + name[strlen(name) - 4] = 0; + BKE_image_path_ensure_ext_from_imformat(name, &imf); + ibuf->planes = 24; + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &rd->im_format); + + if (stamp) { + /* writes the name of the individual cameras */ + Object *view_camera = BKE_camera_multiview_render(scene, camera, rv->name); + ok = BKE_imbuf_write_stamp(scene, view_camera, ibuf, name, &rd->im_format); + } + else { + ok = BKE_imbuf_write(ibuf, name, &rd->im_format); + } + printf("Saved: %s\n", name); + } + + /* imbuf knows which rects are not part of ibuf */ + IMB_freeImBuf(ibuf); + } + } + } + else { /* R_IMF_VIEWS_STEREO_3D */ + BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D); + + if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { + printf("Stereo 3D not support for MultiLayer image: %s\n", name); } else { - ImBuf *ibuf = render_result_rect_to_ibuf(&rres, &scene->r); + ImBuf *ibuf_arr[3] = {NULL}; + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + int i; + + for (i = 0; i < 2; i++) { + int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); + ibuf_arr[i] = render_result_rect_to_ibuf(rr, rd, view_id); + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]); + } - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &scene->r.im_format); + ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); - ok = BKE_imbuf_write_stamp(scene, camera, ibuf, name, &scene->r.im_format); - - if (ok == 0) { + if (stamp) + ok = BKE_imbuf_write_stamp(scene, camera, ibuf_arr[2], name, &rd->im_format); + else + ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format); + + if (ok == false) printf("Render error: cannot save %s\n", name); - } - else printf("Saved: %s", name); - + else + printf("Saved: %s\n", name); + /* optional preview images for exr */ - if (ok && scene->r.im_format.imtype == R_IMF_IMTYPE_OPENEXR && (scene->r.im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) { - ImageFormatData imf = scene->r.im_format; + if (ok && rd->im_format.imtype == R_IMF_IMTYPE_OPENEXR && + (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) + { + ImageFormatData imf = rd->im_format; imf.imtype = R_IMF_IMTYPE_JPEG90; if (BLI_testextensie(name, ".exr")) name[strlen(name) - 4] = 0; + BKE_image_path_ensure_ext_from_imformat(name, &imf); - ibuf->planes = 24; + ibuf_arr[2]->planes = 24; - IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + IMB_colormanagement_imbuf_for_write(ibuf_arr[2], true, false, &scene->view_settings, &scene->display_settings, &imf); - BKE_imbuf_write_stamp(scene, camera, ibuf, name, &imf); - printf("\nSaved: %s", name); + if (stamp) + ok = BKE_imbuf_write_stamp(scene, camera, ibuf_arr[2], name, &rd->im_format); + else + ok = BKE_imbuf_write(ibuf_arr[2], name, &imf); + + printf("Saved: %s\n", name); } - + + /* imbuf knows which rects are not part of ibuf */ + for (i = 0; i < 3; i++) { + IMB_freeImBuf(ibuf_arr[i]); + } + } + } + + return ok; +} + +bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh, + const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos) +{ + bool is_mono; + bool ok = true; + + if (!rr) + return false; + + is_mono = BLI_listbase_count_ex(&rr->views, 2) < 2; + + if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { + size_t view_id; + for (view_id = 0; view_id < totvideos; view_id++) { + bool do_free = false; + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); + ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id); + + /* note; the way it gets 32 bits rects is weak... */ + if (ibuf->rect == NULL) { + ibuf->rect = MEM_mapallocN(sizeof(int) * rr->rectx * rr->recty, "temp 32 bits rect"); + ibuf->mall |= IB_rect; + render_result_rect_get_pixels(rr, ibuf->rect, width, height, &scene->view_settings, &scene->display_settings, view_id); + do_free = true; + } + + IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + + ok &= mh->append_movie(movie_ctx_arr[view_id], rd, scene->r.sfra, scene->r.cfra, + (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports); + + if (do_free) { + MEM_freeN(ibuf->rect); + ibuf->rect = NULL; + ibuf->mall &= ~IB_rect; + } + /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); } + printf("Append frame %d\n", scene->r.cfra); + } + else { /* R_IMF_VIEWS_STEREO_3D */ + const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; + ImBuf *ibuf_arr[3] = {NULL}; + bool do_free[2] = {false, false}; + size_t i; + + BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D)); + + for (i = 0; i < 2; i++) { + int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name)); + ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id); + + /* note; the way it gets 32 bits rects is weak... */ + if (ibuf_arr[i]->rect == NULL) { + ibuf_arr[i]->rect = MEM_mapallocN(sizeof(int) * width * height, "temp 32 bits rect"); + ibuf_arr[i]->mall |= IB_rect; + render_result_rect_get_pixels(rr, ibuf_arr[i]->rect, width, height, &scene->view_settings, &scene->display_settings, view_id); + do_free[i] = true; + } + + IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &scene->view_settings, + &scene->display_settings, &scene->r.im_format); + } + + ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); + + ok = mh->append_movie(movie_ctx_arr[0], rd, scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect, + ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports); + + for (i = 0; i < 2; i++) { + if (do_free[i]) { + MEM_freeN(ibuf_arr[i]->rect); + ibuf_arr[i]->rect = NULL; + ibuf_arr[i]->mall &= ~IB_rect; + } + + /* imbuf knows which rects are not part of ibuf */ + IMB_freeImBuf(ibuf_arr[i]); + } + } + + return ok; +} + +static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const size_t totvideos, const char *name_override) +{ + char name[FILE_MAX]; + RenderResult rres; + double render_time; + bool ok = true; + Object *camera = RE_GetCamera(re); + + RE_AcquireResultImageViews(re, &rres); + + /* write movie or image */ + if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { + RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos); + } + else { + if (name_override) + BLI_strncpy(name, name_override, sizeof(name)); + else + BKE_image_path_from_imformat( + name, scene->r.pic, bmain->name, scene->r.cfra, + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); + + /* write images as individual images or stereo */ + ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, camera, true, name); } - RE_ReleaseResultImage(re); + RE_ReleaseResultImageViews(re, &rres); render_time = re->i.lastframetime; re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -2987,20 +3364,51 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie return ok; } +static void get_videos_dimensions(Render *re, RenderData *rd, size_t *r_width, size_t *r_height) +{ + size_t width, height; + if (re->r.mode & R_BORDER) { + if ((re->r.mode & R_CROP) == 0) { + width = re->winx; + height = re->winy; + } + else { + width = re->rectx; + height = re->recty; + } + } + else { + width = re->rectx; + height = re->recty; + } + + BKE_scene_multiview_videos_dimensions_get(rd, width, height, r_width, r_height); +} + /* saves images to disk */ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_override, unsigned int lay_override, int sfra, int efra, int tfra) { RenderData rd = scene->r; - bMovieHandle *mh = BKE_movie_handle_get(scene->r.im_format.imtype); + bMovieHandle *mh = NULL; int cfrao = scene->r.cfra; int nfra, totrendered = 0, totskipped = 0; - + const size_t totvideos = BKE_scene_multiview_num_videos_get(&rd); + const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype); + const bool is_multiview_name = ((scene->r.scemode & R_MULTIVIEW) != 0 && + (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)); + BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT); /* do not fully call for each frame, it initializes & pops output window */ if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1)) return; + + /* we don't support Frame Server and streaming of individual views */ + if ((rd.im_format.imtype == R_IMF_IMTYPE_FRAMESERVER) && (totvideos > 1)) { + BKE_report(re->reports, RPT_ERROR, "Frame Server only support stereo output for multiview rendering"); + return; + } /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */ /* is also set by caller renderwin.c */ @@ -3008,31 +3416,33 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri re->flag |= R_ANIMATION; - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - int width, height; - if (re->r.mode & R_BORDER) { - if ((re->r.mode & R_CROP) == 0) { - width = re->winx; - height = re->winy; - } - else { - width = re->rectx; - height = re->recty; - } - } - else { - width = re->rectx; - height = re->recty; - } + if (is_movie) { + size_t i, width, height; + + get_videos_dimensions(re, &rd, &width, &height); + + mh = BKE_movie_handle_get(scene->r.im_format.imtype); + re->movie_ctx_arr = MEM_mallocN(sizeof(void *) * totvideos, "Movies' Context"); + + for (i = 0; i < totvideos; i++) { + const char *suffix = BKE_scene_multiview_view_id_suffix_get(&re->r, i); - /* last argument here depends on users really, but no users using preview have been found so far */ - if (!mh->start_movie(scene, &re->r, width, height, re->reports, false)) - G.is_break = true; + re->movie_ctx_arr[i] = mh->context_create(); + + if (!mh->start_movie(re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix)) + G.is_break = true; + } } - if (mh->get_next_frame) { + if (mh && mh->get_next_frame) { + /* MULTIVIEW_TODO: + * in case a new video format is added that implements get_next_frame multiview has to be addressed + * or the error throwing for R_IMF_IMTYPE_FRAMESERVER has to be extended for those cases as well + */ + BLI_assert(totvideos < 2); + while (!(G.is_break == 1)) { - int nf = mh->get_next_frame(&re->r, re->reports); + int nf = mh->get_next_frame(re->movie_ctx_arr[0], &re->r, re->reports); if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) { scene->r.cfra = re->r.cfra = nf; @@ -3042,7 +3452,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri totrendered++; if (re->test_break(re->tbh) == 0) { - if (!do_write_image_or_movie(re, bmain, scene, mh, NULL)) + if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) G.is_break = true; } @@ -3085,20 +3495,67 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri nfra += tfra; /* Touch/NoOverwrite options are only valid for image's */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { + if (is_movie == false) { if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH)) BKE_image_path_from_imformat( name, scene->r.pic, bmain->name, scene->r.cfra, - &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true); + &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); + + if (scene->r.mode & R_NO_OVERWRITE) { + if (!is_multiview_name) { + if (BLI_exists(name)) { + printf("skipping existing frame \"%s\"\n", name); + totskipped++; + continue; + } + } + else { + SceneRenderView *srv; + bool is_skip = false; + char filepath[FILE_MAX]; - if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) { - printf("skipping existing frame \"%s\"\n", name); - totskipped++; - continue; + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if (BLI_exists(filepath)) { + is_skip = true; + printf("skipping existing frame \"%s\" for view \"%s\"\n", filepath, srv->name); + } + } + + if (is_skip) { + totskipped++; + continue; + } + } } - if (scene->r.mode & R_TOUCH && !BLI_exists(name)) { - BLI_make_existing_file(name); /* makes the dir if its not there */ - BLI_file_touch(name); + + if (scene->r.mode & R_TOUCH) { + if (!is_multiview_name) { + if (!BLI_exists(name)) { + BLI_make_existing_file(name); /* makes the dir if its not there */ + BLI_file_touch(name); + } + } + else { + SceneRenderView *srv; + char filepath[FILE_MAX]; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if (!BLI_exists(filepath)) { + BLI_make_existing_file(filepath); /* makes the dir if its not there */ + BLI_file_touch(filepath); + } + } + } } } @@ -3113,7 +3570,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (re->test_break(re->tbh) == 0) { if (!G.is_break) - if (!do_write_image_or_movie(re, bmain, scene, mh, NULL)) + if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) G.is_break = true; } else @@ -3121,10 +3578,30 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri if (G.is_break == true) { /* remove touched file */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) { - if ((scene->r.mode & R_TOUCH) && (BLI_file_size(name) == 0)) { - /* BLI_exists(name) is implicit */ - BLI_delete(name, false, false); + if (is_movie == false) { + if ((scene->r.mode & R_TOUCH)) { + if (!is_multiview_name) { + if ((BLI_file_size(name) == 0)) { + /* BLI_exists(name) is implicit */ + BLI_delete(name, false, false); + } + } + else { + SceneRenderView *srv; + char filepath[FILE_MAX]; + + for (srv = scene->r.views.first; srv; srv = srv->next) { + if (!BKE_scene_multiview_is_render_view_active(&scene->r, srv)) + continue; + + BKE_scene_multiview_filepath_get(srv, name, filepath); + + if ((BLI_file_size(filepath) == 0)) { + /* BLI_exists(filepath) is implicit */ + BLI_delete(filepath, false, false); + } + } + } } } @@ -3139,8 +3616,17 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } /* end movie */ - if (BKE_imtype_is_movie(scene->r.im_format.imtype)) - mh->end_movie(); + if (is_movie) { + size_t i; + for (i = 0; i < totvideos; i++) { + mh->end_movie(re->movie_ctx_arr[i]); + mh->context_free(re->movie_ctx_arr[i]); + } + + if (re->movie_ctx_arr) { + MEM_freeN(re->movie_ctx_arr); + } + } if (totskipped && totrendered == 0) BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite"); @@ -3238,13 +3724,22 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char { /* OCIO_TODO: assume layer was saved in defaule color space */ ImBuf *ibuf = IMB_loadiffname(filename, IB_rect, NULL); + RenderPass *rpass = NULL; + + /* multiview: since the API takes no 'view', we use the first combined pass found */ + for (rpass = layer->passes.first; rpass; rpass = rpass->next) + if (rpass->passtype == SCE_PASS_COMBINED) + break; + + if (rpass == NULL) + BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: no Combined pass found in the render layer '%s'", filename); if (ibuf && (ibuf->rect || ibuf->rect_float)) { if (ibuf->x == layer->rectx && ibuf->y == layer->recty) { if (ibuf->rect_float == NULL) IMB_float_from_rect(ibuf); - memcpy(layer->rectf, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); + memcpy(rpass->rect, ibuf->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); } else { if ((ibuf->x - x >= layer->rectx) && (ibuf->y - y >= layer->recty)) { @@ -3257,7 +3752,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char if (ibuf_clip) { IMB_rectcpy(ibuf_clip, ibuf, 0, 0, x, y, layer->rectx, layer->recty); - memcpy(layer->rectf, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); + memcpy(rpass->rect, ibuf_clip->rect_float, sizeof(float) * 4 * layer->rectx * layer->recty); IMB_freeImBuf(ibuf_clip); } else { @@ -3345,3 +3840,21 @@ bool RE_WriteEnvmapResult(struct ReportList *reports, Scene *scene, EnvMap *env, } } +/* used in the interface to decide whether to show layers */ +bool RE_layers_have_name(struct RenderResult *rr) +{ + switch (BLI_listbase_count_ex(&rr->layers, 2)) { + case 0: + return false; + break; + case 1: + return (((RenderLayer *)rr->layers.first)->name[0] != '\0'); + break; + default: + return true; + break; + } + return false; +} + + -- cgit v1.2.3 From 33a92473347a9b9ee4e95c20e579ec97fd67ef63 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 6 Apr 2015 20:43:34 +0200 Subject: UI i18n cleanup... And some general style cleanup as well (line length...). --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 25adb4db4f7..4a767184c44 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3732,7 +3732,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char break; if (rpass == NULL) - BKE_reportf(reports, RPT_ERROR, "RE_layer_load_from_file: no Combined pass found in the render layer '%s'", filename); + BKE_reportf(reports, RPT_ERROR, "%s: no Combined pass found in the render layer '%s'", __func__, filename); if (ibuf && (ibuf->rect || ibuf->rect_float)) { if (ibuf->x == layer->rectx && ibuf->y == layer->recty) { -- cgit v1.2.3 From 808ea6271a0107cc3df52fb0ef18ccec191f6f15 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 8 Apr 2015 12:23:38 +1000 Subject: Cleanup: confusing if statements & alignment --- source/blender/render/intern/source/pipeline.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 4a767184c44..05bee6f165a 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2249,9 +2249,9 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { /* clamping to 1.0 is needed for correct AA */ - if (col[0] < 0.0f) col[0] = 0.0f; else if (col[0] > 1.0f) col[0] = 1.0f; - if (col[1] < 0.0f) col[1] = 0.0f; else if (col[1] > 1.0f) col[1] = 1.0f; - if (col[2] < 0.0f) col[2] = 0.0f; else if (col[2] > 1.0f) col[2] = 1.0f; + CLAMP(col[0], 0.0, 1.0f); + CLAMP(col[1], 0.0, 1.0f); + CLAMP(col[2], 0.0, 1.0f); add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); } -- cgit v1.2.3 From ae5f2c202504ad23fe7d2147c0bfd8290d6dad07 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Thu, 9 Apr 2015 18:01:52 +0200 Subject: Fix regression after multiview, basically we appended the wrong frames to movie file. We have to resort to use crappy workarounds with preview arguments again since preview range is only for OpenGL preview. --- source/blender/render/intern/source/pipeline.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 05bee6f165a..cd7940e52c8 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3233,7 +3233,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen } bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scene, RenderData *rd, bMovieHandle *mh, - const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos) + const size_t width, const size_t height, void **movie_ctx_arr, const size_t totvideos, bool preview) { bool is_mono; bool ok = true; @@ -3261,7 +3261,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format); - ok &= mh->append_movie(movie_ctx_arr[view_id], rd, scene->r.sfra, scene->r.cfra, + ok &= mh->append_movie(movie_ctx_arr[view_id], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports); if (do_free) { @@ -3301,7 +3301,7 @@ bool RE_WriteRenderViewsMovie(ReportList *reports, RenderResult *rr, Scene *scen ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); - ok = mh->append_movie(movie_ctx_arr[0], rd, scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect, + ok = mh->append_movie(movie_ctx_arr[0], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf_arr[2]->rect, ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports); for (i = 0; i < 2; i++) { @@ -3331,7 +3331,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie /* write movie or image */ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos); + RE_WriteRenderViewsMovie(re->reports, &rres, scene, &re->r, mh, re->rectx, re->recty, re->movie_ctx_arr, totvideos, false); } else { if (name_override) -- cgit v1.2.3 From 1e71270f77a4e1c7c84b871e5378c659d61edb3e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 10 Apr 2015 12:32:19 +0200 Subject: Fix T44329: Blender Crash when rendering in 3DView. This commit fixes two different issues actually: * When view name is unknown/irrelevant, you should pass a NULL str pointer to `RE_RenderLayerGetPass()`, not an empty string! * `render_result_rescale()` would unconditionnaly free re->result (at the end), even if it did not replaced it at all, leading to freed memory access later. This is only a partial fix though, "CacheBuffer" (i.e. saving tiles in EXR files) shall not be used in 3DView rendering, and yet it is here... --- source/blender/render/intern/source/pipeline.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index cd7940e52c8..db3499b4180 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -202,7 +202,7 @@ float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char if (viewname == NULL) break; - else if (strcmp(rpass->view, viewname) == 0) + else if (STREQ(rpass->view, viewname)) break; } } @@ -776,7 +776,7 @@ static void render_result_rescale(Render *re) if (src_rectf == NULL) { RenderLayer *rl = render_get_active_layer(re, re->result); if (rl != NULL) { - src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); + src_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL); } } @@ -795,7 +795,7 @@ static void render_result_rescale(Render *re) RenderLayer *rl; rl = render_get_active_layer(re, re->result); if (rl != NULL) { - dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, ""); + dst_rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, NULL); } } @@ -812,9 +812,8 @@ static void render_result_rescale(Render *re) } } } + render_result_free(result); } - - render_result_free(result); } void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect) -- cgit v1.2.3 From c448196bb4c99b13cdaaf0e197a9f44a46b3bc18 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 14 Apr 2015 10:30:14 +1000 Subject: Cleanup: warnings --- source/blender/render/intern/source/pipeline.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index db3499b4180..24e66cbf3cb 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2248,9 +2248,9 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { /* clamping to 1.0 is needed for correct AA */ - CLAMP(col[0], 0.0, 1.0f); - CLAMP(col[1], 0.0, 1.0f); - CLAMP(col[2], 0.0, 1.0f); + CLAMP(col[0], 0.0f, 1.0f); + CLAMP(col[1], 0.0f, 1.0f); + CLAMP(col[2], 0.0f, 1.0f); add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); } -- cgit v1.2.3 From 479b6696932d133078690063508d8447d6dc0a28 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Fri, 17 Apr 2015 09:48:31 -0300 Subject: Fix T44336: Unable to select cycles-specific passes in UV/image editor This approach gets rid of iuser->pass for good. Also, I'm commenting out the pass increase/decrease. This was broken since multiview. I will fix it later (before 2.75), but I didn't want to get this patch mangled with that fix. Thanks Sergey Sharybin for the review and feedbacks. Reviewers: sergey Differential Revision: https://developer.blender.org/D1232 --- source/blender/render/intern/source/pipeline.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 24e66cbf3cb..e9b0a2bcbf4 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3856,4 +3856,14 @@ bool RE_layers_have_name(struct RenderResult *rr) return false; } - +RenderPass *RE_pass_find_by_type(RenderLayer *rl, int passtype, const char *viewname) +{ + RenderPass *rp; + for (rp = rl->passes.first; rp; rp = rp->next) { + if (rp->passtype == passtype) { + if (STREQ(rp->view, viewname)) + return rp; + } + } + return NULL; +} -- cgit v1.2.3 From 58c511fb0149339b8942bb2124c215fd70219b63 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Tue, 21 Apr 2015 18:33:33 +0200 Subject: Stamp refactoring: Write those on render result during rendering, so we can cleanly write a render result image after rendering. --- source/blender/render/intern/source/pipeline.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e9b0a2bcbf4..d25de64978e 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -363,6 +363,7 @@ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) rr->layers = re->result->layers; rr->xof = re->disprect.xmin; rr->yof = re->disprect.ymin; + rr->stamp_data = re->result->stamp_data; } } } @@ -3026,12 +3027,17 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr scene->r.cfra = frame; if (render_initialize_from_main(re, &scene->r, bmain, scene, srl, camera_override, lay_override, 0, 0)) { + Object *camera; MEM_reset_peak_memory(); BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE); do_render_all_options(re); + /* save render result stamp if needed */ + camera = RE_GetCamera(re); + BKE_render_result_stamp_info(scene, camera, re->result); + if (write_still && !G.is_break) { if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { /* operator checks this but in case its called from elsewhere */ @@ -3082,7 +3088,7 @@ void RE_RenderFreestyleExternal(Render *re) } #endif -bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, struct Object *camera, const bool stamp, char *name) +bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name) { bool is_mono; bool ok = true; @@ -3125,8 +3131,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen if (stamp) { /* writes the name of the individual cameras */ - Object *view_camera = BKE_camera_multiview_render(scene, camera, rv->name); - ok = BKE_imbuf_write_stamp(scene, view_camera, ibuf, name, &rd->im_format); + ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format); } else { ok = BKE_imbuf_write(ibuf, name, &rd->im_format); @@ -3152,8 +3157,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen if (stamp) { /* writes the name of the individual cameras */ - Object *view_camera = BKE_camera_multiview_render(scene, camera, rv->name); - ok = BKE_imbuf_write_stamp(scene, view_camera, ibuf, name, &rd->im_format); + ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format); } else { ok = BKE_imbuf_write(ibuf, name, &rd->im_format); @@ -3188,7 +3192,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]); if (stamp) - ok = BKE_imbuf_write_stamp(scene, camera, ibuf_arr[2], name, &rd->im_format); + ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format); else ok = BKE_imbuf_write(ibuf_arr[2], name, &rd->im_format); @@ -3214,7 +3218,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen &scene->display_settings, &imf); if (stamp) - ok = BKE_imbuf_write_stamp(scene, camera, ibuf_arr[2], name, &rd->im_format); + ok = BKE_imbuf_write_stamp(scene, rr, ibuf_arr[2], name, &rd->im_format); else ok = BKE_imbuf_write(ibuf_arr[2], name, &imf); @@ -3324,7 +3328,6 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie RenderResult rres; double render_time; bool ok = true; - Object *camera = RE_GetCamera(re); RE_AcquireResultImageViews(re, &rres); @@ -3341,7 +3344,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL); /* write images as individual images or stereo */ - ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, camera, true, name); + ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name); } RE_ReleaseResultImageViews(re, &rres); @@ -3469,6 +3472,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } else { for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) { + Object *camera; char name[FILE_MAX]; /* only border now, todo: camera lens. (ton) */ @@ -3567,6 +3571,10 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri do_render_all_options(re); totrendered++; + /* save render result stamp if needed */ + camera = RE_GetCamera(re); + BKE_render_result_stamp_info(scene, camera, re->result); + if (re->test_break(re->tbh) == 0) { if (!G.is_break) if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) -- cgit v1.2.3 From 97587dc5d6b44625ffc00525b12181f64c80b409 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Wed, 22 Apr 2015 11:50:57 +0200 Subject: Stamp cannot be written to file. Make sure stamp data is avaliable before writing stamp to image - this still does not fix stamp, looks like issue is availability of the images themselves for the view, investigating next. --- source/blender/render/intern/source/pipeline.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index d25de64978e..73f837e095a 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2615,6 +2615,8 @@ static void do_render_seq(Render *re) /* main loop: doing sequence + fields + blur + 3d render + compositing */ static void do_render_all_options(Render *re) { + Object *camera; + re->current_scene_update(re->suh, re->scene); BKE_scene_camera_switch_update(re->scene); @@ -2648,6 +2650,10 @@ static void do_render_all_options(Render *re) re->stats_draw(re->sdh, &re->i); + /* save render result stamp if needed */ + camera = RE_GetCamera(re); + BKE_render_result_stamp_info(re->scene, camera, re->result); + /* stamp image info here */ if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) { renderresult_stampinfo(re); @@ -3027,17 +3033,12 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr scene->r.cfra = frame; if (render_initialize_from_main(re, &scene->r, bmain, scene, srl, camera_override, lay_override, 0, 0)) { - Object *camera; MEM_reset_peak_memory(); BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE); do_render_all_options(re); - /* save render result stamp if needed */ - camera = RE_GetCamera(re); - BKE_render_result_stamp_info(scene, camera, re->result); - if (write_still && !G.is_break) { if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { /* operator checks this but in case its called from elsewhere */ @@ -3472,7 +3473,6 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri } else { for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) { - Object *camera; char name[FILE_MAX]; /* only border now, todo: camera lens. (ton) */ @@ -3571,10 +3571,6 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri do_render_all_options(re); totrendered++; - /* save render result stamp if needed */ - camera = RE_GetCamera(re); - BKE_render_result_stamp_info(scene, camera, re->result); - if (re->test_break(re->tbh) == 0) { if (!G.is_break) if (!do_write_image_or_movie(re, bmain, scene, mh, totvideos, NULL)) -- cgit v1.2.3 From 818a0cdc7687c42bde76d372bfed0c6c15c153f9 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Wed, 22 Apr 2015 12:03:06 +0200 Subject: Fix stamp missing after multiview merge. Was not using acquired render result correctly, most likely a copy paste error. --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 73f837e095a..a1fbe7c5365 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2484,7 +2484,7 @@ static void renderresult_stampinfo(Render *re) for (rv = re->result->views.first;rv;rv = rv->next, nr++) { RE_SetActiveRenderView(re, rv->name); RE_AcquireResultImage(re, &rres, nr); - BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rv->rect32, rv->rectf, rres.rectx, rres.recty, 4); + BKE_image_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4); RE_ReleaseResultImage(re); } } -- cgit v1.2.3 From 4a8421faa45c89399cb58ea7b372a6fe65721a55 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 22 Apr 2015 16:38:30 -0300 Subject: Fix T44463 - crash on "Full Sample" --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index a1fbe7c5365..7b5692fbdb6 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2233,7 +2233,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) } } - for (nr = 0, rv = re->result->views.first; rv; rv = rv->next, nr++) { + for (nr = 0, rv = rectfs->first; rv; rv = rv->next, nr++) { rectf = rv->rectf; /* ensure we get either composited result or the active layer */ -- cgit v1.2.3 From f8540d7fd5a47bc9d1d676d5aaaa0de379c71637 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Tue, 28 Apr 2015 17:36:44 -0300 Subject: RenderResult should have a valid view whenever possible --- source/blender/render/intern/source/pipeline.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7b5692fbdb6..7206c21de9e 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -747,6 +747,7 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, re->result = MEM_callocN(sizeof(RenderResult), "new render result"); re->result->rectx = re->rectx; re->result->recty = re->recty; + render_result_view_new(re->result, "new temporary view"); } if (re->r.scemode & R_VIEWPORT_PREVIEW) -- cgit v1.2.3 From b033736eb7ea65d47bc3cb13605df176c490efe1 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 29 Apr 2015 11:18:18 -0300 Subject: Multi-View: new util functions RE_RenderViewGetById() and RE_RenderViewGetByName() Both functions try to find a valid RenderView and if they can't they fallback to the first RenderView of the RenderResult --- source/blender/render/intern/source/pipeline.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7206c21de9e..c26a74f18c5 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -395,9 +395,7 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) rr->recty = re->result->recty; /* actview view */ - rv = BLI_findlink(&re->result->views, view_id); - if (rv == NULL) - rv = (RenderView *)re->result->views.first; + rv = RE_RenderViewGetById(re->result, view_id); rr->rectf = rv ? rv->rectf : NULL; rr->rectz = rv ? rv->rectz : NULL; @@ -2287,7 +2285,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) /* store the final result */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - rv = BLI_findlink(&re->result->views, nr); + rv = RE_RenderViewGetById(re->result, nr); if (rv->rectf) MEM_freeN(rv->rectf); rv->rectf = rectf; @@ -2571,7 +2569,7 @@ static void do_render_seq(Render *re) BLI_rw_mutex_unlock(&re->resultmutex); for (view_id = 0; view_id < tot_views; view_id++) { - RenderView *rv = BLI_findlink(&rr->views, view_id); + RenderView *rv = RE_RenderViewGetById(rr, view_id); BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if (ibuf_arr[view_id]) { -- cgit v1.2.3 From 3e6a66b9dee4e0b034a1de83fbd242191858a7df Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 29 Apr 2015 11:26:30 -0300 Subject: Multi-View cleanup: using RenderResult->rect* only for temporary RenderResults Originally I wanted to get rid of RenderResult->rect* entirely, but it's convenient to have for temporary structs. This patch makes sure they are used only when really needed, which should help clearing the code out. (they are needed when using RE_AcquireResultImage() - which produces a RenderResult with no RenderView) Reviewers: sergey Differential Revision: https://developer.blender.org/D1270 --- source/blender/render/intern/source/pipeline.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index c26a74f18c5..a4089002ba5 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -380,6 +380,8 @@ void RE_ReleaseResultImageViews(Render *re, RenderResult *rr) } /* fill provided result struct with what's currently active or done */ +/* this RenderResult struct is the only exception to the rule of a RenderResult */ +/* always having at least one RenderView */ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) { memset(rr, 0, sizeof(RenderResult)); @@ -397,14 +399,14 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) /* actview view */ rv = RE_RenderViewGetById(re->result, view_id); - rr->rectf = rv ? rv->rectf : NULL; - rr->rectz = rv ? rv->rectz : NULL; - rr->rect32 = rv ? rv->rect32 : NULL; + rr->rectf = rv->rectf; + rr->rectz = rv->rectz; + rr->rect32 = rv->rect32; /* active layer */ rl = render_get_active_layer(re, re->result); - if (rl && rv) { + if (rl) { if (rv->rectf == NULL) rr->rectf = RE_RenderLayerGetPass(rl, SCE_PASS_COMBINED, rv->name); @@ -412,7 +414,7 @@ void RE_AcquireResultImage(Render *re, RenderResult *rr, const int view_id) rr->rectz = RE_RenderLayerGetPass(rl, SCE_PASS_Z, rv->name); } - rr->have_combined = rv ? (rv->rectf != NULL) : false; + rr->have_combined = (rv->rectf != NULL); rr->layers = re->result->layers; rr->views = re->result->views; @@ -434,9 +436,9 @@ void RE_ResultGet32(Render *re, unsigned int *rect) RenderResult rres; const size_t view_id = BKE_scene_multiview_view_id_get(&re->r, re->viewname); - RE_AcquireResultImage(re, &rres, view_id); - render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, 0); - RE_ReleaseResultImage(re); + RE_AcquireResultImageViews(re, &rres); + render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings, view_id); + RE_ReleaseResultImageViews(re, &rres); } /* caller is responsible for allocating rect in correct size! */ @@ -768,11 +770,14 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, static void render_result_rescale(Render *re) { RenderResult *result = re->result; + RenderView *rv; int x, y; float scale_x, scale_y; float *src_rectf; - src_rectf = result->rectf; + rv = RE_RenderViewGetById(result, 0); + src_rectf = rv->rectf; + if (src_rectf == NULL) { RenderLayer *rl = render_get_active_layer(re, re->result); if (rl != NULL) { @@ -790,7 +795,7 @@ static void render_result_rescale(Render *re) ""); if (re->result != NULL) { - dst_rectf = re->result->rectf; + dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf; if (dst_rectf == NULL) { RenderLayer *rl; rl = render_get_active_layer(re, re->result); -- cgit v1.2.3 From df422314c10bb6ef0b33afa4d203916823efa976 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Wed, 6 May 2015 13:58:06 +0200 Subject: Only use render view name in render filenames if we are actually using multiview. --- source/blender/render/intern/source/pipeline.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index a4089002ba5..7f08e576747 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3121,10 +3121,11 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen BLI_strncpy(filepath, name, sizeof(filepath)); for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) { - BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); + if (!is_mono) { + BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name); + } if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) { - RE_WriteRenderResult(reports, rr, name, &rd->im_format, false, rv->name); printf("Saved: %s\n", name); } -- cgit v1.2.3 From bac735380189c63d2b8824cba8e0398bb35e9af2 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 12 May 2015 15:05:57 +0500 Subject: Depsgraph: New dependency graph integration commit This commit integrates the work done so far on the new dependency graph system, where goal was to replace legacy depsgraph with the new one, supporting loads of neat features like: - More granular dependency relation nature, which solves issues with fake cycles in the dependencies. - Move towards all-animatable, by better integration of drivers into the system. - Lay down some basis for upcoming copy-on-write, overrides and so on. The new system is living side-by-side with the previous one and disabled by default, so nothing will become suddenly broken. The way to enable new depsgraph is to pass `--new-depsgraph` command line argument. It's a bit early to consider the system production-ready, there are some TODOs and issues were discovered during the merge period, they'll be addressed ASAP. But it's important to merge, because it's the only way to attract artists to really start testing this system. There are number of assorted documents related on the design of the new system: * http://wiki.blender.org/index.php/User:Aligorith/GSoC2013_Depsgraph#Design_Documents * http://wiki.blender.org/index.php/User:Nazg-gul/DependencyGraph There are also some user-related information online: * http://code.blender.org/2015/02/blender-dependency-graph-branch-for-users/ * http://code.blender.org/2015/03/more-dependency-graph-tricks/ Kudos to everyone who was involved into the project: - Joshua "Aligorith" Leung -- design specification, initial code - Lukas "lukas_t" Toenne -- integrating code into blender, with further fixes - Sergey "Sergey" "Sharybin" -- some mocking around, trying to wrap up the project and so - Bassam "slikdigit" Kurdali -- stressing the new system, reporting all the issues and recording/writing documentation. - Everyone else who i forgot to mention here :) --- source/blender/render/intern/source/pipeline.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 7f08e576747..bdf67434725 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -84,6 +84,8 @@ # include "FRS_freestyle.h" #endif +#include "DEG_depsgraph.h" + /* internal */ #include "render_result.h" #include "render_types.h" @@ -467,8 +469,7 @@ Render *RE_NewRender(const char *name) BLI_strncpy(re->name, name, RE_MAXNAME); BLI_rw_mutex_init(&re->resultmutex); BLI_rw_mutex_init(&re->partsmutex); - re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx"); - re->eval_ctx->mode = DAG_EVAL_RENDER; + re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER); } RE_InitRenderCB(re); -- cgit v1.2.3 From c78df8f9ee9cff5f2c217035327a4888085b1d35 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 13 May 2015 01:00:03 -0300 Subject: Duplicate Render->RenderData.views for thread safety (as we do for layers) This fixes nothing at the moment, but better safe than sorry since there are still a few strange multiview issues around. --- source/blender/render/intern/source/pipeline.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index bdf67434725..3d61cd43dba 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -509,7 +509,8 @@ void RE_FreeRender(Render *re) BLI_rw_mutex_end(&re->partsmutex); BLI_freelistN(&re->r.layers); - + BLI_freelistN(&re->r.views); + /* main dbase can already be invalid now, some database-free code checks it */ re->main = NULL; re->scene = NULL; @@ -656,8 +657,10 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, /* copy render data and render layers for thread safety */ BLI_freelistN(&re->r.layers); + BLI_freelistN(&re->r.views); re->r = *rd; BLI_duplicatelist(&re->r.layers, &rd->layers); + BLI_duplicatelist(&re->r.views, &rd->views); if (source) { /* reuse border flags from source renderer */ @@ -866,6 +869,10 @@ void render_update_anim_renderdata(Render *re, RenderData *rd) /* render layers */ BLI_freelistN(&re->r.layers); BLI_duplicatelist(&re->r.layers, &rd->layers); + + /* render views */ + BLI_freelistN(&re->r.views); + BLI_duplicatelist(&re->r.views, &rd->views); } void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) -- cgit v1.2.3 From 4c0f0eb33897464144735000837a99e86530e3cc Mon Sep 17 00:00:00 2001 From: Tamito Kajiyama Date: Sat, 16 May 2015 23:55:45 +0900 Subject: Fix T44691 Freestyle render crashes when Views is on (Blender Internal). In pipeline.c the function add_freestyle() was supposed to be called once per frame, but after the Multi-view merge the function are called as many as the number of views. There were however a few Freestyle parameters that have to be initialized per frame, and initializing one of the parameters for each view was causing double freeing of allocated memory which was enough to result in a crash. --- source/blender/render/intern/source/pipeline.c | 74 ++++++++++++++++---------- 1 file changed, 47 insertions(+), 27 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 3d61cd43dba..9407412a6d0 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1377,6 +1377,7 @@ static void threaded_tile_processor(Render *re) } #ifdef WITH_FREESTYLE +static void init_freestyle(Render *re); static void add_freestyle(Render *re, int render); static void free_all_freestyle_renders(void); #endif @@ -1394,8 +1395,8 @@ void RE_TileProcessor(Render *re) /* Freestyle */ if (re->r.mode & R_EDGE_FRS) { if (!re->test_break(re->tbh)) { + init_freestyle(re); add_freestyle(re, 1); - free_all_freestyle_renders(); re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime; @@ -1430,6 +1431,12 @@ static void do_render_3d(Render *re) /* init main render result */ main_render_result_new(re); +#ifdef WITH_FREESTYLE + if (re->r.mode & R_EDGE_FRS) { + init_freestyle(re); + } +#endif + /* we need a new database for each view */ for (rv = re->result->views.first; rv; rv = rv->next) { RE_SetActiveRenderView(re, rv->name); @@ -2065,6 +2072,23 @@ static void render_composit_stats(void *UNUSED(arg), const char *str) } #ifdef WITH_FREESTYLE +/* init Freestyle renderer */ +static void init_freestyle(Render *re) +{ + re->freestyle_bmain = BKE_main_new(); + + /* We use the same window manager for freestyle bmain as + * real bmain uses. This is needed because freestyle's + * bmain could be used to tag scenes for update, which + * implies call of ED_render_scene_update in some cases + * and that function requires proper window manager + * to present (sergey) + */ + re->freestyle_bmain->wm = re->main->wm; + + FRS_init_stroke_renderer(re); +} + /* invokes Freestyle stroke rendering */ static void add_freestyle(Render *re, int render) { @@ -2075,18 +2099,7 @@ static void add_freestyle(Render *re, int render) actsrl = BLI_findlink(&re->r.layers, re->r.actlay); - re->freestyle_bmain = BKE_main_new(); - - /* We use the same window manager for freestyle bmain as - * real bmain uses. This is needed because freestyle's - * bmain could be used to tag scenes for update, which - * implies call of ED_render_scene_update in some cases - * and that function requires proper window manager - * to present (sergey) - */ - re->freestyle_bmain->wm = re->main->wm; - - FRS_init_stroke_rendering(re); + FRS_begin_stroke_rendering(re); for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) { if (do_link) { @@ -2102,7 +2115,7 @@ static void add_freestyle(Render *re, int render) } } - FRS_finish_stroke_rendering(re); + FRS_end_stroke_rendering(re); /* restore the global R value (invalidated by nested execution of the internal renderer) */ R = *re; @@ -2112,28 +2125,32 @@ static void add_freestyle(Render *re, int render) static void composite_freestyle_renders(Render *re, int sample) { Render *freestyle_render; + RenderView *rv; SceneRenderLayer *srl, *actsrl; LinkData *link; actsrl = BLI_findlink(&re->r.layers, re->r.actlay); link = (LinkData *)re->freestyle_renders.first; - for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) { - if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) - continue; - if (FRS_is_freestyle_enabled(srl)) { - freestyle_render = (Render *)link->data; + for (rv = re->result->views.first; rv; rv = rv->next) { + for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) { + if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl) + continue; - /* may be NULL in case of empty render layer */ - if (freestyle_render) { - render_result_exr_file_read_sample(freestyle_render, sample); - FRS_composite_result(re, srl, freestyle_render); - RE_FreeRenderResult(freestyle_render->result); - freestyle_render->result = NULL; + if (FRS_is_freestyle_enabled(srl)) { + freestyle_render = (Render *)link->data; + + /* may be NULL in case of empty render layer */ + if (freestyle_render) { + render_result_exr_file_read_sample(freestyle_render, sample); + FRS_composite_result(re, srl, freestyle_render); + RE_FreeRenderResult(freestyle_render->result); + freestyle_render->result = NULL; + } } + link = link->next; } - link = link->next; } } @@ -2375,8 +2392,10 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree) re->display_clear(re->dch, re->result); #ifdef WITH_FREESTYLE - if (re->r.mode & R_EDGE_FRS) + if (re->r.mode & R_EDGE_FRS) { + init_freestyle(re); add_freestyle(re, 0); + } #endif do_merge_fullsample(re, ntree); @@ -3095,6 +3114,7 @@ void RE_RenderFreestyleExternal(Render *re) if (!re->test_break(re->tbh)) { RE_Database_FromScene(re, re->main, re->scene, re->lay, 1); RE_Database_Preprocess(re); + init_freestyle(re); add_freestyle(re, 1); RE_Database_Free(re); } -- cgit v1.2.3 From 947b756d5e8af3d056fe0a7cabc7a8e376732255 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 18 May 2015 10:57:59 -0300 Subject: Multi-View: small cleranup/refactor with RE_pass_find_by_type and RE_RenderLayerGetPass --- source/blender/render/intern/source/pipeline.c | 33 ++++++++++---------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 9407412a6d0..64ed8f1153a 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -195,21 +195,8 @@ void RE_FreeRenderResult(RenderResult *res) float *RE_RenderLayerGetPass(volatile RenderLayer *rl, int passtype, const char *viewname) { - RenderPass *rpass; - float *rect = NULL; - - for (rpass = rl->passes.last; rpass; rpass = rpass->prev) { - if (rpass->passtype == passtype) { - rect = rpass->rect; - - if (viewname == NULL) - break; - else if (STREQ(rpass->view, viewname)) - break; - } - } - - return rect; + RenderPass *rpass = RE_pass_find_by_type(rl, passtype, viewname); + return rpass ? rpass->rect : NULL; } RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) @@ -3893,14 +3880,18 @@ bool RE_layers_have_name(struct RenderResult *rr) return false; } -RenderPass *RE_pass_find_by_type(RenderLayer *rl, int passtype, const char *viewname) +RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname) { - RenderPass *rp; - for (rp = rl->passes.first; rp; rp = rp->next) { + RenderPass *rp = NULL; + + for (rp = rl->passes.last; rp; rp = rp->prev) { if (rp->passtype == passtype) { - if (STREQ(rp->view, viewname)) - return rp; + + if (viewname == NULL) + break; + else if (STREQ(rp->view, viewname)) + break; } } - return NULL; + return rp; } -- cgit v1.2.3 From 3a7691b73f5f80dc339631909682786c2a4c2e68 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 25 May 2015 10:14:19 -0300 Subject: Fix T44836: crash when multi-view is enabled and switching to BI rendered viewport display --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 64ed8f1153a..47301aa7d6d 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3887,7 +3887,7 @@ RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const c for (rp = rl->passes.last; rp; rp = rp->prev) { if (rp->passtype == passtype) { - if (viewname == NULL) + if (viewname == NULL || viewname[0] == '\0') break; else if (STREQ(rp->view, viewname)) break; -- cgit v1.2.3 From c449d4e33694baf7f72f0b22d0377ecf6d8a5d39 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Wed, 27 May 2015 14:41:31 +0200 Subject: Fix jpeg preview for exr renders broken. --- source/blender/render/intern/source/pipeline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 47301aa7d6d..82350e09dca 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3178,10 +3178,10 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen if (stamp) { /* writes the name of the individual cameras */ - ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &rd->im_format); + ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, &imf); } else { - ok = BKE_imbuf_write(ibuf, name, &rd->im_format); + ok = BKE_imbuf_write(ibuf, name, &imf); } printf("Saved: %s\n", name); } -- cgit v1.2.3 From b52af946cd92993dd6918797214d956070813878 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Wed, 27 May 2015 14:43:54 +0200 Subject: Forgot this in the last commit --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 82350e09dca..f8eb133e855 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -3174,7 +3174,7 @@ bool RE_WriteRenderViewsImage(ReportList *reports, RenderResult *rr, Scene *scen ibuf->planes = 24; IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings, - &scene->display_settings, &rd->im_format); + &scene->display_settings, &imf); if (stamp) { /* writes the name of the individual cameras */ -- cgit v1.2.3 From 8dc6fabc34a918ab3a82f93b56d539c4694a8c21 Mon Sep 17 00:00:00 2001 From: Antony Riakiotakis Date: Thu, 28 May 2015 17:01:09 +0200 Subject: Optimize render part commiting to render queue to mitigate delay in T44869. There are a couple of issues here: * Code repeatedly calculated center of ready rendered parts even though they would not change while the operation was done. * Code would calculate distance of tiles from center multiple times * Code would traverse all items, even the ones already sorted * Traversal used linked lists which is quite slow. Mitigated these by doing one pass for the center, a second to calculate distances and a qsort at the end. Should result in O (n * (log n + 2)) instead of O (n * (n * 2)) complexity, plus the number of repeated operations is much less as well. --- source/blender/render/intern/source/pipeline.c | 78 +++++++++++++++++--------- 1 file changed, 53 insertions(+), 25 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index f8eb133e855..af6ea2bc81f 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1113,13 +1113,28 @@ static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewpl return found; } -static RenderPart *find_next_part(Render *re, int minx) +typedef struct SortRenderPart { + RenderPart *pa; + long long int dist; +} SortRenderPart; + +static int sort_render_part(const void *pa1, const void *pa2) { + const SortRenderPart *rpa1 = pa1; + const SortRenderPart *rpa2 = pa2; + + if (rpa1->dist > rpa2->dist) return 1; + else if (rpa1->dist < rpa2->dist) return -1; + + return 0; +} + +static int sort_and_queue_parts(Render *re, int minx, ThreadQueue *workqueue) { - RenderPart *pa, *best = NULL; + RenderPart *pa; /* long long int's needed because of overflow [#24414] */ long long int centx = re->winx / 2, centy = re->winy / 2, tot = 1; - long long int mindist = (long long int)re->winx * (long long int)re->winy; + int totsort = 0; /* find center of rendered parts, image center counts for 1 too */ for (pa = re->parts.first; pa; pa = pa->next) { @@ -1128,31 +1143,48 @@ static RenderPart *find_next_part(Render *re, int minx) centy += BLI_rcti_cent_y(&pa->disprect); tot++; } + else if (pa->status == PART_STATUS_NONE && pa->nr == 0) { + if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) { + totsort++; + } + } } centx /= tot; centy /= tot; - /* closest of the non-rendering parts */ - for (pa = re->parts.first; pa; pa = pa->next) { - if (pa->status == PART_STATUS_NONE && pa->nr == 0) { - long long int distx = centx - BLI_rcti_cent_x(&pa->disprect); - long long int disty = centy - BLI_rcti_cent_y(&pa->disprect); - distx = (long long int)sqrt(distx * distx + disty * disty); - if (distx < mindist) { - if (re->r.mode & R_PANORAMA) { - if (pa->disprect.xmin == minx) { - best = pa; - mindist = distx; - } - } - else { - best = pa; - mindist = distx; + if (totsort > 0) { + SortRenderPart *sortlist = MEM_mallocN(sizeof(*sortlist) * totsort, "renderpartsort"); + long int i = 0; + + /* prepare the list */ + for (pa = re->parts.first; pa; pa = pa->next) { + if (pa->status == PART_STATUS_NONE && pa->nr == 0) { + if (!(re->r.mode & R_PANORAMA) || pa->disprect.xmin == minx) { + long long int distx = centx - BLI_rcti_cent_x(&pa->disprect); + long long int disty = centy - BLI_rcti_cent_y(&pa->disprect); + sortlist[i].dist = (long long int)sqrt(distx * distx + disty * disty); + sortlist[i].pa = pa; + i++; } } } + + /* Now sort it */ + qsort(sortlist, totsort, sizeof(*sortlist), sort_render_part); + + /* Finally flush it to the workqueue */ + for (i = 0; i < totsort; i++) { + pa = sortlist[i].pa; + pa->nr = i + 1; /* for nicest part, and for stats */ + BLI_thread_queue_push(workqueue, pa); + } + + MEM_freeN(sortlist); + + return totsort; } - return best; + + return 0; } static void print_part_stats(Render *re, RenderPart *pa) @@ -1264,11 +1296,7 @@ static void threaded_tile_processor(Render *re) /* for panorama we loop over slices */ while (find_next_pano_slice(re, &slice, &minx, &viewplane)) { /* gather parts into queue */ - while ((pa = find_next_part(re, minx))) { - pa->nr = totpart + 1; /* for nicest part, and for stats */ - totpart++; - BLI_thread_queue_push(workqueue, pa); - } + totpart = sort_and_queue_parts(re, minx, workqueue); BLI_thread_queue_nowait(workqueue); -- cgit v1.2.3 From ab417f31f403d74a76fb51fbd6e2aa3f706e15f1 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 10 Jun 2015 13:35:11 +0200 Subject: Fix/Workaround T44662: Freestyle gives no visual output when the Save Buffers option is enabled For now we solve this for non-multiview renders by merging exr file back into full render result prior to rendering freestyle strokes. Multiview case is still to be supported tho. --- source/blender/render/intern/source/pipeline.c | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index af6ea2bc81f..cac4970cd11 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -121,6 +121,17 @@ * */ +/* Freestyle needs the whole frame to be merged into memory prior to + * doing stroke rendering. This conflicts a bit with multiview save + * buffers behavior which does a merge of exr files after all the + * views are rendered. + * + * For until a proper solution is implemented we'll just merge single + * view image prior to freestyle stroke rendering, which is how this + * worked prior to multiview. Multiview+freestyle+save buffers are + * considered unsupported for the time being. + */ +#define FREESTYLR_SAVEBUFFERS_WORKAROUND /* ********* globals ******** */ @@ -1426,6 +1437,9 @@ void RE_TileProcessor(Render *re) static void do_render_3d(Render *re) { +#ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND + const bool do_early_result_merge = (re->r.scemode & R_MULTIVIEW) == 0; +#endif RenderView *rv; int cfra_backup; @@ -1473,7 +1487,13 @@ static void do_render_3d(Render *re) re->draw_lock(re->dlh, 0); threaded_tile_processor(re); - + +#ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND + if (do_early_result_merge) { + main_render_result_end(re); + } +#endif + #ifdef WITH_FREESTYLE /* Freestyle */ if (re->r.mode & R_EDGE_FRS) @@ -1490,7 +1510,13 @@ static void do_render_3d(Render *re) RE_Database_Free(re); } +#ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND + if (!do_early_result_merge) { + main_render_result_end(re); + } +#else main_render_result_end(re); +#endif re->scene->r.cfra = cfra_backup; re->scene->r.subframe = 0.f; @@ -2929,6 +2955,13 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList * BKE_report(reports, RPT_ERROR, "Fields not supported in Freestyle"); return false; } + +# ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND + if ((scene->r.scemode & R_MULTIVIEW) != 0 && (scene->r.scemode & R_EXR_TILE_FILE) != 0) { + BKE_report(reports, RPT_ERROR, "Multiview combined with Save Buffers not supported in Freestyle"); + return false; + } +# endif } #endif -- cgit v1.2.3 From 087c82e392bc4cd175421fc5bc5faa88d218c224 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 10 Jun 2015 16:23:19 -0300 Subject: Error message fix - In the manual (thus for the user) we are referring to this as "Multi-View", not "Multiview" --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index cac4970cd11..001120d883f 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2958,7 +2958,7 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList * # ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND if ((scene->r.scemode & R_MULTIVIEW) != 0 && (scene->r.scemode & R_EXR_TILE_FILE) != 0) { - BKE_report(reports, RPT_ERROR, "Multiview combined with Save Buffers not supported in Freestyle"); + BKE_report(reports, RPT_ERROR, "Multi-View combined with Save Buffers not supported in Freestyle"); return false; } # endif -- cgit v1.2.3 From bcc4957877e9f32601eee3ed2c27f1ef4450aca5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 17 Jun 2015 15:49:09 +0200 Subject: Flush stdout prior of calling render stats callback Without this extra flush order of stat prints is undefined in the output. which makes it rather tricky to write custom output in a reliable way. --- source/blender/render/intern/source/pipeline.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 001120d883f..e2f82cb59ca 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -193,6 +193,9 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) fprintf(stdout, IFACE_("Sce: %s Ve:%d Fa:%d La:%d"), rs->scene_name, rs->totvert, rs->totface, rs->totlamp); } + /* Flush stdout to be sure python callbacks are printing stuff after blender. */ + fflush(stdout); + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS); fputc('\n', stdout); @@ -3436,7 +3439,10 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie BLI_timestr(re->i.lastframetime, name, sizeof(name)); printf(" Time: %s", name); - + + /* Flush stdout to be sure python callbacks are printing stuff after blender. */ + fflush(stdout); + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_RENDER_STATS); BLI_timestr(re->i.lastframetime - render_time, name, sizeof(name)); -- cgit v1.2.3 From 0119c63405a1fcc66600cc650cec331f27ece712 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 17 Jun 2015 16:06:33 +0200 Subject: Print elapsed time when rendering from the command line --- source/blender/render/intern/source/pipeline.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e2f82cb59ca..20883aa0cc1 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -165,6 +165,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) { uintptr_t mem_in_use, mmap_in_use, peak_memory; float megs_used_memory, mmap_used_memory, megs_peak_memory; + char info_time_str[32]; mem_in_use = MEM_get_memory_in_use(); mmap_in_use = MEM_get_mapped_memory_in_use(); @@ -182,8 +183,11 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) if (rs->curblur) fprintf(stdout, IFACE_("Blur %d "), rs->curblur); + BLI_timestr(PIL_check_seconds_timer() - rs->starttime, info_time_str, sizeof(info_time_str)); + fprintf(stdout, IFACE_("| Time:%s | "), info_time_str); + if (rs->infostr) { - fprintf(stdout, "| %s", rs->infostr); + fprintf(stdout, "%s", rs->infostr); } else { if (rs->tothalo) -- cgit v1.2.3 From 01f21f8026474018067494952f5842104550e76b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 17 Jun 2015 16:29:51 +0200 Subject: Report proper frame and time to the console when doing compositing --- source/blender/render/intern/source/pipeline.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 20883aa0cc1..f2851e23c32 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2520,6 +2520,8 @@ static void do_render_composite_fields_blur_3d(Render *re) /* in case it was never initialized */ R.sdh = re->sdh; R.stats_draw = re->stats_draw; + R.i.starttime = re->i.starttime; + R.i.cfra = re->i.cfra; if (update_newframe) BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay); -- cgit v1.2.3 From fc35b758ade7062b194076c7dd3b848792c1a4ea Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 17 Jun 2015 17:48:15 +0200 Subject: Fix T44682: Save Buffers canceled renders show nothing in Image Editor The issue was caused by render pipeline freeing render parts prior to finishing exr file writing which resulted in unfinished parts not being written into the file by save_empty_result_tiles(). As a temporary solution we do explicitly write unfinished parts as empty tiles to the exr file prior to freeing parts. Not ideal solution, but should work for the release. --- source/blender/render/intern/source/pipeline.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index f2851e23c32..29822b96221 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -1400,7 +1400,13 @@ static void threaded_tile_processor(Render *re) BLI_thread_queue_free(donequeue); BLI_thread_queue_free(workqueue); - + + if (re->result->do_exr_tile) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_save_empty_result_tiles(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } + /* unset threadsafety */ g_break = 0; BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE); -- cgit v1.2.3 From da61c36f2a8e57d4be3eb0d989200262042e770c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 17 Jun 2015 18:02:02 +0200 Subject: Revert "Fix/Workaround T44662: Freestyle gives no visual output when the Save Buffers option is enabled" This reverts commit ab417f31f403d74a76fb51fbd6e2aa3f706e15f1. This workaround caused serious memory corruption issues which is not really acceptable for the release. We'll be likely sticking to a more limited release when using freestyle with saved buffers for until proper solution is implemented. Conflicts: source/blender/render/intern/source/pipeline.c --- source/blender/render/intern/source/pipeline.c | 35 +------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 29822b96221..9444d3ef3c6 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -121,17 +121,6 @@ * */ -/* Freestyle needs the whole frame to be merged into memory prior to - * doing stroke rendering. This conflicts a bit with multiview save - * buffers behavior which does a merge of exr files after all the - * views are rendered. - * - * For until a proper solution is implemented we'll just merge single - * view image prior to freestyle stroke rendering, which is how this - * worked prior to multiview. Multiview+freestyle+save buffers are - * considered unsupported for the time being. - */ -#define FREESTYLR_SAVEBUFFERS_WORKAROUND /* ********* globals ******** */ @@ -1450,9 +1439,6 @@ void RE_TileProcessor(Render *re) static void do_render_3d(Render *re) { -#ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND - const bool do_early_result_merge = (re->r.scemode & R_MULTIVIEW) == 0; -#endif RenderView *rv; int cfra_backup; @@ -1500,13 +1486,7 @@ static void do_render_3d(Render *re) re->draw_lock(re->dlh, 0); threaded_tile_processor(re); - -#ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND - if (do_early_result_merge) { - main_render_result_end(re); - } -#endif - + #ifdef WITH_FREESTYLE /* Freestyle */ if (re->r.mode & R_EDGE_FRS) @@ -1523,13 +1503,7 @@ static void do_render_3d(Render *re) RE_Database_Free(re); } -#ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND - if (!do_early_result_merge) { - main_render_result_end(re); - } -#else main_render_result_end(re); -#endif re->scene->r.cfra = cfra_backup; re->scene->r.subframe = 0.f; @@ -2970,13 +2944,6 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList * BKE_report(reports, RPT_ERROR, "Fields not supported in Freestyle"); return false; } - -# ifdef FREESTYLR_SAVEBUFFERS_WORKAROUND - if ((scene->r.scemode & R_MULTIVIEW) != 0 && (scene->r.scemode & R_EXR_TILE_FILE) != 0) { - BKE_report(reports, RPT_ERROR, "Multi-View combined with Save Buffers not supported in Freestyle"); - return false; - } -# endif } #endif -- cgit v1.2.3 From 973afa0172a66b3d0921ec1d6fd28c6acc6afdbf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 20 Jun 2015 17:09:05 +1000 Subject: Cleanup: use listbase clear --- source/blender/render/intern/source/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/render/intern/source/pipeline.c') diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 9444d3ef3c6..1fa2673f12c 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2205,7 +2205,7 @@ static void free_all_freestyle_renders(void) /* detach the window manager from freestyle bmain (see comments * in add_freestyle() for more detail) */ - re1->freestyle_bmain->wm.first = re1->freestyle_bmain->wm.last = NULL; + BLI_listbase_clear(&re1->freestyle_bmain->wm); BKE_main_free(re1->freestyle_bmain); re1->freestyle_bmain = NULL; -- cgit v1.2.3