diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-01-05 21:50:09 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-01-05 21:50:09 +0400 |
commit | de4befb0756fd65ab92c6b00ca15c324dc513d52 (patch) | |
tree | 002c9ad54612fcf8bf3250bb7ae950a6b5f6d136 /source/blender | |
parent | 015b64be2a5d62d495b43cf74a255f95e0b02721 (diff) |
Code refactoring: split render result related functions into separate file.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/render/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/render/extern/include/RE_pipeline.h | 3 | ||||
-rw-r--r-- | source/blender/render/intern/include/render_result.h | 94 | ||||
-rw-r--r-- | source/blender/render/intern/include/renderpipeline.h | 12 | ||||
-rw-r--r-- | source/blender/render/intern/source/external_engine.c | 15 | ||||
-rw-r--r-- | source/blender/render/intern/source/pipeline.c | 1098 | ||||
-rw-r--r-- | source/blender/render/intern/source/rayshade.c | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/render_result.c | 1021 | ||||
-rw-r--r-- | source/blender/render/intern/source/rendercore.c | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/zbuf.c | 1 |
10 files changed, 1198 insertions, 1050 deletions
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index c7b27c3cd7e..51c5d49208e 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -66,6 +66,7 @@ set(SRC intern/source/pointdensity.c intern/source/rayshade.c intern/source/rendercore.c + intern/source/render_result.c intern/source/render_texture.c intern/source/renderdatabase.c intern/source/shadbuf.c @@ -96,6 +97,7 @@ set(SRC intern/include/rayintersection.h intern/include/raycounter.h intern/include/render_types.h + intern/include/render_result.h intern/include/rendercore.h intern/include/renderdatabase.h intern/include/renderpipeline.h diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 600d1a3c377..cc4136fcccc 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -182,9 +182,6 @@ float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype); /* obligatory initialize call, disprect is optional */ void RE_InitState (struct Render *re, struct Render *source, struct RenderData *rd, struct SceneRenderLayer *srl, int winx, int winy, rcti *disprect); -/* use this to change disprect of active render */ -void RE_SetDispRect (struct Render *re, rcti *disprect); - /* set up the viewplane/perspective matrix, three choices */ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */ void RE_SetCamera(struct Render *re, struct Object *camera); diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h new file mode 100644 index 00000000000..93cbc6fe9c9 --- /dev/null +++ b/source/blender/render/intern/include/render_result.h @@ -0,0 +1,94 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/include/render_result.h + * \ingroup render + */ + +#ifndef RENDER_RESULT_H +#define RENDER_RESULT_H + +#define PASS_VECTOR_MAX 10000.0f + +#define RR_USE_MEM 0 +#define RR_USE_EXR 1 + +struct ImBuf; +struct ListBase; +struct Render; +struct RenderData; +struct RenderLayer; +struct RenderResult; +struct Scene; +struct rcti; + +/* New */ + +struct RenderResult *render_result_new(struct Render *re, + struct rcti *partrct, int crop, int savebuffers); +struct RenderResult *render_result_new_full_sample(struct Render *re, + struct ListBase *lb, struct rcti *partrct, int crop, int savebuffers); + +struct RenderResult *render_result_new_from_exr(void *exrhandle, int rectx, int recty); + +/* Merge */ + +void render_result_merge(struct RenderResult *rr, struct RenderResult *rrpart); + +/* Free */ + +void render_result_free(struct RenderResult *rr); +void render_result_free_list(struct ListBase *lb, struct RenderResult *rr); + +/* Single Layer Render */ + +void render_result_single_layer_begin(struct Render *re); +void render_result_single_layer_end(struct Render *re); + +/* EXR Tile File Render */ + +void render_result_exr_file_begin(struct Render *re); +void render_result_exr_file_end(struct Render *re); + +void render_result_exr_file_merge(struct RenderResult *rr, struct RenderResult *rrpart); + +void render_result_exr_file_path(struct Scene *scene, int sample, char *filepath); +int render_result_exr_file_read(struct Render *re, int sample); +int render_result_exr_file_read_path(struct RenderResult *rr, const char *filepath); + +/* Combined Pixel Rect */ + +struct ImBuf *render_result_rect_to_ibuf(struct RenderResult *rr, struct RenderData *rd); +void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd, + struct ImBuf *ibuf); + +void render_result_rect_fill_zero(struct RenderResult *rr); +void render_result_rect_get_pixels(struct RenderResult *rr, struct RenderData *rd, + unsigned int *rect, int rectx, int recty); + +#endif /* RENDER_RESULT_H */ + diff --git a/source/blender/render/intern/include/renderpipeline.h b/source/blender/render/intern/include/renderpipeline.h index fc46ea83309..9a87cf84012 100644 --- a/source/blender/render/intern/include/renderpipeline.h +++ b/source/blender/render/intern/include/renderpipeline.h @@ -33,22 +33,12 @@ #ifndef PIPELINE_H #define PIPELINE_H -struct ListBase; struct Render; -struct RenderResult; struct RenderLayer; -struct rcti; +struct RenderResult; struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr); float panorama_pixel_rot(struct Render *re); -#define PASS_VECTOR_MAX 10000.0f - -#define RR_USEMEM 0 - -struct RenderResult *new_render_result(struct Render *re, struct rcti *partrct, int crop, int savebuffers); -void merge_render_result(struct RenderResult *rr, struct RenderResult *rrpart); -void free_render_result(struct ListBase *lb, struct RenderResult *rr); - #endif /* PIPELINE_H */ diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 78215498a47..703ca23c15b 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -54,7 +54,7 @@ #include "RE_pipeline.h" #include "render_types.h" -#include "renderpipeline.h" +#include "render_result.h" /* Render Engine Types */ @@ -168,7 +168,7 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, disprect.ymin= y; disprect.ymax= y+h; - result= new_render_result(re, &disprect, 0, RR_USEMEM); + result= render_result_new(re, &disprect, 0, RR_USE_MEM); BLI_addtail(&engine->fullresult, result); result->tilerect.xmin += re->disprect.xmin; @@ -198,7 +198,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result) /* merge. on break, don't merge in result for preview renders, looks nicer */ if(!(re->test_break(re->tbh) && (re->r.scemode & R_PREVIEWBUTS))) - merge_render_result(re->result, result); + render_result_merge(re->result, result); /* draw */ if(!re->test_break(re->tbh)) { @@ -207,7 +207,7 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result) } /* free */ - free_render_result(&engine->fullresult, result); + render_result_free_list(&engine->fullresult, result); } /* Cancel */ @@ -286,8 +286,9 @@ int RE_engine_render(Render *re, int do_all) /* create render result */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) { - RE_FreeRenderResult(re->result); - re->result= new_render_result(re, &re->disprect, 0, 0); + if(re->result) + render_result_free(re->result); + re->result= render_result_new(re, &re->disprect, 0, 0); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -316,7 +317,7 @@ int RE_engine_render(Render *re, int do_all) if(type->render) type->render(engine, re->scene); - free_render_result(&engine->fullresult, engine->fullresult.first); + render_result_free_list(&engine->fullresult, engine->fullresult.first); RE_engine_free(engine); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 0068407a7df..f82287e8645 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -78,6 +78,7 @@ #include "RE_pipeline.h" /* internal */ +#include "render_result.h" #include "render_types.h" #include "renderpipeline.h" #include "renderdatabase.h" @@ -184,345 +185,7 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs) void RE_FreeRenderResult(RenderResult *res) { - if(res==NULL) return; - - while(res->layers.first) { - RenderLayer *rl= res->layers.first; - - if(rl->rectf) MEM_freeN(rl->rectf); - /* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */ - if(rl->acolrect) MEM_freeN(rl->acolrect); - if(rl->scolrect) MEM_freeN(rl->scolrect); - - while(rl->passes.first) { - RenderPass *rpass= rl->passes.first; - if(rpass->rect) MEM_freeN(rpass->rect); - BLI_remlink(&rl->passes, rpass); - MEM_freeN(rpass); - } - BLI_remlink(&res->layers, rl); - MEM_freeN(rl); - } - - if(res->rect32) - MEM_freeN(res->rect32); - if(res->rectz) - MEM_freeN(res->rectz); - if(res->rectf) - MEM_freeN(res->rectf); - if(res->text) - MEM_freeN(res->text); - - MEM_freeN(res); -} - -/* version that's compatible with fullsample buffers */ -void free_render_result(ListBase *lb, RenderResult *rr) -{ - RenderResult *rrnext; - - for(; rr; rr= rrnext) { - rrnext= rr->next; - - if(lb && lb->first) - BLI_remlink(lb, rr); - - RE_FreeRenderResult(rr); - } -} - - -/* all layers except the active one get temporally pushed away */ -static void push_render_result(Render *re) -{ - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - - /* officially pushed result should be NULL... error can happen with do_seq */ - RE_FreeRenderResult(re->pushedresult); - - re->pushedresult= re->result; - re->result= NULL; - - BLI_rw_mutex_unlock(&re->resultmutex); -} - -/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */ -static void pop_render_result(Render *re) -{ - if(re->result==NULL) { - printf("pop render result error; no current result!\n"); - return; - } - - if(re->pushedresult) { - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - - if(re->pushedresult->rectx==re->result->rectx && re->pushedresult->recty==re->result->recty) { - /* find which layer in pushedresult should be replaced */ - SceneRenderLayer *srl; - RenderLayer *rlpush; - RenderLayer *rl= re->result->layers.first; - int nr; - - /* render result should be empty after this */ - BLI_remlink(&re->result->layers, rl); - - /* reconstruct render result layers */ - for(nr=0, srl= re->scene->r.layers.first; srl; srl= srl->next, nr++) { - if(nr==re->r.actlay) - BLI_addtail(&re->result->layers, rl); - else { - rlpush= RE_GetRenderLayer(re->pushedresult, srl->name); - if(rlpush) { - BLI_remlink(&re->pushedresult->layers, rlpush); - BLI_addtail(&re->result->layers, rlpush); - } - } - } - } - - RE_FreeRenderResult(re->pushedresult); - re->pushedresult= NULL; - - BLI_rw_mutex_unlock(&re->resultmutex); - } -} - -/* NOTE: OpenEXR only supports 32 chars for layer+pass names - In blender we now use max 10 chars for pass, max 20 for layer */ -static const char *get_pass_name(int passtype, int channel) -{ - - if(passtype == SCE_PASS_COMBINED) { - if(channel==-1) return "Combined"; - if(channel==0) return "Combined.R"; - if(channel==1) return "Combined.G"; - if(channel==2) return "Combined.B"; - return "Combined.A"; - } - if(passtype == SCE_PASS_Z) { - if(channel==-1) return "Depth"; - return "Depth.Z"; - } - if(passtype == SCE_PASS_VECTOR) { - if(channel==-1) return "Vector"; - if(channel==0) return "Vector.X"; - if(channel==1) return "Vector.Y"; - if(channel==2) return "Vector.Z"; - return "Vector.W"; - } - if(passtype == SCE_PASS_NORMAL) { - if(channel==-1) return "Normal"; - if(channel==0) return "Normal.X"; - if(channel==1) return "Normal.Y"; - return "Normal.Z"; - } - if(passtype == SCE_PASS_UV) { - if(channel==-1) return "UV"; - if(channel==0) return "UV.U"; - if(channel==1) return "UV.V"; - return "UV.A"; - } - if(passtype == SCE_PASS_RGBA) { - if(channel==-1) return "Color"; - if(channel==0) return "Color.R"; - if(channel==1) return "Color.G"; - if(channel==2) return "Color.B"; - return "Color.A"; - } - if(passtype == SCE_PASS_EMIT) { - if(channel==-1) return "Emit"; - if(channel==0) return "Emit.R"; - if(channel==1) return "Emit.G"; - return "Emit.B"; - } - if(passtype == SCE_PASS_DIFFUSE) { - if(channel==-1) return "Diffuse"; - if(channel==0) return "Diffuse.R"; - if(channel==1) return "Diffuse.G"; - return "Diffuse.B"; - } - if(passtype == SCE_PASS_SPEC) { - if(channel==-1) return "Spec"; - if(channel==0) return "Spec.R"; - if(channel==1) return "Spec.G"; - return "Spec.B"; - } - if(passtype == SCE_PASS_SHADOW) { - if(channel==-1) return "Shadow"; - if(channel==0) return "Shadow.R"; - if(channel==1) return "Shadow.G"; - return "Shadow.B"; - } - if(passtype == SCE_PASS_AO) { - if(channel==-1) return "AO"; - if(channel==0) return "AO.R"; - if(channel==1) return "AO.G"; - return "AO.B"; - } - if(passtype == SCE_PASS_ENVIRONMENT) { - if(channel==-1) return "Env"; - if(channel==0) return "Env.R"; - if(channel==1) return "Env.G"; - return "Env.B"; - } - if(passtype == SCE_PASS_INDIRECT) { - if(channel==-1) return "Indirect"; - if(channel==0) return "Indirect.R"; - if(channel==1) return "Indirect.G"; - return "Indirect.B"; - } - if(passtype == SCE_PASS_REFLECT) { - if(channel==-1) return "Reflect"; - if(channel==0) return "Reflect.R"; - if(channel==1) return "Reflect.G"; - return "Reflect.B"; - } - if(passtype == SCE_PASS_REFRACT) { - if(channel==-1) return "Refract"; - if(channel==0) return "Refract.R"; - if(channel==1) return "Refract.G"; - return "Refract.B"; - } - if(passtype == SCE_PASS_INDEXOB) { - if(channel==-1) return "IndexOB"; - return "IndexOB.X"; - } - if(passtype == SCE_PASS_INDEXMA) { - if(channel==-1) return "IndexMA"; - return "IndexMA.X"; - } - if(passtype == SCE_PASS_MIST) { - if(channel==-1) return "Mist"; - return "Mist.Z"; - } - if(passtype == SCE_PASS_RAYHITS) - { - if(channel==-1) return "Rayhits"; - if(channel==0) return "Rayhits.R"; - if(channel==1) return "Rayhits.G"; - return "Rayhits.B"; - } - return "Unknown"; -} - -static int passtype_from_name(const char *str) -{ - - if(strcmp(str, "Combined")==0) - return SCE_PASS_COMBINED; - - if(strcmp(str, "Depth")==0) - return SCE_PASS_Z; - - if(strcmp(str, "Vector")==0) - return SCE_PASS_VECTOR; - - if(strcmp(str, "Normal")==0) - return SCE_PASS_NORMAL; - - if(strcmp(str, "UV")==0) - return SCE_PASS_UV; - - if(strcmp(str, "Color")==0) - return SCE_PASS_RGBA; - - if(strcmp(str, "Emit")==0) - return SCE_PASS_EMIT; - - if(strcmp(str, "Diffuse")==0) - return SCE_PASS_DIFFUSE; - - if(strcmp(str, "Spec")==0) - return SCE_PASS_SPEC; - - if(strcmp(str, "Shadow")==0) - return SCE_PASS_SHADOW; - - if(strcmp(str, "AO")==0) - return SCE_PASS_AO; - - if(strcmp(str, "Env")==0) - return SCE_PASS_ENVIRONMENT; - - if(strcmp(str, "Indirect")==0) - return SCE_PASS_INDIRECT; - - if(strcmp(str, "Reflect")==0) - return SCE_PASS_REFLECT; - - if(strcmp(str, "Refract")==0) - return SCE_PASS_REFRACT; - - if(strcmp(str, "IndexOB")==0) - return SCE_PASS_INDEXOB; - - if(strcmp(str, "IndexMA")==0) - return SCE_PASS_INDEXMA; - - if(strcmp(str, "Mist")==0) - return SCE_PASS_MIST; - - if(strcmp(str, "RayHits")==0) - return SCE_PASS_RAYHITS; - return 0; -} - -static void scene_unique_exr_name(Scene *scene, char *str, int sample) -{ - char di[FILE_MAX], name[FILE_MAXFILE+MAX_ID_NAME+100], fi[FILE_MAXFILE]; - - BLI_strncpy(di, G.main->name, FILE_MAX); - BLI_splitdirstring(di, fi); - - if(sample==0) - BLI_snprintf(name, sizeof(name), "%s_%s.exr", fi, scene->id.name+2); - else - BLI_snprintf(name, sizeof(name), "%s_%s%d.exr", fi, scene->id.name+2, sample); - - BLI_make_file_string("/", str, BLI_temporary_dir(), name); -} - -static void render_unique_exr_name(Render *re, char *str, int sample) -{ - scene_unique_exr_name(re->scene, str, sample); -} - -static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype) -{ - const char *typestr= get_pass_name(passtype, 0); - RenderPass *rpass= MEM_callocN(sizeof(RenderPass), typestr); - int rectsize= rr->rectx*rr->recty*channels; - - BLI_addtail(&rl->passes, rpass); - rpass->passtype= passtype; - rpass->channels= channels; - rpass->rectx= rl->rectx; - rpass->recty= rl->recty; - - if(rr->exrhandle) { - int a; - for(a=0; a<channels; a++) - IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL); - } - else { - float *rect; - int x; - - rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr); - - if(passtype==SCE_PASS_VECTOR) { - /* initialize to max speed */ - rect= rpass->rect; - for(x= rectsize-1; x>=0; x--) - rect[x]= PASS_VECTOR_MAX; - } - else if(passtype==SCE_PASS_Z) { - rect= rpass->rect; - for(x= rectsize-1; x>=0; x--) - rect[x]= 10e10; - } - } + render_result_free(res); } float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) @@ -547,140 +210,19 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) return NULL; } -/* called by main render as well for parts */ -/* will read info from Render *re to define layers */ -/* called in threads */ -/* re->winx,winy is coordinate space of entire image, partrct the part within */ -RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int savebuffers) +RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty) { - RenderResult *rr; - RenderLayer *rl; - SceneRenderLayer *srl; - int rectx, recty, nr; - - rectx= partrct->xmax - partrct->xmin; - recty= partrct->ymax - partrct->ymin; - - if(rectx<=0 || recty<=0) - return NULL; - - rr= MEM_callocN(sizeof(RenderResult), "new render result"); - rr->rectx= rectx; - rr->recty= recty; - rr->renrect.xmin= 0; rr->renrect.xmax= rectx-2*crop; - /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ - rr->crop= crop; - - /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ - rr->tilerect.xmin= partrct->xmin - re->disprect.xmin; - rr->tilerect.xmax= partrct->xmax - re->disprect.xmax; - rr->tilerect.ymin= partrct->ymin - re->disprect.ymin; - rr->tilerect.ymax= partrct->ymax - re->disprect.ymax; - - if(savebuffers) { - rr->exrhandle= IMB_exr_get_handle(); - } - - /* check renderdata for amount of layers */ - for(nr=0, srl= re->r.layers.first; srl; srl= srl->next, nr++) { - - if((re->r.scemode & R_SINGLE_LAYER) && nr!=re->r.actlay) - continue; - if(srl->layflag & SCE_LAY_DISABLE) - continue; - - rl= MEM_callocN(sizeof(RenderLayer), "new render layer"); - BLI_addtail(&rr->layers, rl); - - BLI_strncpy(rl->name, srl->name, sizeof(rl->name)); - rl->lay= srl->lay; - rl->lay_zmask= srl->lay_zmask; - rl->layflag= srl->layflag; - rl->passflag= srl->passflag; // for debugging: srl->passflag|SCE_PASS_RAYHITS; - rl->pass_xor= srl->pass_xor; - rl->light_override= srl->light_override; - rl->mat_override= srl->mat_override; - rl->rectx= rectx; - rl->recty= recty; - - if(rr->exrhandle) { - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL); - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL); - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL); - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL); - } - else - rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba"); - - if(srl->passflag & SCE_PASS_Z) - render_layer_add_pass(rr, rl, 1, SCE_PASS_Z); - if(srl->passflag & SCE_PASS_VECTOR) - render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR); - if(srl->passflag & SCE_PASS_NORMAL) - render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL); - if(srl->passflag & SCE_PASS_UV) - render_layer_add_pass(rr, rl, 3, SCE_PASS_UV); - if(srl->passflag & SCE_PASS_RGBA) - render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA); - if(srl->passflag & SCE_PASS_EMIT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT); - if(srl->passflag & SCE_PASS_DIFFUSE) - render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE); - if(srl->passflag & SCE_PASS_SPEC) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC); - if(srl->passflag & SCE_PASS_AO) - render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); - if(srl->passflag & SCE_PASS_ENVIRONMENT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT); - if(srl->passflag & SCE_PASS_INDIRECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT); - if(srl->passflag & SCE_PASS_SHADOW) - render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); - if(srl->passflag & SCE_PASS_REFLECT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT); - if(srl->passflag & SCE_PASS_REFRACT) - render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT); - if(srl->passflag & SCE_PASS_INDEXOB) - render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB); - if(srl->passflag & SCE_PASS_INDEXMA) - render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA); - if(srl->passflag & SCE_PASS_MIST) - render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST); - if(rl->passflag & SCE_PASS_RAYHITS) - render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS); - - } - /* sss, previewrender and envmap don't do layers, so we make a default one */ - if(rr->layers.first==NULL) { - rl= MEM_callocN(sizeof(RenderLayer), "new render layer"); - BLI_addtail(&rr->layers, rl); - - rl->rectx= rectx; - rl->recty= recty; - - /* duplicate code... */ - if(rr->exrhandle) { - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL); - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL); - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL); - IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL); - } - else - rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba"); - - /* note, this has to be in sync with scene.c */ - rl->lay= (1<<20) -1; - rl->layflag= 0x7FFF; /* solid ztra halo strand */ - rl->passflag= SCE_PASS_COMBINED; - - re->r.actlay= 0; - } - - /* border render; calculate offset for use in compositor. compo is centralized coords */ - rr->xof= re->disprect.xmin + (re->disprect.xmax - re->disprect.xmin)/2 - re->winx/2; - rr->yof= re->disprect.ymin + (re->disprect.ymax - re->disprect.ymin)/2 - re->winy/2; + return render_result_new_from_exr(exrhandle, rectx, recty); +} + +RenderLayer *render_get_active_layer(Render *re, RenderResult *rr) +{ + RenderLayer *rl= BLI_findlink(&rr->layers, re->r.actlay); - return rr; + if(rl) + return rl; + else + return rr->layers.first; } static int render_scene_needs_vector(Render *re) @@ -695,344 +237,6 @@ static int render_scene_needs_vector(Render *re) return 0; } -static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize) -{ - int y, ofs, copylen, tilex, tiley; - - copylen= tilex= rrpart->rectx; - tiley= rrpart->recty; - - if(rrpart->crop) { /* filters add pixel extra */ - tile+= pixsize*(rrpart->crop + rrpart->crop*tilex); - - copylen= tilex - 2*rrpart->crop; - tiley -= 2*rrpart->crop; - - ofs= (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop); - target+= pixsize*ofs; - } - else { - ofs= (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin); - target+= pixsize*ofs; - } - - copylen *= sizeof(float)*pixsize; - tilex *= pixsize; - ofs= pixsize*rr->rectx; - - for(y=0; y<tiley; y++) { - memcpy(target, tile, copylen); - target+= ofs; - tile+= tilex; - } -} - -/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */ -/* no test happens here if it fits... we also assume layers are in sync */ -/* is used within threads */ -void merge_render_result(RenderResult *rr, RenderResult *rrpart) -{ - RenderLayer *rl, *rlp; - RenderPass *rpass, *rpassp; - - for(rl= rr->layers.first, rlp= rrpart->layers.first; rl && rlp; rl= rl->next, rlp= rlp->next) { - - /* combined */ - if(rl->rectf && rlp->rectf) - do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4); - - /* passes are allocated in sync */ - for(rpass= rl->passes.first, rpassp= rlp->passes.first; rpass && rpassp; rpass= rpass->next, rpassp= rpassp->next) { - do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels); - } - } -} - - -static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) -{ - RenderLayer *rlp; - RenderPass *rpassp; - int offs, partx, party; - - BLI_lock_thread(LOCK_IMAGE); - - for(rlp= rrpart->layers.first; rlp; rlp= rlp->next) { - - if(rrpart->crop) { /* filters add pixel extra */ - offs= (rrpart->crop + rrpart->crop*rrpart->rectx); - } - else { - offs= 0; - } - - /* combined */ - if(rlp->rectf) { - int a, xstride= 4; - for(a=0; a<xstride; a++) - IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride*rrpart->rectx, rlp->rectf+a + xstride*offs); - } - - /* passes are allocated in sync */ - for(rpassp= rlp->passes.first; rpassp; rpassp= rpassp->next) { - int a, xstride= rpassp->channels; - for(a=0; a<xstride; a++) - IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), - xstride, xstride*rrpart->rectx, rpassp->rect+a + xstride*offs); - } - - } - - party= rrpart->tilerect.ymin + rrpart->crop; - partx= rrpart->tilerect.xmin + rrpart->crop; - IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0); - - BLI_unlock_thread(LOCK_IMAGE); - -} - -static void save_empty_result_tiles(Render *re) -{ - RenderPart *pa; - RenderResult *rr; - - for(rr= re->result; rr; rr= rr->next) { - IMB_exrtile_clear_channels(rr->exrhandle); - - for(pa= re->parts.first; pa; pa= pa->next) { - if(pa->ready==0) { - int party= pa->disprect.ymin - re->disprect.ymin + pa->crop; - int partx= pa->disprect.xmin - re->disprect.xmin + pa->crop; - IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0); - } - } - } -} - - -/* for passes read from files, these have names stored */ -static char *make_pass_name(RenderPass *rpass, int chan) -{ - static char name[16]; - int len; - - BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME); - len= strlen(name); - name[len]= '.'; - name[len+1]= rpass->chan_id[chan]; - name[len+2]= 0; - - return name; -} - -/* filename already made absolute */ -/* called from within UI, saves both rendered result as a file-read result */ -int RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress) -{ - RenderLayer *rl; - RenderPass *rpass; - void *exrhandle= IMB_exr_get_handle(); - int success; - - BLI_make_existing_file(filename); - - /* composite result */ - if(rr->rectf) { - IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4*rr->rectx, rr->rectf); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4*rr->rectx, rr->rectf+1); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4*rr->rectx, rr->rectf+2); - IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4*rr->rectx, rr->rectf+3); - } - - /* add layers/passes and assign channels */ - for(rl= rr->layers.first; rl; rl= rl->next) { - - /* combined */ - if(rl->rectf) { - int a, xstride= 4; - for(a=0; a<xstride; a++) - IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride*rr->rectx, rl->rectf+a); - } - - /* passes are allocated in sync */ - for(rpass= rl->passes.first; rpass; rpass= rpass->next) { - int a, xstride= rpass->channels; - for(a=0; a<xstride; a++) { - if(rpass->passtype) - IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), - xstride, xstride*rr->rectx, rpass->rect+a); - else - IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), - xstride, xstride*rr->rectx, rpass->rect+a); - } - } - } - - /* when the filename has no permissions, this can fail */ - if(IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) { - IMB_exr_write_channels(exrhandle); - success= TRUE; - } - else { - /* TODO, get the error from openexr's exception */ - BKE_report(reports, RPT_ERROR, "Error Writing Render Result, see console"); - success= FALSE; - } - IMB_exr_close(exrhandle); - - return success; -} - -/* callbacks for RE_MultilayerConvert */ -static void *ml_addlayer_cb(void *base, char *str) -{ - RenderResult *rr= base; - RenderLayer *rl; - - rl= MEM_callocN(sizeof(RenderLayer), "new render layer"); - BLI_addtail(&rr->layers, rl); - - BLI_strncpy(rl->name, str, EXR_LAY_MAXNAME); - return rl; -} -static void ml_addpass_cb(void *UNUSED(base), void *lay, char *str, float *rect, int totchan, char *chan_id) -{ - RenderLayer *rl= lay; - RenderPass *rpass= MEM_callocN(sizeof(RenderPass), "loaded pass"); - int a; - - BLI_addtail(&rl->passes, rpass); - rpass->channels= totchan; - - rpass->passtype= passtype_from_name(str); - if(rpass->passtype==0) printf("unknown pass %s\n", str); - rl->passflag |= rpass->passtype; - - BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME); - /* channel id chars */ - for(a=0; a<totchan; a++) - rpass->chan_id[a]= chan_id[a]; - - rpass->rect= rect; -} - -/* from imbuf, if a handle was returned we convert this to render result */ -RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty) -{ - RenderResult *rr= MEM_callocN(sizeof(RenderResult), "loaded render result"); - RenderLayer *rl; - RenderPass *rpass; - - rr->rectx= rectx; - rr->recty= recty; - - IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb); - - for(rl=rr->layers.first; rl; rl=rl->next) { - rl->rectx= rectx; - rl->recty= recty; - - for(rpass=rl->passes.first; rpass; rpass=rpass->next) { - rpass->rectx= rectx; - rpass->recty= recty; - } - } - - return rr; -} - -/* called in end of render, to add names to passes... for UI only */ -static void renderresult_add_names(RenderResult *rr) -{ - RenderLayer *rl; - RenderPass *rpass; - - for(rl= rr->layers.first; rl; rl= rl->next) - for(rpass= rl->passes.first; rpass; rpass= rpass->next) - BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); -} - -/* called for reading temp files, and for external engines */ -static int read_render_result_from_file(const char *filename, RenderResult *rr) -{ - RenderLayer *rl; - RenderPass *rpass; - void *exrhandle= IMB_exr_get_handle(); - int rectx, recty; - - if(IMB_exr_begin_read(exrhandle, filename, &rectx, &recty)==0) { - printf("failed being read %s\n", filename); - IMB_exr_close(exrhandle); - return 0; - } - - if(rr == NULL || rectx!=rr->rectx || recty!=rr->recty) { - if(rr) - printf("error in reading render result: dimensions don't match\n"); - else - printf("error in reading render result: NULL result pointer\n"); - IMB_exr_close(exrhandle); - return 0; - } - else { - for(rl= rr->layers.first; rl; rl= rl->next) { - - /* combined */ - if(rl->rectf) { - int a, xstride= 4; - for(a=0; a<xstride; a++) - IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), - xstride, xstride*rectx, rl->rectf+a); - } - - /* passes are allocated in sync */ - for(rpass= rl->passes.first; rpass; rpass= rpass->next) { - int a, xstride= rpass->channels; - for(a=0; a<xstride; a++) - IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), - xstride, xstride*rectx, rpass->rect+a); - } - - } - IMB_exr_read_channels(exrhandle); - renderresult_add_names(rr); - } - - IMB_exr_close(exrhandle); - - return 1; -} - -/* only for temp buffer files, makes exact copy of render result */ -static int read_render_result(Render *re, int sample) -{ - char str[FILE_MAX]; - int success; - - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - - RE_FreeRenderResult(re->result); - re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM); - - render_unique_exr_name(re, str, sample); - printf("read exr tmp file: %s\n", str); - - if(read_render_result_from_file(str, re->result)) { - success= TRUE; - } - else { - printf("cannot read: %s\n", str); - success= FALSE; - - } - - BLI_rw_mutex_unlock(&re->resultmutex); - - return success; -} - /* *************************************************** */ Render *RE_GetRender(const char *name) @@ -1091,17 +295,6 @@ Scene *RE_GetScene(Render *re) return NULL; } -RenderLayer *render_get_active_layer(Render *re, RenderResult *rr) -{ - RenderLayer *rl= BLI_findlink(&rr->layers, re->r.actlay); - - if(rl) - return rl; - else - return rr->layers.first; -} - - /* fill provided result struct with what's currently active or done */ void RE_AcquireResultImage(Render *re, RenderResult *rr) { @@ -1148,23 +341,7 @@ void RE_ResultGet32(Render *re, unsigned int *rect) RenderResult rres; RE_AcquireResultImage(re, &rres); - - if(rres.rect32) { - memcpy(rect, rres.rect32, sizeof(int)*rres.rectx*rres.recty); - } - else if(rres.rectf) { - int profile_from= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); - int dither= 0; - - IMB_buffer_byte_from_float((unsigned char*)rect, rres.rectf, - 4, dither, IB_PROFILE_SRGB, profile_from, predivide, - rres.rectx, rres.recty, rres.rectx, rres.rectx); - } - else - /* else fill with black */ - memset(rect, 0, sizeof(int)*re->rectx*re->recty); - + render_result_rect_get_pixels(&rres, &re->r, rect, re->rectx, re->recty); RE_ReleaseResultImage(re); } @@ -1222,8 +399,8 @@ void RE_FreeRender(Render *re) free_renderdata_tables(re); free_sample_tables(re); - RE_FreeRenderResult(re->result); - RE_FreeRenderResult(re->pushedresult); + render_result_free(re->result); + render_result_free(re->pushedresult); BLI_remlink(&RenderGlobal.renderlist, re); MEM_freeN(re); @@ -1323,14 +500,14 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer * if(re->r.scemode & R_PREVIEWBUTS) { if(re->result && re->result->rectx==re->rectx && re->result->recty==re->recty); else { - RE_FreeRenderResult(re->result); + render_result_free(re->result); re->result= NULL; } } else { /* make empty render result, so display callbacks can initialize */ - RE_FreeRenderResult(re->result); + render_result_free(re->result); re->result= MEM_callocN(sizeof(RenderResult), "new render result"); re->result->rectx= re->rectx; re->result->recty= re->recty; @@ -1346,22 +523,6 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer * RE_init_threadcount(re); } -/* part of external api, not called for regular render pipeline */ -void RE_SetDispRect (struct Render *re, rcti *disprect) -{ - re->disprect= *disprect; - re->rectx= disprect->xmax-disprect->xmin; - re->recty= disprect->ymax-disprect->ymin; - - /* initialize render result */ - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - - RE_FreeRenderResult(re->result); - re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM); - - BLI_rw_mutex_unlock(&re->resultmutex); -} - void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ @@ -1456,24 +617,6 @@ static int render_display_draw_enabled(Render *re) return 1; } -/* allocate osa new results for samples */ -static RenderResult *new_full_sample_buffers(Render *re, ListBase *lb, rcti *partrct, int crop) -{ - int a; - - if(re->osa==0) - return new_render_result(re, partrct, crop, RR_USEMEM); - - for(a=0; a<re->osa; a++) { - RenderResult *rr= new_render_result(re, partrct, crop, RR_USEMEM); - BLI_addtail(lb, rr); - rr->sample_nr= a; - } - - return lb->first; -} - - /* the main thread call, renders an entire part */ static void *do_part_thread(void *pa_v) { @@ -1483,9 +626,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= new_full_sample_buffers(&R, &pa->fullresult, &pa->disprect, pa->crop); + pa->result= render_result_new_full_sample(&R, &pa->fullresult, &pa->disprect, pa->crop, RR_USE_MEM); else - pa->result= new_render_result(&R, &pa->disprect, pa->crop, RR_USEMEM); + pa->result= render_result_new(&R, &pa->disprect, pa->crop, RR_USE_MEM); if(R.sss_points) zbufshade_sss_tile(pa); @@ -1496,16 +639,12 @@ static void *do_part_thread(void *pa_v) /* merge too on break! */ if(R.result->exrhandle) { - RenderResult *rr, *rrpart; - - for(rr= R.result, rrpart= pa->result; rr && rrpart; rr= rr->next, rrpart= rrpart->next) - save_render_result_tile(rr, rrpart); - + render_result_exr_file_merge(R.result, pa->result); } else if(render_display_draw_enabled(&R)) { /* on break, don't merge in result for preview renders, looks nicer */ if(R.test_break(R.tbh) && (R.r.scemode & R_PREVIEWBUTS)); - else merge_render_result(R.result, pa->result); + else render_result_merge(R.result, pa->result); } } @@ -1629,20 +768,6 @@ static void print_part_stats(Render *re, RenderPart *pa) re->i.infostr= NULL; } -/* make osa new results for samples */ -static RenderResult *new_full_sample_buffers_exr(Render *re) -{ - int a; - - for(a=0; a<re->osa; a++) { - RenderResult *rr= new_render_result(re, &re->disprect, 0, 1); - BLI_addtail(&re->fullresult, rr); - rr->sample_nr= a; - } - - return re->fullresult.first; -} - static void threaded_tile_processor(Render *re) { ListBase threads; @@ -1654,14 +779,15 @@ static void threaded_tile_processor(Render *re) /* first step; free the entire render result, make new, and/or prepare exr buffer saving */ if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) { - RE_FreeRenderResult(re->result); + render_result_free(re->result); if(re->sss_points && render_display_draw_enabled(re)) - re->result= new_render_result(re, &re->disprect, 0, 0); + re->result= render_result_new(re, &re->disprect, 0, RR_USE_MEM); else if(re->r.scemode & R_FULL_SAMPLE) - re->result= new_full_sample_buffers_exr(re); + re->result= render_result_new_full_sample(re, &re->fullresult, &re->disprect, 0, RR_USE_EXR); else - re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE)); + re->result= render_result_new(re, &re->disprect, 0, + (re->r.scemode & R_EXR_TILE_FILE)? RR_USE_EXR: RR_USE_MEM); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -1673,17 +799,8 @@ static void threaded_tile_processor(Render *re) initparts(re); - if(re->result->exrhandle) { - RenderResult *rr; - char str[FILE_MAX]; - - for(rr= re->result; rr; rr= rr->next) { - render_unique_exr_name(re, str, rr->sample_nr); - - printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str); - IMB_exrtile_begin_write(rr->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party); - } - } + if(re->result->exrhandle) + render_result_exr_file_begin(re); BLI_init_threads(&threads, do_part_thread, re->r.threads); @@ -1737,7 +854,7 @@ static void threaded_tile_processor(Render *re) re->display_draw(re->ddh, pa->result, NULL); print_part_stats(re, pa); - free_render_result(&pa->fullresult, pa->result); + render_result_free_list(&pa->fullresult, pa->result); pa->result= NULL; re->i.partsdone++; re->progress(re->prh, re->i.partsdone / (float)re->i.totpart); @@ -1763,22 +880,9 @@ static void threaded_tile_processor(Render *re) } if(re->result->exrhandle) { - RenderResult *rr; - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - save_empty_result_tiles(re); - - for(rr= re->result; rr; rr= rr->next) { - IMB_exr_close(rr->exrhandle); - rr->exrhandle= NULL; - } - - free_render_result(&re->fullresult, re->result); - re->result= NULL; - + render_result_exr_file_end(re); BLI_rw_mutex_unlock(&re->resultmutex); - - read_render_result(re, 0); } /* unset threadsafety */ @@ -1928,7 +1032,7 @@ static void do_render_blur_3d(Render *re) int blur= re->r.mblur_samples; /* create accumulation render result */ - rres= new_render_result(re, &re->disprect, 0, RR_USEMEM); + rres= render_result_new(re, &re->disprect, 0, RR_USE_MEM); /* do the blur steps */ while(blur--) { @@ -1946,7 +1050,7 @@ static void do_render_blur_3d(Render *re) /* swap results */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - RE_FreeRenderResult(re->result); + render_result_free(re->result); re->result= rres; BLI_rw_mutex_unlock(&re->resultmutex); @@ -2053,7 +1157,7 @@ static void do_render_fields_3d(Render *re) re->disprect.ymax *= 2; BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM); + re->result= render_result_new(re, &re->disprect, 0, RR_USE_MEM); if(rr2) { if(re->r.mode & R_ODDFIELD) @@ -2061,10 +1165,10 @@ static void do_render_fields_3d(Render *re) else merge_renderresult_fields(re->result, rr1, rr2); - RE_FreeRenderResult(rr2); + render_result_free(rr2); } - RE_FreeRenderResult(rr1); + render_result_free(rr1); re->i.curfield= 0; /* stats */ @@ -2116,10 +1220,10 @@ static void do_render_fields_blur_3d(Render *re) re->rectx= re->winx; re->recty= re->winy; - rres= new_render_result(re, &re->disprect, 0, RR_USEMEM); + rres= render_result_new(re, &re->disprect, 0, RR_USE_MEM); - merge_render_result(rres, re->result); - RE_FreeRenderResult(re->result); + render_result_merge(rres, re->result); + render_result_free(re->result); re->result= rres; /* weak... the display callback wants an active renderlayer pointer... */ @@ -2302,8 +1406,11 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) for(re1= RenderGlobal.renderlist.first; re1; re1= re1->next) { if(re1->scene->id.flag & LIB_DOIT) { if(re1->r.scemode & R_FULL_SAMPLE) { - if(sample) - read_render_result(re1, sample); + if(sample) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_exr_file_read(re1, sample); + BLI_rw_mutex_unlock(&re->resultmutex); + } ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */ } } @@ -2432,8 +1539,8 @@ static void do_render_composite_fields_blur_3d(Render *re) /* ensure new result gets added, like for regular renders */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - RE_FreeRenderResult(re->result); - re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM); + render_result_free(re->result); + re->result= render_result_new(re, &re->disprect, 0, RR_USE_MEM); BLI_rw_mutex_unlock(&re->resultmutex); @@ -2442,8 +1549,11 @@ static void do_render_composite_fields_blur_3d(Render *re) } /* swap render result */ - if(re->r.scemode & R_SINGLE_LAYER) - pop_render_result(re); + if(re->r.scemode & R_SINGLE_LAYER) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_single_layer_end(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } if(!re->test_break(re->tbh)) { @@ -2559,61 +1669,19 @@ static void do_render_seq(Render * re) BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); if(ibuf) { - if(ibuf->rect_float) { - /* color management: when off ensure rectf is non-lin, since thats what the internal - * render engine delivers */ - int profile_to= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int profile_from= (ibuf->profile == IB_PROFILE_LINEAR_RGB)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; - int predivide= (re->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); - - if (!rr->rectf) - rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf"); - - IMB_buffer_float_from_float(rr->rectf, ibuf->rect_float, - 4, profile_to, profile_from, predivide, - rr->rectx, rr->recty, rr->rectx, rr->rectx); - - /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 - can hang around when sequence render has rendered a 32 bits one before */ - if(rr->rect32) { - MEM_freeN(rr->rect32); - rr->rect32= NULL; - } - } - else if(ibuf->rect) { - if (!rr->rect32) - rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect"); - - memcpy(rr->rect32, ibuf->rect, 4*rr->rectx*rr->recty); - - /* if (ibuf->zbuf) { */ - /* if (R.rectz) freeN(R.rectz); */ - /* R.rectz = BLI_dupallocN(ibuf->zbuf); */ - /* } */ - - /* Same things as above, old rectf can hang around from previous render. */ - if(rr->rectf) { - MEM_freeN(rr->rectf); - rr->rectf= NULL; - } - } + /* 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) { + if (ed) free_imbuf_seq(re->scene, &ed->seqbase, TRUE, TRUE); - } } IMB_freeImBuf(ibuf); } else { /* render result is delivered empty in most cases, nevertheless we handle all cases */ - if (rr->rectf) - memset(rr->rectf, 0, 4*sizeof(float)*rr->rectx*rr->recty); - else if (rr->rect32) - memset(rr->rect32, 0, 4*rr->rectx*rr->recty); - else - rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect"); + render_result_rect_fill_zero(rr); } BLI_rw_mutex_unlock(&re->resultmutex); @@ -2655,11 +1723,6 @@ static void do_render_all_options(Render *re) do_render_composite_fields_blur_3d(re); } - /* for UI only */ - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - renderresult_add_names(re->result); - BLI_rw_mutex_unlock(&re->resultmutex); - re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime; re->stats_draw(re->sdh, &re->i); @@ -2743,7 +1806,7 @@ int RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *r if(scene->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE)) { char str[FILE_MAX]; - scene_unique_exr_name(scene, str, 0); + render_result_exr_file_path(scene, 0, str); if (BLI_file_is_writable(str)==0) { BKE_report(reports, RPT_ERROR, "Can not save render buffers, check the temp default path"); @@ -2905,8 +1968,11 @@ static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, Sc update_physics_cache(re, scene, anim_init); } - if(srl || scene->r.scemode & R_SINGLE_LAYER) - push_render_result(re); + if(srl || scene->r.scemode & R_SINGLE_LAYER) { + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + render_result_single_layer_begin(re); + BLI_rw_mutex_unlock(&re->resultmutex); + } RE_InitState(re, NULL, &scene->r, srl, winx, winy, &disprect); if(!re->ok) /* if an error was printed, abort */ @@ -3003,37 +2069,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie } } else { - int flags = (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE)? IB_cm_predivide: 0; - ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.im_format.planes, flags); - - /* if not exists, BKE_write_ibuf makes one */ - ibuf->rect= (unsigned int *)rres.rect32; - ibuf->rect_float= rres.rectf; - ibuf->zbuf_float= rres.rectz; - - /* float factor for random dither, imbuf takes care of it */ - ibuf->dither= scene->r.dither_intensity; - - /* prepare to gamma correct to sRGB color space */ - if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) { - /* sequence editor can generate 8bpc render buffers */ - if (ibuf->rect) { - ibuf->profile = IB_PROFILE_SRGB; - if (BKE_imtype_valid_depths(scene->r.im_format.imtype) & (R_IMF_CHAN_DEPTH_12|R_IMF_CHAN_DEPTH_16|R_IMF_CHAN_DEPTH_24|R_IMF_CHAN_DEPTH_32)) - IMB_float_from_rect(ibuf); - } else { - ibuf->profile = IB_PROFILE_LINEAR_RGB; - } - } - - /* color -> greyscale */ - /* editing directly would alter the render view */ - if(scene->r.im_format.planes == R_IMF_PLANES_BW) { - ImBuf *ibuf_bw= IMB_dupImBuf(ibuf); - IMB_color_to_bw(ibuf_bw); - IMB_freeImBuf(ibuf); - ibuf= ibuf_bw; - } + ImBuf *ibuf= render_result_rect_to_ibuf(&rres, &scene->r); ok= BKE_write_ibuf_stamp(scene, camera, ibuf, name, &scene->r.im_format); @@ -3232,7 +2268,7 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce) int RE_ReadRenderResult(Scene *scene, Scene *scenode) { Render *re; - int winx, winy; + int winx, winy, success; rcti disprect; /* calculate actual render result and display size */ @@ -3263,7 +2299,11 @@ int RE_ReadRenderResult(Scene *scene, Scene *scenode) RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect); re->scene= scene; - return read_render_result(re, 0); + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + success= render_result_exr_file_read(re, 0); + BLI_rw_mutex_unlock(&re->resultmutex); + + return success; } void RE_set_max_threads(int threads) @@ -3330,7 +2370,7 @@ void RE_layer_load_from_file(RenderLayer *layer, ReportList *reports, const char void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename) { - if(!read_render_result_from_file(filename, result)) { + if(!render_result_exr_file_read_path(result, filename)) { BKE_reportf(reports, RPT_ERROR, "RE_result_rect_from_file: failed to load '%s'\n", filename); return; } diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 41bfcb55068..42ad5fd15e5 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -53,6 +53,7 @@ #include "PIL_time.h" +#include "render_result.h" #include "render_types.h" #include "renderpipeline.h" #include "rendercore.h" diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c new file mode 100644 index 00000000000..e825c9d842e --- /dev/null +++ b/source/blender/render/intern/source/render_result.c @@ -0,0 +1,1021 @@ +/* + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/render/intern/source/render_result.c + * \ingroup render + */ + +#include <stdio.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BKE_image.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_report.h" +#include "BKE_utildefines.h" + +#include "BLI_fileops.h" +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_threads.h" +#include "BLI_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "intern/openexr/openexr_multi.h" + +#include "render_result.h" +#include "render_types.h" + +/********************************** Free *************************************/ + +void render_result_free(RenderResult *res) +{ + if(res==NULL) return; + + while(res->layers.first) { + RenderLayer *rl= res->layers.first; + + if(rl->rectf) MEM_freeN(rl->rectf); + /* acolrect and scolrect are optionally allocated in shade_tile, only free here since it can be used for drawing */ + if(rl->acolrect) MEM_freeN(rl->acolrect); + if(rl->scolrect) MEM_freeN(rl->scolrect); + + while(rl->passes.first) { + RenderPass *rpass= rl->passes.first; + if(rpass->rect) MEM_freeN(rpass->rect); + BLI_remlink(&rl->passes, rpass); + MEM_freeN(rpass); + } + BLI_remlink(&res->layers, rl); + MEM_freeN(rl); + } + + if(res->rect32) + MEM_freeN(res->rect32); + if(res->rectz) + MEM_freeN(res->rectz); + if(res->rectf) + MEM_freeN(res->rectf); + if(res->text) + MEM_freeN(res->text); + + MEM_freeN(res); +} + +/* version that's compatible with fullsample buffers */ +void render_result_free_list(ListBase *lb, RenderResult *rr) +{ + RenderResult *rrnext; + + for(; rr; rr= rrnext) { + rrnext= rr->next; + + if(lb && lb->first) + BLI_remlink(lb, rr); + + render_result_free(rr); + } +} + +/********************************* Names *************************************/ + +/* NOTE: OpenEXR only supports 32 chars for layer+pass names + In blender we now use max 10 chars for pass, max 20 for layer */ +static const char *get_pass_name(int passtype, int channel) +{ + + if(passtype == SCE_PASS_COMBINED) { + if(channel==-1) return "Combined"; + if(channel==0) return "Combined.R"; + if(channel==1) return "Combined.G"; + if(channel==2) return "Combined.B"; + return "Combined.A"; + } + if(passtype == SCE_PASS_Z) { + if(channel==-1) return "Depth"; + return "Depth.Z"; + } + if(passtype == SCE_PASS_VECTOR) { + if(channel==-1) return "Vector"; + if(channel==0) return "Vector.X"; + if(channel==1) return "Vector.Y"; + if(channel==2) return "Vector.Z"; + return "Vector.W"; + } + if(passtype == SCE_PASS_NORMAL) { + if(channel==-1) return "Normal"; + if(channel==0) return "Normal.X"; + if(channel==1) return "Normal.Y"; + return "Normal.Z"; + } + if(passtype == SCE_PASS_UV) { + if(channel==-1) return "UV"; + if(channel==0) return "UV.U"; + if(channel==1) return "UV.V"; + return "UV.A"; + } + if(passtype == SCE_PASS_RGBA) { + if(channel==-1) return "Color"; + if(channel==0) return "Color.R"; + if(channel==1) return "Color.G"; + if(channel==2) return "Color.B"; + return "Color.A"; + } + if(passtype == SCE_PASS_EMIT) { + if(channel==-1) return "Emit"; + if(channel==0) return "Emit.R"; + if(channel==1) return "Emit.G"; + return "Emit.B"; + } + if(passtype == SCE_PASS_DIFFUSE) { + if(channel==-1) return "Diffuse"; + if(channel==0) return "Diffuse.R"; + if(channel==1) return "Diffuse.G"; + return "Diffuse.B"; + } + if(passtype == SCE_PASS_SPEC) { + if(channel==-1) return "Spec"; + if(channel==0) return "Spec.R"; + if(channel==1) return "Spec.G"; + return "Spec.B"; + } + if(passtype == SCE_PASS_SHADOW) { + if(channel==-1) return "Shadow"; + if(channel==0) return "Shadow.R"; + if(channel==1) return "Shadow.G"; + return "Shadow.B"; + } + if(passtype == SCE_PASS_AO) { + if(channel==-1) return "AO"; + if(channel==0) return "AO.R"; + if(channel==1) return "AO.G"; + return "AO.B"; + } + if(passtype == SCE_PASS_ENVIRONMENT) { + if(channel==-1) return "Env"; + if(channel==0) return "Env.R"; + if(channel==1) return "Env.G"; + return "Env.B"; + } + if(passtype == SCE_PASS_INDIRECT) { + if(channel==-1) return "Indirect"; + if(channel==0) return "Indirect.R"; + if(channel==1) return "Indirect.G"; + return "Indirect.B"; + } + if(passtype == SCE_PASS_REFLECT) { + if(channel==-1) return "Reflect"; + if(channel==0) return "Reflect.R"; + if(channel==1) return "Reflect.G"; + return "Reflect.B"; + } + if(passtype == SCE_PASS_REFRACT) { + if(channel==-1) return "Refract"; + if(channel==0) return "Refract.R"; + if(channel==1) return "Refract.G"; + return "Refract.B"; + } + if(passtype == SCE_PASS_INDEXOB) { + if(channel==-1) return "IndexOB"; + return "IndexOB.X"; + } + if(passtype == SCE_PASS_INDEXMA) { + if(channel==-1) return "IndexMA"; + return "IndexMA.X"; + } + if(passtype == SCE_PASS_MIST) { + if(channel==-1) return "Mist"; + return "Mist.Z"; + } + if(passtype == SCE_PASS_RAYHITS) + { + if(channel==-1) return "Rayhits"; + if(channel==0) return "Rayhits.R"; + if(channel==1) return "Rayhits.G"; + return "Rayhits.B"; + } + return "Unknown"; +} + +static int passtype_from_name(const char *str) +{ + + if(strcmp(str, "Combined")==0) + return SCE_PASS_COMBINED; + + if(strcmp(str, "Depth")==0) + return SCE_PASS_Z; + + if(strcmp(str, "Vector")==0) + return SCE_PASS_VECTOR; + + if(strcmp(str, "Normal")==0) + return SCE_PASS_NORMAL; + + if(strcmp(str, "UV")==0) + return SCE_PASS_UV; + + if(strcmp(str, "Color")==0) + return SCE_PASS_RGBA; + + if(strcmp(str, "Emit")==0) + return SCE_PASS_EMIT; + + if(strcmp(str, "Diffuse")==0) + return SCE_PASS_DIFFUSE; + + if(strcmp(str, "Spec")==0) + return SCE_PASS_SPEC; + + if(strcmp(str, "Shadow")==0) + return SCE_PASS_SHADOW; + + if(strcmp(str, "AO")==0) + return SCE_PASS_AO; + + if(strcmp(str, "Env")==0) + return SCE_PASS_ENVIRONMENT; + + if(strcmp(str, "Indirect")==0) + return SCE_PASS_INDIRECT; + + if(strcmp(str, "Reflect")==0) + return SCE_PASS_REFLECT; + + if(strcmp(str, "Refract")==0) + return SCE_PASS_REFRACT; + + if(strcmp(str, "IndexOB")==0) + return SCE_PASS_INDEXOB; + + if(strcmp(str, "IndexMA")==0) + return SCE_PASS_INDEXMA; + + if(strcmp(str, "Mist")==0) + return SCE_PASS_MIST; + + if(strcmp(str, "RayHits")==0) + return SCE_PASS_RAYHITS; + return 0; +} + +/********************************** New **************************************/ + +static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype) +{ + const char *typestr= get_pass_name(passtype, 0); + RenderPass *rpass= MEM_callocN(sizeof(RenderPass), typestr); + int rectsize= rr->rectx*rr->recty*channels; + + BLI_addtail(&rl->passes, rpass); + rpass->passtype= passtype; + rpass->channels= channels; + rpass->rectx= rl->rectx; + rpass->recty= rl->recty; + BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); + + if(rr->exrhandle) { + int a; + for(a=0; a<channels; a++) + IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL); + } + else { + float *rect; + int x; + + rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr); + + if(passtype==SCE_PASS_VECTOR) { + /* initialize to max speed */ + rect= rpass->rect; + for(x= rectsize-1; x>=0; x--) + rect[x]= PASS_VECTOR_MAX; + } + else if(passtype==SCE_PASS_Z) { + rect= rpass->rect; + for(x= rectsize-1; x>=0; x--) + rect[x]= 10e10; + } + } +} + +/* called by main render as well for parts */ +/* will read info from Render *re to define layers */ +/* called in threads */ +/* re->winx,winy is coordinate space of entire image, partrct the part within */ +RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuffers) +{ + RenderResult *rr; + RenderLayer *rl; + SceneRenderLayer *srl; + int rectx, recty, nr; + + rectx= partrct->xmax - partrct->xmin; + recty= partrct->ymax - partrct->ymin; + + if(rectx<=0 || recty<=0) + return NULL; + + rr= MEM_callocN(sizeof(RenderResult), "new render result"); + rr->rectx= rectx; + rr->recty= recty; + rr->renrect.xmin= 0; rr->renrect.xmax= rectx-2*crop; + /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ + rr->crop= crop; + + /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ + rr->tilerect.xmin= partrct->xmin - re->disprect.xmin; + rr->tilerect.xmax= partrct->xmax - re->disprect.xmax; + rr->tilerect.ymin= partrct->ymin - re->disprect.ymin; + rr->tilerect.ymax= partrct->ymax - re->disprect.ymax; + + if(savebuffers) { + rr->exrhandle= IMB_exr_get_handle(); + } + + /* check renderdata for amount of layers */ + for(nr=0, srl= re->r.layers.first; srl; srl= srl->next, nr++) { + + if((re->r.scemode & R_SINGLE_LAYER) && nr!=re->r.actlay) + continue; + if(srl->layflag & SCE_LAY_DISABLE) + continue; + + rl= MEM_callocN(sizeof(RenderLayer), "new render layer"); + BLI_addtail(&rr->layers, rl); + + BLI_strncpy(rl->name, srl->name, sizeof(rl->name)); + rl->lay= srl->lay; + rl->lay_zmask= srl->lay_zmask; + rl->layflag= srl->layflag; + rl->passflag= srl->passflag; // for debugging: srl->passflag|SCE_PASS_RAYHITS; + rl->pass_xor= srl->pass_xor; + rl->light_override= srl->light_override; + rl->mat_override= srl->mat_override; + rl->rectx= rectx; + rl->recty= recty; + + if(rr->exrhandle) { + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL); + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL); + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL); + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL); + } + else + rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba"); + + if(srl->passflag & SCE_PASS_Z) + render_layer_add_pass(rr, rl, 1, SCE_PASS_Z); + if(srl->passflag & SCE_PASS_VECTOR) + render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR); + if(srl->passflag & SCE_PASS_NORMAL) + render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL); + if(srl->passflag & SCE_PASS_UV) + render_layer_add_pass(rr, rl, 3, SCE_PASS_UV); + if(srl->passflag & SCE_PASS_RGBA) + render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA); + if(srl->passflag & SCE_PASS_EMIT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_EMIT); + if(srl->passflag & SCE_PASS_DIFFUSE) + render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE); + if(srl->passflag & SCE_PASS_SPEC) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC); + if(srl->passflag & SCE_PASS_AO) + render_layer_add_pass(rr, rl, 3, SCE_PASS_AO); + if(srl->passflag & SCE_PASS_ENVIRONMENT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_ENVIRONMENT); + if(srl->passflag & SCE_PASS_INDIRECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_INDIRECT); + if(srl->passflag & SCE_PASS_SHADOW) + render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW); + if(srl->passflag & SCE_PASS_REFLECT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT); + if(srl->passflag & SCE_PASS_REFRACT) + render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT); + if(srl->passflag & SCE_PASS_INDEXOB) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB); + if(srl->passflag & SCE_PASS_INDEXMA) + render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXMA); + if(srl->passflag & SCE_PASS_MIST) + render_layer_add_pass(rr, rl, 1, SCE_PASS_MIST); + if(rl->passflag & SCE_PASS_RAYHITS) + render_layer_add_pass(rr, rl, 4, SCE_PASS_RAYHITS); + + } + /* sss, previewrender and envmap don't do layers, so we make a default one */ + if(rr->layers.first==NULL) { + rl= MEM_callocN(sizeof(RenderLayer), "new render layer"); + BLI_addtail(&rr->layers, rl); + + rl->rectx= rectx; + rl->recty= recty; + + /* duplicate code... */ + if(rr->exrhandle) { + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL); + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL); + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL); + IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL); + } + else + rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba"); + + /* note, this has to be in sync with scene.c */ + rl->lay= (1<<20) -1; + rl->layflag= 0x7FFF; /* solid ztra halo strand */ + rl->passflag= SCE_PASS_COMBINED; + + re->r.actlay= 0; + } + + /* border render; calculate offset for use in compositor. compo is centralized coords */ + rr->xof= re->disprect.xmin + (re->disprect.xmax - re->disprect.xmin)/2 - re->winx/2; + rr->yof= re->disprect.ymin + (re->disprect.ymax - re->disprect.ymin)/2 - re->winy/2; + + return rr; +} + +/* allocate osa new results for samples */ +RenderResult *render_result_new_full_sample(Render *re, ListBase *lb, rcti *partrct, int crop, int savebuffers) +{ + int a; + + if(re->osa==0) + return render_result_new(re, partrct, crop, savebuffers); + + for(a=0; a<re->osa; a++) { + RenderResult *rr= render_result_new(re, partrct, crop, savebuffers); + BLI_addtail(lb, rr); + rr->sample_nr= a; + } + + return lb->first; +} + +/* callbacks for render_result_new_from_exr */ +static void *ml_addlayer_cb(void *base, char *str) +{ + RenderResult *rr= base; + RenderLayer *rl; + + rl= MEM_callocN(sizeof(RenderLayer), "new render layer"); + BLI_addtail(&rr->layers, rl); + + BLI_strncpy(rl->name, str, EXR_LAY_MAXNAME); + return rl; +} + +static void ml_addpass_cb(void *UNUSED(base), void *lay, char *str, float *rect, int totchan, char *chan_id) +{ + RenderLayer *rl= lay; + RenderPass *rpass= MEM_callocN(sizeof(RenderPass), "loaded pass"); + int a; + + BLI_addtail(&rl->passes, rpass); + rpass->channels= totchan; + + rpass->passtype= passtype_from_name(str); + if(rpass->passtype==0) printf("unknown pass %s\n", str); + rl->passflag |= rpass->passtype; + + BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME); + /* channel id chars */ + for(a=0; a<totchan; a++) + rpass->chan_id[a]= chan_id[a]; + + rpass->rect= rect; +} + +/* from imbuf, if a handle was returned we convert this to render result */ +RenderResult *render_result_new_from_exr(void *exrhandle, int rectx, int recty) +{ + RenderResult *rr= MEM_callocN(sizeof(RenderResult), "loaded render result"); + RenderLayer *rl; + RenderPass *rpass; + + rr->rectx= rectx; + rr->recty= recty; + + IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb); + + for(rl=rr->layers.first; rl; rl=rl->next) { + rl->rectx= rectx; + rl->recty= recty; + + for(rpass=rl->passes.first; rpass; rpass=rpass->next) { + rpass->rectx= rectx; + rpass->recty= recty; + } + } + + return rr; +} + +/*********************************** Merge ***********************************/ + +static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize) +{ + int y, ofs, copylen, tilex, tiley; + + copylen= tilex= rrpart->rectx; + tiley= rrpart->recty; + + if(rrpart->crop) { /* filters add pixel extra */ + tile+= pixsize*(rrpart->crop + rrpart->crop*tilex); + + copylen= tilex - 2*rrpart->crop; + tiley -= 2*rrpart->crop; + + ofs= (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop); + target+= pixsize*ofs; + } + else { + ofs= (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin); + target+= pixsize*ofs; + } + + copylen *= sizeof(float)*pixsize; + tilex *= pixsize; + ofs= pixsize*rr->rectx; + + for(y=0; y<tiley; y++) { + memcpy(target, tile, copylen); + target+= ofs; + tile+= tilex; + } +} + +/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */ +/* no test happens here if it fits... we also assume layers are in sync */ +/* is used within threads */ +void render_result_merge(RenderResult *rr, RenderResult *rrpart) +{ + RenderLayer *rl, *rlp; + RenderPass *rpass, *rpassp; + + for(rl= rr->layers.first, rlp= rrpart->layers.first; rl && rlp; rl= rl->next, rlp= rlp->next) { + + /* combined */ + if(rl->rectf && rlp->rectf) + do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4); + + /* passes are allocated in sync */ + for(rpass= rl->passes.first, rpassp= rlp->passes.first; rpass && rpassp; rpass= rpass->next, rpassp= rpassp->next) { + do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels); + } + } +} + +/* for passes read from files, these have names stored */ +static char *make_pass_name(RenderPass *rpass, int chan) +{ + static char name[16]; + int len; + + BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME); + len= strlen(name); + name[len]= '.'; + name[len+1]= rpass->chan_id[chan]; + name[len+2]= 0; + + return name; +} + +/* filename already made absolute */ +/* called from within UI, saves both rendered result as a file-read result */ +int RE_WriteRenderResult(ReportList *reports, RenderResult *rr, const char *filename, int compress) +{ + RenderLayer *rl; + RenderPass *rpass; + void *exrhandle= IMB_exr_get_handle(); + int success; + + BLI_make_existing_file(filename); + + /* composite result */ + if(rr->rectf) { + IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4*rr->rectx, rr->rectf); + IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4*rr->rectx, rr->rectf+1); + IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4*rr->rectx, rr->rectf+2); + IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4*rr->rectx, rr->rectf+3); + } + + /* add layers/passes and assign channels */ + for(rl= rr->layers.first; rl; rl= rl->next) { + + /* combined */ + if(rl->rectf) { + int a, xstride= 4; + for(a=0; a<xstride; a++) + IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), + xstride, xstride*rr->rectx, rl->rectf+a); + } + + /* passes are allocated in sync */ + for(rpass= rl->passes.first; rpass; rpass= rpass->next) { + int a, xstride= rpass->channels; + for(a=0; a<xstride; a++) { + if(rpass->passtype) + IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), + xstride, xstride*rr->rectx, rpass->rect+a); + else + IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a), + xstride, xstride*rr->rectx, rpass->rect+a); + } + } + } + + /* when the filename has no permissions, this can fail */ + if(IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress)) { + IMB_exr_write_channels(exrhandle); + success= TRUE; + } + else { + /* TODO, get the error from openexr's exception */ + BKE_report(reports, RPT_ERROR, "Error Writing Render Result, see console"); + success= FALSE; + } + IMB_exr_close(exrhandle); + + return success; +} + +/**************************** Single Layer Rendering *************************/ + +void render_result_single_layer_begin(Render *re) +{ + /* all layers except the active one get temporally pushed away */ + + /* officially pushed result should be NULL... error can happen with do_seq */ + RE_FreeRenderResult(re->pushedresult); + + re->pushedresult= re->result; + re->result= NULL; +} + +/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */ +void render_result_single_layer_end(Render *re) +{ + SceneRenderLayer *srl; + RenderLayer *rlpush; + RenderLayer *rl; + int nr; + + if(re->result==NULL) { + printf("pop render result error; no current result!\n"); + return; + } + + if(!re->pushedresult) + return; + + if(re->pushedresult->rectx==re->result->rectx && re->pushedresult->recty==re->result->recty) { + /* find which layer in re->pushedresult should be replaced */ + rl= re->result->layers.first; + + /* render result should be empty after this */ + BLI_remlink(&re->result->layers, rl); + + /* reconstruct render result layers */ + for(nr=0, srl= re->scene->r.layers.first; srl; srl= srl->next, nr++) { + if(nr==re->r.actlay) + BLI_addtail(&re->result->layers, rl); + else { + rlpush= RE_GetRenderLayer(re->pushedresult, srl->name); + if(rlpush) { + BLI_remlink(&re->pushedresult->layers, rlpush); + BLI_addtail(&re->result->layers, rlpush); + } + } + } + } + + RE_FreeRenderResult(re->pushedresult); + re->pushedresult= NULL; +} + +/************************* EXR Tile File Rendering ***************************/ + +static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart) +{ + RenderLayer *rlp; + RenderPass *rpassp; + int offs, partx, party; + + BLI_lock_thread(LOCK_IMAGE); + + for(rlp= rrpart->layers.first; rlp; rlp= rlp->next) { + + if(rrpart->crop) { /* filters add pixel extra */ + offs= (rrpart->crop + rrpart->crop*rrpart->rectx); + } + else { + offs= 0; + } + + /* combined */ + if(rlp->rectf) { + int a, xstride= 4; + for(a=0; a<xstride; a++) + IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a), + xstride, xstride*rrpart->rectx, rlp->rectf+a + xstride*offs); + } + + /* passes are allocated in sync */ + for(rpassp= rlp->passes.first; rpassp; rpassp= rpassp->next) { + int a, xstride= rpassp->channels; + for(a=0; a<xstride; a++) + IMB_exr_set_channel(rr->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a), + xstride, xstride*rrpart->rectx, rpassp->rect+a + xstride*offs); + } + + } + + party= rrpart->tilerect.ymin + rrpart->crop; + partx= rrpart->tilerect.xmin + rrpart->crop; + IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0); + + BLI_unlock_thread(LOCK_IMAGE); +} + +static void save_empty_result_tiles(Render *re) +{ + RenderPart *pa; + RenderResult *rr; + + for(rr= re->result; rr; rr= rr->next) { + IMB_exrtile_clear_channels(rr->exrhandle); + + for(pa= re->parts.first; pa; pa= pa->next) { + if(pa->ready==0) { + int party= pa->disprect.ymin - re->disprect.ymin + pa->crop; + int partx= pa->disprect.xmin - re->disprect.xmin + pa->crop; + IMB_exrtile_write_channels(rr->exrhandle, partx, party, 0); + } + } + } +} + +/* begin write of exr tile file */ +void render_result_exr_file_begin(Render *re) +{ + RenderResult *rr; + char str[FILE_MAX]; + + for(rr= re->result; rr; rr= rr->next) { + render_result_exr_file_path(re->scene, rr->sample_nr, str); + + printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str); + IMB_exrtile_begin_write(rr->exrhandle, str, 0, rr->rectx, rr->recty, re->partx, re->party); + } +} + +/* end write of exr tile file, read back first sample */ +void render_result_exr_file_end(Render *re) +{ + RenderResult *rr; + + save_empty_result_tiles(re); + + for(rr= re->result; rr; rr= rr->next) { + IMB_exr_close(rr->exrhandle); + rr->exrhandle= NULL; + } + + render_result_free_list(&re->fullresult, re->result); + re->result= NULL; + + render_result_exr_file_read(re, 0); +} + +/* save part into exr file */ +void render_result_exr_file_merge(RenderResult *rr, RenderResult *rrpart) +{ + for(; rr && rrpart; rr= rr->next, rrpart= rrpart->next) + save_render_result_tile(rr, rrpart); +} + +/* path to temporary exr file */ +void render_result_exr_file_path(Scene *scene, int sample, char *filepath) +{ + char di[FILE_MAX], name[FILE_MAXFILE+MAX_ID_NAME+100], fi[FILE_MAXFILE]; + + BLI_strncpy(di, G.main->name, FILE_MAX); + BLI_splitdirstring(di, fi); + + if(sample==0) + BLI_snprintf(name, sizeof(name), "%s_%s.exr", fi, scene->id.name+2); + else + BLI_snprintf(name, sizeof(name), "%s_%s%d.exr", fi, scene->id.name+2, sample); + + BLI_make_file_string("/", filepath, BLI_temporary_dir(), name); +} + +/* only for temp buffer files, makes exact copy of render result */ +int render_result_exr_file_read(Render *re, int sample) +{ + char str[FILE_MAX]; + int success; + + RE_FreeRenderResult(re->result); + re->result= render_result_new(re, &re->disprect, 0, RR_USE_MEM); + + render_result_exr_file_path(re->scene, sample, str); + printf("read exr tmp file: %s\n", str); + + if(render_result_exr_file_read_path(re->result, str)) { + success= TRUE; + } + else { + printf("cannot read: %s\n", str); + success= FALSE; + + } + + return success; +} + +/* called for reading temp files, and for external engines */ +int render_result_exr_file_read_path(RenderResult *rr, const char *filepath) +{ + RenderLayer *rl; + RenderPass *rpass; + void *exrhandle= IMB_exr_get_handle(); + int rectx, recty; + + if(IMB_exr_begin_read(exrhandle, filepath, &rectx, &recty)==0) { + printf("failed being read %s\n", filepath); + IMB_exr_close(exrhandle); + return 0; + } + + if(rr == NULL || rectx!=rr->rectx || recty!=rr->recty) { + if(rr) + printf("error in reading render result: dimensions don't match\n"); + else + printf("error in reading render result: NULL result pointer\n"); + IMB_exr_close(exrhandle); + return 0; + } + + for(rl= rr->layers.first; rl; rl= rl->next) { + /* combined */ + if(rl->rectf) { + int a, xstride= 4; + for(a=0; a<xstride; a++) + IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a), + xstride, xstride*rectx, rl->rectf+a); + } + + /* passes are allocated in sync */ + for(rpass= rl->passes.first; rpass; rpass= rpass->next) { + int a, xstride= rpass->channels; + for(a=0; a<xstride; a++) + IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a), + xstride, xstride*rectx, rpass->rect+a); + + BLI_strncpy(rpass->name, get_pass_name(rpass->passtype, -1), sizeof(rpass->name)); + } + } + + IMB_exr_read_channels(exrhandle); + IMB_exr_close(exrhandle); + + return 1; +} + +/*************************** Combined Pixel Rect *****************************/ + +ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd) +{ + int flags = (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE)? IB_cm_predivide: 0; + ImBuf *ibuf= IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, flags); + + /* if not exists, BKE_write_ibuf makes one */ + ibuf->rect= (unsigned int *)rr->rect32; + ibuf->rect_float= rr->rectf; + ibuf->zbuf_float= rr->rectz; + + /* float factor for random dither, imbuf takes care of it */ + ibuf->dither= rd->dither_intensity; + + /* prepare to gamma correct to sRGB color space */ + if (rd->color_mgt_flag & R_COLOR_MANAGEMENT) { + /* sequence editor can generate 8bpc render buffers */ + if (ibuf->rect) { + ibuf->profile = IB_PROFILE_SRGB; + if (BKE_imtype_valid_depths(rd->im_format.imtype) & (R_IMF_CHAN_DEPTH_12|R_IMF_CHAN_DEPTH_16|R_IMF_CHAN_DEPTH_24|R_IMF_CHAN_DEPTH_32)) + IMB_float_from_rect(ibuf); + } else { + ibuf->profile = IB_PROFILE_LINEAR_RGB; + } + } + + /* color -> greyscale */ + /* editing directly would alter the render view */ + if(rd->im_format.planes == R_IMF_PLANES_BW) { + ImBuf *ibuf_bw= IMB_dupImBuf(ibuf); + IMB_color_to_bw(ibuf_bw); + IMB_freeImBuf(ibuf); + ibuf= ibuf_bw; + } + + return ibuf; +} + +void render_result_rect_from_ibuf(RenderResult *rr, RenderData *rd, ImBuf *ibuf) +{ + if(ibuf->rect_float) { + /* color management: when off ensure rectf is non-lin, since thats what the internal + * render engine delivers */ + int profile_to= (rd->color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; + int profile_from= (ibuf->profile == IB_PROFILE_LINEAR_RGB)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; + int predivide= (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); + + if (!rr->rectf) + rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf"); + + IMB_buffer_float_from_float(rr->rectf, ibuf->rect_float, + 4, profile_to, profile_from, predivide, + rr->rectx, rr->recty, rr->rectx, rr->rectx); + + /* TSK! Since sequence render doesn't free the *rr render result, the old rect32 + can hang around when sequence render has rendered a 32 bits one before */ + if(rr->rect32) { + MEM_freeN(rr->rect32); + rr->rect32= NULL; + } + } + else if(ibuf->rect) { + if (!rr->rect32) + rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect"); + + memcpy(rr->rect32, ibuf->rect, 4*rr->rectx*rr->recty); + + /* Same things as above, old rectf can hang around from previous render. */ + if(rr->rectf) { + MEM_freeN(rr->rectf); + rr->rectf= NULL; + } + } +} + +void render_result_rect_fill_zero(RenderResult *rr) +{ + if (rr->rectf) + memset(rr->rectf, 0, 4*sizeof(float)*rr->rectx*rr->recty); + else if (rr->rect32) + memset(rr->rect32, 0, 4*rr->rectx*rr->recty); + else + rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect"); +} + +void render_result_rect_get_pixels(RenderResult *rr, RenderData *rd, unsigned int *rect, int rectx, int recty) +{ + if(rr->rect32) { + memcpy(rect, rr->rect32, sizeof(int)*rr->rectx*rr->recty); + } + else if(rr->rectf) { + int profile_from= (rd->color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB; + int predivide= (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE); + int dither= 0; + + IMB_buffer_byte_from_float((unsigned char*)rect, rr->rectf, + 4, dither, IB_PROFILE_SRGB, profile_from, predivide, + rr->rectx, rr->recty, rr->rectx, rr->rectx); + } + else + /* else fill with black */ + memset(rect, 0, sizeof(int)*rectx*recty); +} + diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 96f9918891a..630acf3d88a 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -67,6 +67,7 @@ #include "rayintersection.h" #include "rayobject.h" #include "renderpipeline.h" +#include "render_result.h" #include "render_types.h" #include "renderdatabase.h" #include "occlusion.h" diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index 8efe23c38f9..c77a1309743 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -63,6 +63,7 @@ /* local includes */ #include "gammaCorrectionTables.h" #include "pixelblending.h" +#include "render_result.h" #include "render_types.h" #include "renderpipeline.h" #include "renderdatabase.h" |