forked from bartvdbraak/blender
Blender Internal: optimization to remove sleep() calls from the render threading
code. This gives a speedup up to a couple of seconds based only on the image resolution and tile size. For complex renders a second or two is not so noticeable but for quick ones it's nice to save some time. On the default cube this gives me about half a second speedup. Patch by Johan Walles, based on the render branch implementation by me.
This commit is contained in:
parent
7a6919a74e
commit
6b600d0793
@ -673,6 +673,10 @@ static void *do_part_thread(void *pa_v)
|
|||||||
else
|
else
|
||||||
zbufshade_tile(pa);
|
zbufshade_tile(pa);
|
||||||
|
|
||||||
|
/* we do actually write pixels, but don't allocate/deallocate anything,
|
||||||
|
* so it is safe with other threads reading at the same time */
|
||||||
|
BLI_rw_mutex_lock(&R.resultmutex, THREAD_LOCK_READ);
|
||||||
|
|
||||||
/* merge too on break! */
|
/* merge too on break! */
|
||||||
if (R.result->do_exr_tile) {
|
if (R.result->do_exr_tile) {
|
||||||
render_result_exr_file_merge(R.result, pa->result);
|
render_result_exr_file_merge(R.result, pa->result);
|
||||||
@ -686,6 +690,8 @@ static void *do_part_thread(void *pa_v)
|
|||||||
render_result_merge(R.result, pa->result);
|
render_result_merge(R.result, pa->result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLI_rw_mutex_unlock(&R.resultmutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
pa->status = PART_STATUS_READY;
|
pa->status = PART_STATUS_READY;
|
||||||
@ -719,24 +725,33 @@ float panorama_pixel_rot(Render *re)
|
|||||||
return phi;
|
return phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call when all parts stopped rendering, to find the next Y slice */
|
/* for panorama, we render per Y slice, and update
|
||||||
/* if slice found, it rotates the dbase */
|
* camera parameters when we go the next slice */
|
||||||
static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
|
static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewplane)
|
||||||
{
|
{
|
||||||
RenderPart *pa, *best = NULL;
|
RenderPart *pa, *best = NULL;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
*minx = re->winx;
|
*minx = re->winx;
|
||||||
|
|
||||||
|
if (!(re->r.mode & R_PANORAMA)) {
|
||||||
|
/* for regular render, just one 'slice' */
|
||||||
|
found = (*slice == 0);
|
||||||
|
(*slice)++;
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
/* most left part of the non-rendering parts */
|
/* most left part of the non-rendering parts */
|
||||||
for (pa = re->parts.first; pa; pa = pa->next) {
|
for (pa = re->parts.first; pa; pa = pa->next) {
|
||||||
if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
|
if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
|
||||||
if (pa->disprect.xmin < *minx) {
|
if (pa->disprect.xmin < *minx) {
|
||||||
|
found = true;
|
||||||
best = pa;
|
best = pa;
|
||||||
*minx = pa->disprect.xmin;
|
*minx = pa->disprect.xmin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best) {
|
if (best) {
|
||||||
float phi = panorama_pixel_rot(re);
|
float phi = panorama_pixel_rot(re);
|
||||||
|
|
||||||
@ -754,7 +769,10 @@ static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
|
|||||||
R.panosi = sin(R.panodxp * phi);
|
R.panosi = sin(R.panodxp * phi);
|
||||||
R.panoco = cos(R.panodxp * phi);
|
R.panoco = cos(R.panodxp * phi);
|
||||||
}
|
}
|
||||||
return best;
|
|
||||||
|
(*slice)++;
|
||||||
|
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RenderPart *find_next_part(Render *re, int minx)
|
static RenderPart *find_next_part(Render *re, int minx)
|
||||||
@ -809,26 +827,53 @@ static void print_part_stats(Render *re, RenderPart *pa)
|
|||||||
re->i.infostr = NULL;
|
re->i.infostr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct RenderThread {
|
||||||
|
ThreadQueue *workqueue;
|
||||||
|
ThreadQueue *donequeue;
|
||||||
|
|
||||||
|
int number;
|
||||||
|
} RenderThread;
|
||||||
|
|
||||||
|
static void *do_render_thread(void *thread_v)
|
||||||
|
{
|
||||||
|
RenderThread *thread = thread_v;
|
||||||
|
RenderPart *pa;
|
||||||
|
|
||||||
|
while ((pa = BLI_thread_queue_pop(thread->workqueue))) {
|
||||||
|
pa->thread = thread->number;
|
||||||
|
do_part_thread(pa);
|
||||||
|
BLI_thread_queue_push(thread->donequeue, pa);
|
||||||
|
|
||||||
|
if(R.test_break(R.tbh))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void threaded_tile_processor(Render *re)
|
static void threaded_tile_processor(Render *re)
|
||||||
{
|
{
|
||||||
|
RenderThread thread[BLENDER_MAX_THREADS];
|
||||||
|
ThreadQueue *workqueue, *donequeue;
|
||||||
ListBase threads;
|
ListBase threads;
|
||||||
RenderPart *pa, *nextpa;
|
RenderPart *pa;
|
||||||
rctf viewplane = re->viewplane;
|
rctf viewplane = re->viewplane;
|
||||||
int rendering = 1, counter = 1, drawtimer = 0, hasdrawn, minx = 0;
|
double lastdraw, elapsed, redrawtime = 1.0f;
|
||||||
|
int totpart = 0, minx = 0, slice = 0, a, wait;
|
||||||
|
|
||||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
|
|
||||||
/* first step; free the entire render result, make new, and/or prepare exr buffer saving */
|
/* first step; free the entire render result, make new, and/or prepare exr buffer saving */
|
||||||
if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
|
if (re->result == NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
|
||||||
render_result_free(re->result);
|
render_result_free(re->result);
|
||||||
|
|
||||||
if (re->sss_points && render_display_draw_enabled(re))
|
if (re->sss_points && render_display_draw_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);
|
||||||
else if (re->r.scemode & R_FULL_SAMPLE)
|
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);
|
||||||
else
|
else
|
||||||
re->result = render_result_new(re, &re->disprect, 0,
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_rw_mutex_unlock(&re->resultmutex);
|
BLI_rw_mutex_unlock(&re->resultmutex);
|
||||||
@ -843,53 +888,46 @@ static void threaded_tile_processor(Render *re)
|
|||||||
if (re->result->do_exr_tile)
|
if (re->result->do_exr_tile)
|
||||||
render_result_exr_file_begin(re);
|
render_result_exr_file_begin(re);
|
||||||
|
|
||||||
BLI_init_threads(&threads, do_part_thread, re->r.threads);
|
|
||||||
|
|
||||||
/* assuming no new data gets added to dbase... */
|
/* assuming no new data gets added to dbase... */
|
||||||
R = *re;
|
R = *re;
|
||||||
|
|
||||||
/* set threadsafe break */
|
/* set threadsafe break */
|
||||||
R.test_break = thread_break;
|
R.test_break = thread_break;
|
||||||
|
|
||||||
/* timer loop demands to sleep when no parts are left, so we enter loop with a part */
|
/* create and fill work queue */
|
||||||
if (re->r.mode & R_PANORAMA)
|
workqueue = BLI_thread_queue_init();
|
||||||
nextpa = find_next_pano_slice(re, &minx, &viewplane);
|
donequeue = BLI_thread_queue_init();
|
||||||
else
|
|
||||||
nextpa = find_next_part(re, 0);
|
|
||||||
|
|
||||||
while (rendering) {
|
/* for panorama we loop over slices */
|
||||||
|
while (find_next_pano_slice(re, &slice, &minx, &viewplane)) {
|
||||||
if (re->test_break(re->tbh))
|
/* gather parts into queue */
|
||||||
PIL_sleep_ms(50);
|
while ((pa = find_next_part(re, minx))) {
|
||||||
else if (nextpa && BLI_available_threads(&threads)) {
|
pa->nr = totpart + 1; /* for nicest part, and for stats */
|
||||||
drawtimer = 0;
|
totpart++;
|
||||||
nextpa->nr = counter++; /* for nicest part, and for stats */
|
BLI_thread_queue_push(workqueue, pa);
|
||||||
nextpa->thread = BLI_available_thread_index(&threads); /* sample index */
|
|
||||||
BLI_insert_thread(&threads, nextpa);
|
|
||||||
|
|
||||||
nextpa = find_next_part(re, minx);
|
|
||||||
}
|
|
||||||
else if (re->r.mode & R_PANORAMA) {
|
|
||||||
if (nextpa == NULL && BLI_available_threads(&threads) == re->r.threads)
|
|
||||||
nextpa = find_next_pano_slice(re, &minx, &viewplane);
|
|
||||||
else {
|
|
||||||
PIL_sleep_ms(50);
|
|
||||||
drawtimer++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PIL_sleep_ms(50);
|
|
||||||
drawtimer++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for ready ones to display, and if we need to continue */
|
BLI_thread_queue_nowait(workqueue);
|
||||||
rendering = 0;
|
|
||||||
hasdrawn = 0;
|
/* start all threads */
|
||||||
for (pa = re->parts.first; pa; pa = pa->next) {
|
BLI_init_threads(&threads, do_render_thread, re->r.threads);
|
||||||
if (pa->status == PART_STATUS_READY) {
|
|
||||||
|
for (a = 0; a < re->r.threads; a++) {
|
||||||
BLI_remove_thread(&threads, pa);
|
thread[a].workqueue = workqueue;
|
||||||
|
thread[a].donequeue = donequeue;
|
||||||
|
thread[a].number = a;
|
||||||
|
BLI_insert_thread(&threads, &thread[a]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for results to come back */
|
||||||
|
lastdraw = PIL_check_seconds_timer();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
elapsed = PIL_check_seconds_timer() - lastdraw;
|
||||||
|
wait = (redrawtime - elapsed)*1000;
|
||||||
|
|
||||||
|
/* handle finished part */
|
||||||
|
if ((pa=BLI_thread_queue_pop_timeout(donequeue, wait))) {
|
||||||
if (pa->result) {
|
if (pa->result) {
|
||||||
if (render_display_draw_enabled(re))
|
if (render_display_draw_enabled(re))
|
||||||
re->display_draw(re->ddh, pa->result, NULL);
|
re->display_draw(re->ddh, pa->result, NULL);
|
||||||
@ -899,27 +937,40 @@ static void threaded_tile_processor(Render *re)
|
|||||||
pa->result = NULL;
|
pa->result = NULL;
|
||||||
re->i.partsdone++;
|
re->i.partsdone++;
|
||||||
re->progress(re->prh, re->i.partsdone / (float)re->i.totpart);
|
re->progress(re->prh, re->i.partsdone / (float)re->i.totpart);
|
||||||
hasdrawn = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totpart--;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
rendering = 1;
|
/* check for render cancel */
|
||||||
if (pa->nr && pa->result && drawtimer > 20) {
|
if ((g_break=re->test_break(re->tbh)))
|
||||||
if (render_display_draw_enabled(re))
|
break;
|
||||||
re->display_draw(re->ddh, pa->result, &pa->result->renrect);
|
|
||||||
hasdrawn = 1;
|
/* or done with parts */
|
||||||
}
|
if (totpart == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* redraw in progress parts */
|
||||||
|
elapsed = PIL_check_seconds_timer() - lastdraw;
|
||||||
|
if (elapsed > redrawtime) {
|
||||||
|
if (render_display_draw_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);
|
||||||
|
|
||||||
|
lastdraw = PIL_check_seconds_timer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasdrawn)
|
|
||||||
drawtimer = 0;
|
|
||||||
|
|
||||||
/* on break, wait for all slots to get freed */
|
|
||||||
if ( (g_break = re->test_break(re->tbh)) && BLI_available_threads(&threads) == re->r.threads)
|
|
||||||
rendering = 0;
|
|
||||||
|
|
||||||
|
BLI_end_threads(&threads);
|
||||||
|
|
||||||
|
if ((g_break=re->test_break(re->tbh)))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BLI_thread_queue_free(donequeue);
|
||||||
|
BLI_thread_queue_free(workqueue);
|
||||||
|
|
||||||
if (re->result->do_exr_tile) {
|
if (re->result->do_exr_tile) {
|
||||||
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
|
||||||
render_result_exr_file_end(re);
|
render_result_exr_file_end(re);
|
||||||
@ -929,7 +980,6 @@ static void threaded_tile_processor(Render *re)
|
|||||||
/* unset threadsafety */
|
/* unset threadsafety */
|
||||||
g_break = 0;
|
g_break = 0;
|
||||||
|
|
||||||
BLI_end_threads(&threads);
|
|
||||||
RE_parts_free(re);
|
RE_parts_free(re);
|
||||||
re->viewplane = viewplane; /* restore viewplane, modified by pano render */
|
re->viewplane = viewplane; /* restore viewplane, modified by pano render */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user