Changes to partial update during rendering
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 17 Dec 2013 17:42:38 +0000 (23:42 +0600)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 17 Dec 2013 17:42:38 +0000 (23:42 +0600)
Summary:
Mainly addressed to solve old TODO with color managed fallback
to CPU mode when displaying render result during rendering.

That fallback was caused by the fact that partial image update
was always acquiring image buffer for composite output and was
only modifying display buffer directly.

This was a big issue for Cycles rendering which renders layers
one by one and wanted to display progress of each individual
layer. This lead to situations when display buffer was based on
what Cycles passes via RenderResult and didn't take layer/pass
from image editor header into account.

Now made it so image buffer which partial update is operating
with always corresponds to what is set in image editor header.

To make Cycles displaying progress of all the layers one by one
made it so image_rect_update switches image editor user to
newly rendering render layer. It happens only once when render
engine starts rendering next render layer, so should not be
annoying for navigation during rendering.

Additional change to render engines was done to make it so
they're able to merge composite output to final result
without marking tile as done. This is done via do_merge_result
argument to end_result() callback. This argument is optional
so should not break script compatibility.

Additional changes:

- Partial display update for Blender Internal now happens from
  the same thread as tile rendering. This makes it so display
  conversion (which could be pretty heavy actually) is done in
  separate threads. Also gives better UI feedback when rendering
  easy scene with small tiles.

- Avoid freeing/allocating byte buffer for render result
  if it's owned by the image buffer. Only mark it as invalid
  for color management.

  Saves loads of buffer re-allocations in cases when having
  several image editors opened with render result. This change
  in conjunction with the rest of the patch gave around
  50%-100% speedup of render time when displaying non-combined
  pass during rendering on my laptop.

- Partial display buffer update was wrong for buffers with number
  of channels different from 4.

- Remove unused window from RenderJob.

- Made image_buffer_rect_update static since it's only used
  in single file.

Reviewers: brecht

Reviewed By: brecht

CC: dingto
Differential Revision: http://developer.blender.org/D98

16 files changed:
intern/cycles/blender/blender_session.cpp
source/blender/blenkernel/intern/image.c
source/blender/editors/render/render_intern.h
source/blender/editors/render/render_internal.c
source/blender/editors/render/render_preview.c
source/blender/editors/render/render_view.c
source/blender/editors/screen/glutil.c
source/blender/imbuf/intern/colormanagement.c
source/blender/makesrna/intern/rna_render.c
source/blender/render/extern/include/RE_engine.h
source/blender/render/extern/include/RE_pipeline.h
source/blender/render/intern/include/render_types.h
source/blender/render/intern/source/envmap.c
source/blender/render/intern/source/external_engine.c
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/rendercore.c

index db673a8d6252a3e8443d3af491558c6f30522093..f81de7d529ad332302eb9b748ac6a1ed4e90b70e 100644 (file)
@@ -261,9 +261,9 @@ static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, in
        return b_engine.begin_result(x, y, w, h, layername);
 }
 
-static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel = false)
+static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel, bool do_merge_results)
 {
-       b_engine.end_result(b_rr, (int)cancel);
+       b_engine.end_result(b_rr, (int)cancel, (int)do_merge_results);
 }
 
 void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_update_only)
@@ -302,12 +302,12 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
                        update_render_result(b_rr, b_rlay, rtile);
                }
 
-               end_render_result(b_engine, b_rr, true);
+               end_render_result(b_engine, b_rr, true, true);
        }
        else {
                /* write result */
                write_render_result(b_rr, b_rlay, rtile);
-               end_render_result(b_engine, b_rr);
+               end_render_result(b_engine, b_rr, false, true);
        }
 }
 
@@ -352,7 +352,7 @@ void BlenderSession::render()
 
                /* layer will be missing if it was disabled in the UI */
                if(b_single_rlay == b_rr.layers.end()) {
-                       end_render_result(b_engine, b_rr, true);
+                       end_render_result(b_engine, b_rr, true, false);
                        continue;
                }
 
@@ -379,7 +379,7 @@ void BlenderSession::render()
                }
 
                /* free result without merging */
-               end_render_result(b_engine, b_rr, true);
+               end_render_result(b_engine, b_rr, true, false);
 
                buffer_params.passes = passes;
                scene->film->tag_passes_update(scene, passes);
index 51c70e8434a77c84988cdee1e59453ec812d8155..dc26cedbc46eed7f4f4977aa2ce2d77ee49b45e5 100644 (file)
@@ -2862,13 +2862,8 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_
        ibuf->x = rres.rectx;
        ibuf->y = rres.recty;
 
-       /* free rect buffer if float buffer changes, so it can be recreated with
-        * the updated result, and also in case we got byte buffer from sequencer,
-        * so we don't keep reference to freed buffer */
-       if (ibuf->rect_float != rectf || rect)
-               imb_freerectImBuf(ibuf);
-
        if (rect) {
+               imb_freerectImBuf(ibuf);
                ibuf->rect = rect;
        }
        else {
index eb09606e57eae46e8e6205056c45865106936e22..8f8cc542821a6ca3cb8d9891b0d209fcc81a3300 100644 (file)
@@ -35,6 +35,7 @@
 struct wmOperatorType;
 struct RenderResult;
 struct Scene;
+struct ScrArea;
 
 /* render_shading.c */
 void OBJECT_OT_material_slot_add(struct wmOperatorType *ot);
@@ -86,11 +87,8 @@ void RENDER_OT_render(struct wmOperatorType *ot);
 void render_view3d_update(struct RenderEngine *engine, const struct bContext *C);
 void render_view3d_draw(struct RenderEngine *engine, const struct bContext *C);
 
-/* render_opengl.c uses this */
-void image_buffer_rect_update(struct Scene *scene, struct RenderResult *rr, struct ImBuf *ibuf, volatile struct rcti *renrect);
-
 /* render_view.c */
-void render_view_open(struct bContext *C, int mx, int my);
+struct ScrArea *render_view_open(struct bContext *C, int mx, int my);
 
 void RENDER_OT_view_show(struct wmOperatorType *ot);
 void RENDER_OT_view_cancel(struct wmOperatorType *ot);
index 1b090cb16ec81cdce4afcf60e1150fc0a4dff977..7ecada993e2dd6614a7b0356462e98e84ee7f7c7 100644 (file)
 static int render_break(void *rjv);
 
 /* called inside thread! */
-void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect)
+static void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, ImageUser *iuser, volatile rcti *renrect)
 {
        float *rectf = NULL;
        int ymin, ymax, xmin, xmax;
        int rymin, rxmin;
+       int linear_stride, linear_offset_x, linear_offset_y;
+
+       if (ibuf->userflags & IB_DISPLAY_BUFFER_INVALID) {
+               /* The whole image buffer it so be color managed again anyway. */
+               return;
+       }
 
        /* if renrect argument, we only refresh scanlines */
        if (renrect) {
@@ -138,33 +144,55 @@ void image_buffer_rect_update(Scene *scene, RenderResult *rr, ImBuf *ibuf, volat
 
        if (xmax < 1 || ymax < 1) return;
 
-       /* find current float rect for display, first case is after composite... still weak */
-       if (rr->rectf)
-               rectf = rr->rectf;
-       else {
-               if (rr->rect32) {
-                       /* special case, currently only happens with sequencer rendering,
-                        * which updates the whole frame, so we can only mark display buffer
-                        * as invalid here (sergey)
-                        */
-                       ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-                       return;
-               }
+       /* The thing here is, the logic below (which was default behavior
+        * of how rectf is acquiring since forever) gives float buffer for
+        * composite output only. This buffer can not be used for other
+        * passes obviously.
+        *
+        * We might try finding corresponding for pass buffer in render result
+        * (which is actually missing when rendering with Cycles, who only
+        * writes all the passes when the tile is finished) or use float
+        * buffer from image buffer as reference, which is easier to use and
+        * contains all the data we need anyway.
+        *                                              - sergey -
+        */
+       /* TODO(sergey): Need to check has_combined here? */
+       if (iuser->pass == 0) {
+               /* find current float rect for display, first case is after composite... still weak */
+               if (rr->rectf)
+                       rectf = rr->rectf;
                else {
-                       if (rr->renlay == NULL || rr->renlay->rectf == NULL) return;
-                       rectf = rr->renlay->rectf;
+                       if (rr->rect32) {
+                               /* special case, currently only happens with sequencer rendering,
+                                * which updates the whole frame, so we can only mark display buffer
+                                * as invalid here (sergey)
+                                */
+                               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+                               return;
+                       }
+                       else {
+                               if (rr->renlay == NULL || rr->renlay->rectf == NULL) return;
+                               rectf = rr->renlay->rectf;
+                       }
                }
-       }
-       if (rectf == NULL) return;
+               if (rectf == NULL) return;
 
-       if (ibuf->rect == NULL)
-               imb_addrectImBuf(ibuf);
-
-       rectf += 4 * (rr->rectx * ymin + xmin);
+               rectf += 4 * (rr->rectx * ymin + xmin);
+               linear_stride = rr->rectx;
+               linear_offset_x = rxmin;
+               linear_offset_y = rymin;
+       }
+       else {
+               rectf = ibuf->rect_float;
+               linear_stride = ibuf->x;
+               linear_offset_x = 0;
+               linear_offset_y = 0;
+       }
 
-       IMB_partial_display_buffer_update(ibuf, rectf, NULL, rr->rectx, rxmin, rymin,
+       IMB_partial_display_buffer_update(ibuf, rectf, NULL,
+                                         linear_stride, linear_offset_x, linear_offset_y,
                                          &scene->view_settings, &scene->display_settings,
-                                         rxmin, rymin, rxmin + xmax, rymin + ymax, true);
+                                         rxmin, rymin, rxmin + xmax, rymin + ymax, false);
 }
 
 /* ****************************** render invoking ***************** */
@@ -262,7 +290,6 @@ typedef struct RenderJob {
        Main *main;
        Scene *scene;
        Render *re;
-       wmWindow *win;
        SceneRenderLayer *srl;
        struct Object *camera_override;
        int lay_override;
@@ -275,6 +302,9 @@ typedef struct RenderJob {
        short *do_update;
        float *progress;
        ReportList *reports;
+       int orig_layer;
+       int last_layer;
+       ScrArea *sa;
 } RenderJob;
 
 static void render_freejob(void *rjv)
@@ -402,6 +432,64 @@ static void render_progress_update(void *rjv, float progress)
        }
 }
 
+/* Not totally reliable, but works fine in most of cases and
+ * in worst case would just make it so extra color management
+ * for the whole render result is applied (which was already
+ * happening already).
+ */
+static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
+{
+       wmWindowManager *wm;
+       ScrArea *first_sa = NULL, *matched_sa = NULL;
+
+       /* image window, compo node users */
+       for (wm = rj->main->wm.first; wm && matched_sa == NULL; wm = wm->id.next) { /* only 1 wm */
+               wmWindow *win;
+               for (win = wm->windows.first; win && matched_sa == NULL; win = win->next) {
+                       ScrArea *sa;
+                       for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+                               if (sa->spacetype == SPACE_IMAGE) {
+                                       SpaceImage *sima = sa->spacedata.first;
+                                       if (sima->image == rj->image) {
+                                               if (first_sa == NULL) {
+                                                       first_sa = sa;
+                                               }
+                                               if (sa == rj->sa) {
+                                                       matched_sa = sa;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if (matched_sa == NULL) {
+               matched_sa = first_sa;
+       }
+
+       if (matched_sa) {
+               SpaceImage *sima = matched_sa->spacedata.first;
+               RenderResult *main_rr = RE_AcquireResultRead(rj->re);
+
+               /* TODO(sergey): is there faster way to get the layer index? */
+               if (rr->renlay) {
+                       int layer = BLI_findstringindex(&main_rr->layers,
+                                                       (char *)rr->renlay->name,
+                                                       offsetof(RenderLayer, name));
+                       if (layer != rj->last_layer) {
+                               sima->iuser.layer = layer;
+                               rj->last_layer = layer;
+                       }
+               }
+
+               iuser->pass = sima->iuser.pass;
+               iuser->layer = sima->iuser.layer;
+
+               RE_ReleaseResult(rj->re);
+       }
+}
+
 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
 {
        RenderJob *rj = rjv;
@@ -423,9 +511,17 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
        }
 
        /* update part of render */
+       render_image_update_pass_and_layer(rj, rr, &rj->iuser);
        ibuf = BKE_image_acquire_ibuf(ima, &rj->iuser, &lock);
        if (ibuf) {
-               image_buffer_rect_update(rj->scene, rr, ibuf, renrect);
+               /* Don't waste time on CPU side color management if
+                * image will be displayed using GLSL.
+                */
+               if (ibuf->channels == 1 ||
+                   U.image_draw_method != IMAGE_DRAW_METHOD_GLSL)
+               {
+                       image_buffer_rect_update(rj->scene, rr, ibuf, &rj->iuser, renrect);
+               }
 
                /* make jobs timer to send notifier */
                *(rj->do_update) = TRUE;
@@ -451,6 +547,28 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
        RE_SetReports(rj->re, NULL);
 }
 
+static void render_image_restore_layer(RenderJob *rj)
+{
+       wmWindowManager *wm;
+
+       /* image window, compo node users */
+       for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+               wmWindow *win;
+               for (win = wm->windows.first; win; win = win->next) {
+                       ScrArea *sa;
+                       for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+                               if (sa == rj->sa) {
+                                       if (sa->spacetype == SPACE_IMAGE) {
+                                               SpaceImage *sima = sa->spacedata.first;
+                                               sima->iuser.layer = rj->orig_layer;
+                                       }
+                                       return;
+                               }
+                       }
+               }
+       }
+}
+
 static void render_endjob(void *rjv)
 {
        RenderJob *rj = rjv;
@@ -481,6 +599,10 @@ static void render_endjob(void *rjv)
                WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
        }
 
+       if (rj->sa) {
+               render_image_restore_layer(rj);
+       }
+
        /* XXX render stability hack */
        G.is_rendering = FALSE;
        WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL);
@@ -592,6 +714,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
        struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
        const char *name;
        Object *active_object = CTX_data_active_object(C);
+       ScrArea *sa;
        
        /* only one render job at a time */
        if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER))
@@ -644,7 +767,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
        // store spare
 
        /* ensure at least 1 area shows result */
-       render_view_open(C, event->x, event->y);
+       sa = render_view_open(C, event->x, event->y);
 
        jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS;
        
@@ -658,7 +781,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
        rj = MEM_callocN(sizeof(RenderJob), "render job");
        rj->main = mainp;
        rj->scene = scene;
-       rj->win = CTX_wm_window(C);
        rj->srl = srl;
        rj->camera_override = camera_override;
        rj->lay_override = 0;
@@ -667,6 +789,14 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
        rj->iuser.scene = scene;
        rj->iuser.ok = 1;
        rj->reports = op->reports;
+       rj->orig_layer = 0;
+       rj->last_layer = 0;
+       rj->sa = sa;
+
+       if (sa) {
+               SpaceImage *sima = sa->spacedata.first;
+               rj->orig_layer = sima->iuser.layer;
+       }
 
        if (v3d) {
                if (scene->lay != v3d->lay) {
@@ -699,7 +829,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
        re = RE_NewRender(scene->id.name);
        RE_test_break_cb(re, rj, render_breakjob);
        RE_draw_lock_cb(re, rj, render_drawlock);
-       RE_display_draw_cb(re, rj, image_rect_update);
+       RE_display_update_cb(re, rj, image_rect_update);
        RE_stats_draw_cb(re, rj, image_renderinfo_cb);
        RE_progress_cb(re, rj, render_progress_update);
 
@@ -850,7 +980,7 @@ static int render_view3d_break(void *rpv)
        return *(rp->stop);
 }
 
-static void render_view3d_draw_update(void *rpv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect))
+static void render_view3d_display_update(void *rpv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect))
 {
        RenderPreview *rp = rpv;
        
@@ -908,7 +1038,7 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
        
        /* set this always, rp is different for each job */
        RE_test_break_cb(re, rp, render_view3d_break);
-       RE_display_draw_cb(re, rp, render_view3d_draw_update);
+       RE_display_update_cb(re, rp, render_view3d_display_update);
        RE_stats_draw_cb(re, rp, render_view3d_renderinfo_cb);
        
        rstats = RE_GetStats(re);
index 081187ef1d8aa4e42373c464a2d6fc957eccfb76..99f86371eb3a18924448dd04dd4d710413bd2141 100644 (file)
@@ -625,7 +625,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
 /* **************************** new shader preview system ****************** */
 
 /* inside thread, called by renderer, sets job update value */
-static void shader_preview_draw(void *spv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect))
+static void shader_preview_update(void *spv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect))
 {
        ShaderPreview *sp = spv;
        
@@ -734,7 +734,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
 
        /* callbacs are cleared on GetRender() */
        if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) {
-               RE_display_draw_cb(re, sp, shader_preview_draw);
+               RE_display_update_cb(re, sp, shader_preview_update);
        }
        /* set this for all previews, default is react to G.is_break still */
        RE_test_break_cb(re, sp, shader_preview_break);
index 1103f956f7816c4094e793f0f45ac7dd3a0acb99..9f72ddc179faf02caafefab726cbc969d8c9118e 100644 (file)
@@ -132,7 +132,7 @@ static ScrArea *find_area_image_empty(bContext *C)
 /********************** open image editor for render *************************/
 
 /* new window uses x,y to set position */
-void render_view_open(bContext *C, int mx, int my)
+ScrArea *render_view_open(bContext *C, int mx, int my)
 {
        wmWindow *win = CTX_wm_window(C);
        Scene *scene = CTX_data_scene(C);
@@ -141,7 +141,7 @@ void render_view_open(bContext *C, int mx, int my)
        int area_was_image = 0;
 
        if (scene->r.displaymode == R_OUTPUT_NONE)
-               return;
+               return NULL;
        
        if (scene->r.displaymode == R_OUTPUT_WINDOW) {
                rcti rect;
@@ -226,6 +226,8 @@ void render_view_open(bContext *C, int mx, int my)
                         * full screen to the original tiled setup */
                }
        }
+
+       return sa;
 }
 
 /*************************** cancel render viewer **********************/
index af5f9d3c875602c10b52c998439334e4d08f17df..230c3a11108236b64618a977586451dcab5200c8 100644 (file)
@@ -1050,39 +1050,6 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter,
        /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */
        force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL);
 
-       /* This is actually lots of crap, but currently not sure about
-        * more clear way to bypass partial buffer update crappyness
-        * while rendering.
-        *
-        * The thing is -- render engines are only updating byte and
-        * display buffers for active render result opened in image
-        * editor. This works fine to show render progress without
-        * switching render layers in image editor user, but this is
-        * completely useless for GLSL display, where we need to have
-        * original buffer which we could color manage.
-        *
-        * For the time of rendering, we'll stick back to slower CPU
-        * display buffer update. GLSL could be used as soon as some
-        * fixes (?) are done in render itself, so we'll always have
-        * image buffer with relevant float buffer opened while
-        * rendering.
-        *
-        * On the other hand, when using Cycles, stressing GPU with
-        * GLSL could backfire on a performance.
-        *                                         - sergey -
-        */
-       if (G.is_rendering) {
-               /* Try to detect whether we're drawing render result,
-                * other images could have both rect and rect_float
-                * but they'll be synchronized
-                */
-               if (ibuf->rect_float && ibuf->rect &&
-                   ((ibuf->mall & IB_rectfloat) == 0))
-               {
-                       force_fallback = true;
-               }
-       }
-
        /* Try to draw buffer using GLSL display transform */
        if (force_fallback == false) {
                int ok;
index 139354c0afc7f00fb9c307555424fb0e458eb37b..e57a876bcde97f13db15af42a4d27dabb574d003 100644 (file)
@@ -1887,6 +1887,13 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
        bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
        bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
 
+       if (ibuf->rect_float && ibuf->rect &&
+           (ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0)
+       {
+               IMB_rect_from_float(ibuf);
+               ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
+       }
+
        do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
 
        if (do_colormanagement || do_alpha_under) {
@@ -2663,7 +2670,18 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
                                float pixel[4];
 
                                if (linear_buffer) {
-                                       copy_v4_v4(pixel, (float *) linear_buffer + linear_index);
+                                       if (channels == 4) {
+                                               copy_v4_v4(pixel, (float *) linear_buffer + linear_index);
+                                       }
+                                       else if (channels == 3) {
+                                               copy_v3_v3(pixel, (float *) linear_buffer + linear_index);
+                                       }
+                                       else if (channels == 1) {
+                                               pixel[0] = linear_buffer[linear_index];
+                                       }
+                                       else {
+                                               BLI_assert(!"Unsupported number of channels in partial buffer update");
+                                       }
                                }
                                else if (byte_buffer) {
                                        rgba_uchar_to_float(pixel, byte_buffer + linear_index);
@@ -2678,12 +2696,32 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
                                if (display_buffer_float) {
                                        int index = ((y - ymin) * width + (x - xmin)) * channels;
 
-                                       copy_v4_v4(display_buffer_float + index, pixel);
+                                       if (channels == 4) {
+                                               copy_v4_v4(display_buffer_float + index, pixel);
+                                       }
+                                       else if (channels == 3) {
+                                               copy_v3_v3(display_buffer_float + index, pixel);
+                                       }
+                                       else /* if (channels == 1) */ {
+                                               display_buffer_float[index] = pixel[0];
+                                       }
                                }
                                else {
-                                       float pixel_straight[4];
-                                       premul_to_straight_v4_v4(pixel_straight, pixel);
-                                       rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
+                                       if (channels == 4) {
+                                               float pixel_straight[4];
+                                               premul_to_straight_v4_v4(pixel_straight, pixel);
+                                               rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
+                                       }
+                                       else if (channels == 3) {
+                                               rgb_float_to_uchar(display_buffer + display_index, pixel);
+                                               display_buffer[display_index + 1] = 255;
+                                       }
+                                       else /* if (channels == 1) */ {
+                                               display_buffer[display_index] =
+                                                       display_buffer[display_index + 1] =
+                                                       display_buffer[display_index + 2] =
+                                                       display_buffer[display_index + 3] = FTOCHAR(pixel[0]);
+                                       }
                                }
                        }
                }
@@ -2729,7 +2767,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
                int channels = ibuf->channels;
                int width = xmax - xmin;
                int height = ymax - ymin;
-               int rect_index = (ymin * ibuf->x + xmin) * channels;
+               int rect_index = (ymin * ibuf->x + xmin) * 4;
                int linear_index = ((ymin - offset_y) * stride + (xmin - offset_x)) * channels;
 
                IMB_buffer_byte_from_float(rect + rect_index, linear_buffer + linear_index, channels, ibuf->dither,
index 854275ccb64614c925f5c2a5b42f04140413b736..031c5bdc367132e2c9c6a01766cbda31d04617ad 100644 (file)
@@ -393,7 +393,8 @@ static void rna_def_render_engine(BlenderRNA *brna)
        RNA_def_function_ui_description(func, "All pixels in the render result have been set and are final");
        prop = RNA_def_pointer(func, "result", "RenderResult", "Result", "");
        RNA_def_property_flag(prop, PROP_REQUIRED);
-       RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't merge back results");
+       RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't mark tile as done, don't merge results unless forced");
+       RNA_def_boolean(func, "do_merge_results", 0, "Merge Results", "Merge results even if cancel=true");
 
        func = RNA_def_function(srna, "test_break", "RE_engine_test_break");
        RNA_def_function_ui_description(func, "Test if the render operation should been canceled, this is a fast call that should be used regularly for responsiveness");
index 7bec3eb234d7fe22e3b1437220b8e5be4bd70866..559f21f6961317f0dbc031b061ea743815208c53 100644 (file)
@@ -132,7 +132,7 @@ void RE_result_load_from_file(struct RenderResult *result, struct ReportList *re
 
 struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername);
 void RE_engine_update_result(RenderEngine *engine, struct RenderResult *result);
-void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel);
+void RE_engine_end_result(RenderEngine *engine, struct RenderResult *result, int cancel, int merge_results);
 
 int RE_engine_test_break(RenderEngine *engine);
 void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info);
index 109524c9814522f1c5b03caaf65896cbb1d57325..7e8713566e595af1afd0fcf50bd0450a9ef7849e 100644 (file)
@@ -250,7 +250,7 @@ void RE_MergeFullSample(struct Render *re, struct Main *bmain, struct Scene *sce
 /* display and event callbacks */
 void RE_display_init_cb        (struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr));
 void RE_display_clear_cb(struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr));
-void RE_display_draw_cb        (struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr, volatile struct rcti *rect));
+void RE_display_update_cb(struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr, volatile struct rcti *rect));
 void RE_stats_draw_cb  (struct Render *re, void *handle, void (*f)(void *handle, RenderStats *rs));
 void RE_progress_cb    (struct Render *re, void *handle, void (*f)(void *handle, float));
 void RE_draw_lock_cb           (struct Render *re, void *handle, void (*f)(void *handle, int));
index 3d97eda50d9ca81e79955cf9c44d415a23c1c47c..2a43cab7bcef87a2f4cbe1b405d79944988df5d1 100644 (file)
@@ -252,8 +252,8 @@ struct Render
        void *dih;
        void (*display_clear)(void *handle, RenderResult *rr);
        void *dch;
-       void (*display_draw)(void *handle, RenderResult *rr, volatile rcti *rect);
-       void *ddh;
+       void (*display_update)(void *handle, RenderResult *rr, volatile rcti *rect);
+       void *duh;
        
        void (*stats_draw)(void *handle, RenderStats *ri);
        void *sdh;
index b5bc5ea768bb1088f291e3be098fa32c23564b3b..ac814e9e03303cd488539d7fcc714de2a766b578 100644 (file)
@@ -168,8 +168,8 @@ static Render *envmap_render_copy(Render *re, EnvMap *env)
        copy_m4_m4(envre->viewmat_orig, re->viewmat_orig);
        
        /* callbacks */
-       envre->display_draw = re->display_draw;
-       envre->ddh = re->ddh;
+       envre->display_update = re->display_update;
+       envre->duh = re->duh;
        envre->test_break = re->test_break;
        envre->tbh = re->tbh;
        
index 827a1f8f1134ae5afa8e4715a36b4ba87666edc9..c3628e99d04b4465c19a1bc41e5661998f77674c 100644 (file)
@@ -235,11 +235,11 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
 
        if (result) {
                result->renlay = result->layers.first; /* weak, draws first layer always */
-               re->display_draw(re->ddh, result, NULL);
+               re->display_update(re->duh, result, NULL);
        }
 }
 
-void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel)
+void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel, int merge_results)
 {
        Render *re = engine->re;
 
@@ -260,7 +260,9 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
                         * buffers, we are going to get openexr save errors */
                        fprintf(stderr, "RenderEngine.end_result: dimensions do not match any OpenEXR tile.\n");
                }
+       }
 
+       if (!cancel || merge_results) {
                if (re->result->do_exr_tile)
                        render_result_exr_file_merge(re->result, result);
                else if (!(re->test_break(re->tbh) && (re->r.scemode & R_BUTS_PREVIEW)))
@@ -269,7 +271,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
                /* draw */
                if (!re->test_break(re->tbh)) {
                        result->renlay = result->layers.first; /* weak, draws first layer always */
-                       re->display_draw(re->ddh, result, NULL);
+                       re->display_update(re->duh, result, NULL);
                }
        }
 
index d11f46156986f88de948d81821161e8762104374..ba8265a83febf248bd4d9d5ac0254ec220a6c2d8 100644 (file)
@@ -390,7 +390,7 @@ void RE_InitRenderCB(Render *re)
        /* set default empty callbacks */
        re->display_init = result_nothing;
        re->display_clear = result_nothing;
-       re->display_draw = result_rcti_nothing;
+       re->display_update = result_rcti_nothing;
        re->progress = float_nothing;
        re->test_break = default_break;
        if (G.background)
@@ -398,7 +398,7 @@ void RE_InitRenderCB(Render *re)
        else
                re->stats_draw = stats_nothing;
        /* clear callback handles */
-       re->dih = re->dch = re->ddh = re->sdh = re->prh = re->tbh = NULL;
+       re->dih = re->dch = re->duh = re->sdh = re->prh = re->tbh = NULL;
 }
 
 /* only call this while you know it will remove the link too */
@@ -709,10 +709,10 @@ void RE_display_clear_cb(Render *re, void *handle, void (*f)(void *handle, Rende
        re->display_clear = f;
        re->dch = handle;
 }
-void RE_display_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr, volatile rcti *rect))
+void RE_display_update_cb(Render *re, void *handle, void (*f)(void *handle, RenderResult *rr, volatile rcti *rect))
 {
-       re->display_draw = f;
-       re->ddh = handle;
+       re->display_update = f;
+       re->duh = handle;
 }
 void RE_stats_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderStats *rs))
 {
@@ -751,7 +751,7 @@ void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob))
 
 /* *************************************** */
 
-static int render_display_draw_enabled(Render *re)
+static int render_display_update_enabled(Render *re)
 {
        /* don't show preprocess for previewrender sss */
        if (re->sss_points)
@@ -790,7 +790,7 @@ static void *do_part_thread(void *pa_v)
                if (R.result->do_exr_tile) {
                        render_result_exr_file_merge(R.result, pa->result);
                }
-               else if (render_display_draw_enabled(&R)) {
+               else if (render_display_update_enabled(&R)) {
                        /* on break, don't merge in result for preview renders, looks nicer */
                        if (R.test_break(R.tbh) && (R.r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
                                /* pass */
@@ -941,6 +941,9 @@ typedef struct RenderThread {
        ThreadQueue *donequeue;
        
        int number;
+
+       void (*display_update)(void *handle, RenderResult *rr, volatile rcti *rect);
+       void *duh;
 } RenderThread;
 
 static void *do_render_thread(void *thread_v)
@@ -951,6 +954,11 @@ static void *do_render_thread(void *thread_v)
        while ((pa = BLI_thread_queue_pop(thread->workqueue))) {
                pa->thread = thread->number;
                do_part_thread(pa);
+
+               if (thread->display_update) {
+                       thread->display_update(thread->duh, pa->result, NULL);
+               }
+
                BLI_thread_queue_push(thread->donequeue, pa);
                
                if (R.test_break(R.tbh))
@@ -976,7 +984,7 @@ static void threaded_tile_processor(Render *re)
        if (re->result == NULL || !(re->r.scemode & (R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))) {
                render_result_free(re->result);
 
-               if (re->sss_points && render_display_draw_enabled(re))
+               if (re->sss_points && render_display_update_enabled(re))
                        re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
                else if (re->r.scemode & R_FULL_SAMPLE)
                        re->result = render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR);
@@ -1025,6 +1033,10 @@ static void threaded_tile_processor(Render *re)
                        thread[a].workqueue = workqueue;
                        thread[a].donequeue = donequeue;
                        thread[a].number = a;
+                       if (render_display_update_enabled(re)) {
+                               thread[a].display_update = re->display_update;
+                               thread[a].duh = re->duh;
+                       }
                        BLI_insert_thread(&threads, &thread[a]);
                }
                
@@ -1038,8 +1050,6 @@ static void threaded_tile_processor(Render *re)
                        /* handle finished part */
                        if ((pa=BLI_thread_queue_pop_timeout(donequeue, wait))) {
                                if (pa->result) {
-                                       if (render_display_draw_enabled(re))
-                                               re->display_draw(re->ddh, pa->result, NULL);
                                        print_part_stats(re, pa);
                                        
                                        render_result_free_list(&pa->fullresult, pa->result);
@@ -1062,10 +1072,10 @@ static void threaded_tile_processor(Render *re)
                        /* redraw in progress parts */
                        elapsed = PIL_check_seconds_timer() - lastdraw;
                        if (elapsed > redrawtime) {
-                               if (render_display_draw_enabled(re))
+                               if (render_display_update_enabled(re))
                                        for (pa = re->parts.first; pa; pa = pa->next)
                                                if ((pa->status == PART_STATUS_IN_PROGRESS) && pa->nr && pa->result)
-                                                       re->display_draw(re->ddh, pa->result, &pa->result->renrect);
+                                                       re->display_update(re->duh, pa->result, &pa->result->renrect);
                                
                                lastdraw = PIL_check_seconds_timer();
                        }
@@ -1315,7 +1325,7 @@ static void do_render_blur_3d(Render *re)
        
        /* weak... the display callback wants an active renderlayer pointer... */
        re->result->renlay = render_get_active_layer(re, re->result);
-       re->display_draw(re->ddh, re->result, NULL);
+       re->display_update(re->duh, re->result, NULL);
 }
 
 
@@ -1436,7 +1446,7 @@ static void do_render_fields_3d(Render *re)
 
        BLI_rw_mutex_unlock(&re->resultmutex);
 
-       re->display_draw(re->ddh, re->result, NULL);
+       re->display_update(re->duh, re->result, NULL);
 }
 
 /* make sure disprect is not affected by the render border */
@@ -1496,7 +1506,7 @@ static void do_render_fields_blur_3d(Render *re)
                                BLI_rw_mutex_unlock(&re->resultmutex);
                
                                re->display_init(re->dih, re->result);
-                               re->display_draw(re->ddh, re->result, NULL);
+                               re->display_update(re->duh, re->result, NULL);
                        }
                        else {
                                /* set offset (again) for use in compositor, disprect was manipulated. */
@@ -1539,8 +1549,8 @@ static void render_scene(Render *re, Scene *sce, int cfra)
        BKE_scene_set_background(re->main, sce);
 
        /* copy callbacks */
-       resc->display_draw = re->display_draw;
-       resc->ddh = re->ddh;
+       resc->display_update = re->display_update;
+       resc->duh = re->duh;
        resc->test_break = re->test_break;
        resc->tbh = re->tbh;
        resc->stats_draw = re->stats_draw;
@@ -1849,7 +1859,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
                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_draw(re->ddh, re->result, NULL);
+                       re->display_update(re->duh, re->result, NULL);
                }
                
                if (re->test_break(re->tbh))
@@ -2034,7 +2044,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
 
        /* weak... the display callback wants an active renderlayer pointer... */
        re->result->renlay = render_get_active_layer(re, re->result);
-       re->display_draw(re->ddh, re->result, NULL);
+       re->display_update(re->duh, re->result, NULL);
 }
 
 static void renderresult_stampinfo(Render *re)
@@ -2140,7 +2150,7 @@ static void do_render_seq(Render *re)
                re->progress(re->prh, 1.0f);
 
        /* would mark display buffers as invalid */
-       re->display_draw(re->ddh, re->result, NULL);
+       re->display_update(re->duh, re->result, NULL);
 }
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@@ -2164,7 +2174,7 @@ static void do_render_all_options(Render *re)
                        do_render_seq(re);
                
                re->stats_draw(re->sdh, &re->i);
-               re->display_draw(re->ddh, re->result, NULL);
+               re->display_update(re->duh, re->result, NULL);
        }
        else {
                re->pool = BKE_image_pool_new();
@@ -2182,7 +2192,7 @@ static void do_render_all_options(Render *re)
        /* stamp image info here */
        if ((re->r.stamp & R_STAMP_ALL) && (re->r.stamp & R_STAMP_DRAW)) {
                renderresult_stampinfo(re);
-               re->display_draw(re->ddh, re->result, NULL);
+               re->display_update(re->duh, re->result, NULL);
        }
 }
 
index 8791af557928e5de6801a40c88b2dcd94d7171be..2fb956ee3a6f7567d8dcb5b59f5caaa5235c0a89 100644 (file)
@@ -1866,7 +1866,7 @@ void add_halo_flare(Render *re)
                if (do_draw) {
                        /* weak... the display callback wants an active renderlayer pointer... */
                        rr->renlay= rl;
-                       re->display_draw(re->ddh, rr, NULL);
+                       re->display_update(re->duh, rr, NULL);
                }
 
                R.r.mode= mode;