Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2016-09-16 11:28:41 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2016-09-16 11:31:37 +0300
commit6f92604e539b2114763150fb1ace60d28e59a889 (patch)
treeddc52f46db88ca341773089c3b8f436e1b048e91 /source/blender/editors/render/render_opengl.c
parent04bfea0d6747b48cf8e792586cd6df8df0f00dcc (diff)
OpenGL render: Move file writing to a separate thread
The idea is to have a dedicated thread which is responsive for all the file writing to a separate thread, so slow disk will not slow down OpenGL itself. Gives really nice speedup around 1.5x when exporting barber shop layout file to h264 video.
Diffstat (limited to 'source/blender/editors/render/render_opengl.c')
-rw-r--r--source/blender/editors/render/render_opengl.c153
1 files changed, 127 insertions, 26 deletions
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 46353ec4a44..ee2772ce31a 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -40,6 +40,7 @@
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
#include "BLI_threads.h"
+#include "BLI_task.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -130,6 +131,10 @@ typedef struct OGLRender {
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
+ TaskPool *task_pool;
+ bool pool_ok;
+ SpinLock reports_lock;
+
#ifdef DEBUG_TIME
double time_start;
#endif
@@ -685,6 +690,24 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->mh = NULL;
oglrender->movie_ctx_arr = NULL;
+ if (is_animation) {
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
+ oglrender->task_pool = BLI_task_pool_create_background(task_scheduler,
+ oglrender);
+ BLI_pool_set_num_threads(oglrender->task_pool, 1);
+ }
+ else {
+ oglrender->task_pool = BLI_task_pool_create(task_scheduler,
+ oglrender);
+ }
+ }
+ else {
+ oglrender->task_pool = NULL;
+ }
+ oglrender->pool_ok = true;
+ BLI_spin_init(&oglrender->reports_lock);
+
#ifdef DEBUG_TIME
oglrender->time_start = PIL_check_seconds_timer();
#endif
@@ -698,6 +721,10 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
Scene *scene = oglrender->scene;
int i;
+ BLI_task_pool_work_and_wait(oglrender->task_pool);
+ BLI_task_pool_free(oglrender->task_pool);
+ BLI_spin_end(&oglrender->reports_lock);
+
#ifdef DEBUG_TIME
printf("Total render time: %f\n", PIL_check_seconds_timer() - oglrender->time_start);
#endif
@@ -796,6 +823,102 @@ static bool screen_opengl_render_anim_initialize(bContext *C, wmOperator *op)
return true;
}
+typedef struct WriteTaskData {
+ RenderResult *rr;
+ int cfra;
+} WriteTaskData;
+
+static void write_result_func(TaskPool * __restrict pool,
+ void *task_data_v,
+ int UNUSED(thread_id))
+{
+ OGLRender *oglrender = (OGLRender *) BLI_task_pool_userdata(pool);
+ WriteTaskData *task_data = (WriteTaskData *) task_data_v;
+ Scene *scene = oglrender->scene;
+ RenderResult *rr = task_data->rr;
+ const bool is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
+ const int cfra = task_data->cfra;
+ bool ok;
+ /* Construct local thread0safe copy of reports structure which we can
+ * safely pass to the underlying functions.
+ */
+ ReportList reports;
+ BKE_reports_init(&reports, oglrender->reports->flag & ~RPT_PRINT);
+ /* Do actual save logic here, depending on the file format. */
+ if (is_movie) {
+ /* We have to construct temporary scene with proper scene->r.cfra.
+ * This is because underlying calls do not use r.cfra but use scene
+ * for that.
+ */
+ Scene tmp_scene = *scene;
+ tmp_scene.r.cfra = cfra;
+ ok = RE_WriteRenderViewsMovie(&reports,
+ rr,
+ &tmp_scene,
+ &tmp_scene.r,
+ oglrender->mh,
+ oglrender->movie_ctx_arr,
+ oglrender->totvideos,
+ PRVRANGEON != 0);
+ }
+ else {
+ /* TODO(sergey): We can in theory save some CPU ticks here because we
+ * calculate file name again here.
+ */
+ char name[FILE_MAX];
+ BKE_image_path_from_imformat(name,
+ scene->r.pic,
+ oglrender->bmain->name,
+ cfra,
+ &scene->r.im_format,
+ (scene->r.scemode & R_EXTENSION) != 0,
+ true,
+ NULL);
+
+ BKE_render_result_stamp_info(scene, scene->camera, rr, false);
+ ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ if (!ok) {
+ BKE_reportf(&reports,
+ RPT_ERROR,
+ "Write error: cannot save %s",
+ name);
+ }
+ }
+ if (reports.list.first != NULL) {
+ BLI_spin_lock(&oglrender->reports_lock);
+ for (Report *report = reports.list.first;
+ report != NULL;
+ report = report->next)
+ {
+ BKE_report(oglrender->reports,
+ report->type,
+ report->message);
+ }
+ BLI_spin_unlock(&oglrender->reports_lock);
+ }
+ if (!ok) {
+ oglrender->pool_ok = false;
+ }
+ RE_FreeRenderResult(rr);
+}
+
+static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
+{
+ if (!oglrender->pool_ok) {
+ return false;
+ }
+ Scene *scene = oglrender->scene;
+ WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ task_data->rr = rr;
+ task_data->cfra = scene->r.cfra;
+ BLI_task_pool_push(oglrender->task_pool,
+ write_result_func,
+ task_data,
+ true,
+ TASK_PRIORITY_LOW);
+ return true;
+}
+
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -828,7 +951,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, NULL);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
+ BLI_spin_lock(&oglrender->reports_lock);
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
+ BLI_spin_unlock(&oglrender->reports_lock);
ok = true;
goto finally;
}
@@ -856,34 +981,10 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
-
- if (is_movie) {
- ok = RE_WriteRenderViewsMovie(oglrender->reports, rr, scene, &scene->r, oglrender->mh,
- oglrender->movie_ctx_arr, oglrender->totvideos, PRVRANGEON != 0);
- if (ok) {
- printf("Append frame %d", scene->r.cfra);
- BKE_reportf(op->reports, RPT_INFO, "Appended frame: %d", scene->r.cfra);
- }
- }
- else {
- BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(op->reports, rr, scene, true, name);
- if (ok) {
- printf("Saved: %s", name);
- BKE_reportf(op->reports, RPT_INFO, "Saved file: %s", name);
- }
- else {
- printf("Write error: cannot save %s\n", name);
- BKE_reportf(op->reports, RPT_ERROR, "Write error: cannot save %s", name);
- }
- }
-
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
RE_ReleaseResult(oglrender->re);
-
- /* movie stats prints have no line break */
- printf("\n");
-
+ ok = schedule_write_result(oglrender, new_rr);
finally: /* Step the frame and bail early if needed */