Highlight currently rendering tiles

This commit implements highlight of tiles which are being currently
rendered for both Blender Internal and Cycles (and should be possible
to use it for other external engines as well).

Couple of implementation details:

- Added one extra boolean flag to render engine which should be set
  to truth if render engine wants to highlight tiles. If so, property
  use_highlight_tiles should be set to True.

- Render Part's ready boolena was changed by status enum, which could
  be NONE, IN_PROGRESS and READY. All render part with IN_PROGRESS
  status will be highlighted in image editor.

- For external engines render part's status is filling in automatically.
  Initially all render parts has got NONE status, then one external
  engine acquire render result, corresponding part will change status
  to IN_PROGRESS. As soon as render result is finished, corresponding
  render part will change status to FINISHED

  This should make it easy to highlight tiles for other engines as well.
This commit is contained in:
Sergey Sharybin 2013-01-01 16:15:13 +00:00
parent b88836a45b
commit 2e0e2cb170
9 changed files with 184 additions and 27 deletions

@ -107,6 +107,8 @@ void BlenderSession::create_session()
/* set buffer parameters */
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_v3d, b_rv3d, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
}
void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
@ -149,6 +151,8 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
session->reset(buffer_params, session_params.samples);
b_engine.use_highlight_tiles(session_params.progressive_refine == false);
}
void BlenderSession::free_session()
@ -252,7 +256,15 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda
if (do_update_only) {
/* update only needed */
update_render_result(b_rr, b_rlay, rtile);
if (rtile.sample != 0) {
/* sample would be zero at initial tile update, which is only needed
* to tag tile form blender side as IN PROGRESS for proper highlight
* no buffers should be sent to blender yet
*/
update_render_result(b_rr, b_rlay, rtile);
}
end_render_result(b_engine, b_rr, true);
}
else {

@ -357,7 +357,7 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
tile_lock.unlock();
/* in case of a permant buffer, return it, otherwise we will allocate
/* in case of a permanent buffer, return it, otherwise we will allocate
* a new temporary buffer */
if(!params.background) {
tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
@ -411,6 +411,12 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
rtile.rgba = 0;
rtile.buffers = tilebuffers;
/* this will tag tile as IN PROGRESS in blender-side render pipeline,
* which is needed to highlight currently rendering tile before first
* sample was processed for it
*/
update_tile_sample(rtile);
return true;
}

@ -75,12 +75,14 @@
#include "WM_types.h"
#include "RE_pipeline.h"
#include "RE_engine.h"
#include "image_intern.h"
static void draw_render_info(Scene *scene, Image *ima, ARegion *ar)
static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx, float zoomy)
{
RenderResult *rr;
Render *re = RE_GetRender(scene->id.name);
rr = BKE_image_acquire_renderresult(scene, ima);
@ -89,6 +91,73 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar)
}
BKE_image_release_renderresult(scene, ima);
if (re) {
int total_tiles;
rcti *tiles;
RE_engine_get_current_tiles(re, &total_tiles, &tiles);
if (total_tiles) {
int i, x, y;
rcti *tile;
/* find window pixel coordinates of origin */
UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glScalef(zoomx, zoomy, 1.0f);
if (scene->r.mode & R_BORDER) {
glTranslatef(-scene->r.border.xmin * scene->r.xsch * scene->r.size / 100.0f,
-scene->r.border.ymin * scene->r.ysch * scene->r.size / 100.0f,
0.0f);
}
UI_ThemeColor(TH_FACE_SELECT);
for (i = 0, tile = tiles; i < total_tiles; i++, tile++) {
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
float delta_y = 4.0f * UI_DPI_FAC / zoomy;
delta_x = min_ff(delta_x, tile->xmax - tile->xmin);
delta_y = min_ff(delta_y, tile->ymax - tile->ymin);
/* left bottom corner */
glBegin(GL_LINE_STRIP);
glVertex2f(tile->xmin, tile->ymin + delta_y);
glVertex2f(tile->xmin, tile->ymin);
glVertex2f(tile->xmin + delta_x, tile->ymin);
glEnd();
/* left top corner */
glBegin(GL_LINE_STRIP);
glVertex2f(tile->xmin, tile->ymax - delta_y);
glVertex2f(tile->xmin, tile->ymax);
glVertex2f(tile->xmin + delta_x, tile->ymax);
glEnd();
/* right bottom corner */
glBegin(GL_LINE_STRIP);
glVertex2f(tile->xmax - delta_x, tile->ymin);
glVertex2f(tile->xmax, tile->ymin);
glVertex2f(tile->xmax, tile->ymin + delta_y);
glEnd();
/* right top corner */
glBegin(GL_LINE_STRIP);
glVertex2f(tile->xmax - delta_x, tile->ymax);
glVertex2f(tile->xmax, tile->ymax);
glVertex2f(tile->xmax, tile->ymax - delta_y);
glEnd();
}
MEM_freeN(tiles);
glPopMatrix();
}
}
}
/* used by node view too */
@ -786,7 +855,6 @@ void draw_image_main(const bContext *C, ARegion *ar)
if (sima->mode == SI_MODE_PAINT)
draw_image_paint_helpers(C, ar, scene, zoomx, zoomy);
/* XXX integrate this code */
#if 0
if (ibuf) {
@ -812,5 +880,5 @@ void draw_image_main(const bContext *C, ARegion *ar)
/* render info */
if (ima && show_render)
draw_render_info(scene, ima, ar);
draw_render_info(scene, ima, ar, zoomx, zoomy);
}

@ -406,6 +406,9 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "resolution_y");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "use_highlight_tiles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_HIGHLIGHT_TILES);
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);

@ -61,6 +61,7 @@ struct Scene;
#define RE_ENGINE_DO_DRAW 4
#define RE_ENGINE_DO_UPDATE 8
#define RE_ENGINE_RENDERING 16
#define RE_ENGINE_HIGHLIGHT_TILES 32
extern ListBase R_engines;
@ -130,5 +131,7 @@ void RE_engines_exit(void);
RenderEngineType *RE_engines_find(const char *idname);
void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r);
#endif /* __RE_ENGINE_H__ */

@ -104,13 +104,19 @@ typedef struct RenderPart {
rcti disprect; /* part coordinates within total picture */
int rectx, recty; /* the size */
short crop, ready; /* crop is amount of pixels we crop, for filter */
short crop, status; /* crop is amount of pixels we crop, for filter */
short sample, nr; /* sample can be used by zbuffers, nr is partnr */
short thread; /* thread id */
char *clipflag; /* clipflags for part zbuffering */
} RenderPart;
enum {
PART_STATUS_NONE = 0,
PART_STATUS_IN_PROGRESS = 1,
PART_STATUS_READY = 2
};
/* controls state of render, everything that's read-only during render stage */
struct Render
{

@ -150,6 +150,23 @@ void RE_engine_free(RenderEngine *engine)
/* Render Results */
static RenderPart *get_part_from_result(Render *re, RenderResult *result)
{
RenderPart *pa;
for (pa = re->parts.first; pa; pa = pa->next) {
if (result->tilerect.xmin == pa->disprect.xmin - re->disprect.xmin &&
result->tilerect.ymin == pa->disprect.ymin - re->disprect.ymin &&
result->tilerect.xmax == pa->disprect.xmax - re->disprect.xmin &&
result->tilerect.ymax == pa->disprect.ymax - re->disprect.ymin)
{
return pa;
}
}
return NULL;
}
RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
{
Render *re = engine->re;
@ -179,12 +196,19 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
/* can be NULL if we CLAMP the width or height to 0 */
if (result) {
RenderPart *pa;
BLI_addtail(&engine->fullresult, result);
result->tilerect.xmin += re->disprect.xmin;
result->tilerect.xmax += re->disprect.xmin;
result->tilerect.ymin += re->disprect.ymin;
result->tilerect.ymax += re->disprect.ymin;
pa = get_part_from_result(re, result);
if (pa)
pa->status = PART_STATUS_IN_PROGRESS;
}
return result;
@ -203,7 +227,6 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel)
{
Render *re = engine->re;
RenderPart *pa;
if (!result) {
return;
@ -212,15 +235,10 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
/* merge. on break, don't merge in result for preview renders, looks nicer */
if (!cancel) {
/* for exr tile render, detect tiles that are done */
for (pa = re->parts.first; pa; pa = pa->next) {
if (result->tilerect.xmin == pa->disprect.xmin &&
result->tilerect.ymin == pa->disprect.ymin &&
result->tilerect.xmax == pa->disprect.xmax &&
result->tilerect.ymax == pa->disprect.ymax)
{
pa->ready = 1;
}
}
RenderPart *pa = get_part_from_result(re, result);
if (pa)
pa->status = PART_STATUS_READY;
if (re->result->do_exr_tile)
render_result_exr_file_merge(re->result, result);
@ -310,6 +328,47 @@ void RE_engine_report(RenderEngine *engine, int type, const char *msg)
BKE_report(engine->reports, type, msg);
}
void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r)
{
RenderPart *pa;
int total_tiles = 0;
rcti *tiles = NULL;
int allocation_size = 0, allocation_step = BLENDER_MAX_THREADS;
if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
*total_tiles_r = 0;
*tiles_r = NULL;
return;
}
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->status == PART_STATUS_IN_PROGRESS) {
if (total_tiles >= allocation_size) {
if (tiles == NULL)
tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles");
else
tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti));
allocation_size += allocation_step;
}
tiles[total_tiles] = pa->disprect;
if (pa->crop) {
tiles[total_tiles].xmin += pa->crop;
tiles[total_tiles].ymin += pa->crop;
tiles[total_tiles].xmax -= pa->crop;
tiles[total_tiles].ymax -= pa->crop;
}
total_tiles++;
}
}
*total_tiles_r = total_tiles;
*tiles_r = tiles;
}
/* Render */
int RE_engine_render(Render *re, int do_all)
@ -354,9 +413,7 @@ int RE_engine_render(Render *re, int do_all)
if (!engine) {
engine = RE_engine_create(type);
if (persistent_data)
re->engine = engine;
re->engine = engine;
}
engine->flag |= RE_ENGINE_RENDERING;

@ -656,6 +656,8 @@ static void *do_part_thread(void *pa_v)
{
RenderPart *pa = pa_v;
pa->status = PART_STATUS_IN_PROGRESS;
/* need to return nicely all parts on esc */
if (R.test_break(R.tbh) == 0) {
@ -686,7 +688,7 @@ static void *do_part_thread(void *pa_v)
}
}
pa->ready = 1;
pa->status = PART_STATUS_READY;
return NULL;
}
@ -727,7 +729,7 @@ static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
/* most left part of the non-rendering parts */
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->ready == 0 && pa->nr == 0) {
if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
if (pa->disprect.xmin < *minx) {
best = pa;
*minx = pa->disprect.xmin;
@ -765,7 +767,7 @@ static RenderPart *find_next_part(Render *re, int minx)
/* find center of rendered parts, image center counts for 1 too */
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->ready) {
if (pa->status == PART_STATUS_READY) {
centx += BLI_rcti_cent_x(&pa->disprect);
centy += BLI_rcti_cent_y(&pa->disprect);
tot++;
@ -776,7 +778,7 @@ static RenderPart *find_next_part(Render *re, int minx)
/* closest of the non-rendering parts */
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->ready == 0 && pa->nr == 0) {
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);
@ -884,7 +886,7 @@ static void threaded_tile_processor(Render *re)
rendering = 0;
hasdrawn = 0;
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->ready) {
if (pa->status == PART_STATUS_READY) {
BLI_remove_thread(&threads, pa);

@ -924,7 +924,7 @@ static void save_empty_result_tiles(Render *re)
IMB_exrtile_clear_channels(rl->exrhandle);
for (pa = re->parts.first; pa; pa = pa->next) {
if (pa->ready == 0) {
if (pa->status != PART_STATUS_READY) {
int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);