#include "BLI_arithb.h"
#include "BLI_blenlib.h"
+#include "BLI_threads.h"
#include "PIL_time.h"
#include "IMB_imbuf.h"
#include "zbuf.h"
#include "SDL_thread.h"
+#include "SDL_mutex.h"
/* render flow
/* ********* alloc and free ******** */
-static SDL_mutex *malloc_lock= NULL;
+SDL_mutex *malloc_lock= NULL;
void *RE_mallocN(int len, char *name)
{
}
if(res->rect32)
- MEM_freeN(res->rect32);
+ RE_freeN(res->rect32);
+ if(res->rectz)
+ RE_freeN(res->rectz);
if(res->rectf)
- MEM_freeN(res->rectf);
+ RE_freeN(res->rectf);
RE_freeN(res);
}
{
RenderResult *rr;
RenderLayer *rl;
+ SceneRenderLayer *srl;
int rectx, recty;
rectx= partrct->xmax - partrct->xmin;
rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
- /* check renderdata for amount of layers */
- /* for now just one */
- rl= RE_callocN(sizeof(RenderLayer), "new render layer");
- BLI_addtail(&rr->layers, rl);
+ /* copy, so display callbacks can find out too */
+ rr->actlay= re->r.actlay;
- rl->rectf= RE_callocN(rectx*recty*sizeof(float)*4, "layer float rgba");
- rl->rectz= RE_callocN(rectx*recty*sizeof(float), "layer float Z");
+ /* check renderdata for amount of layers */
+ for(srl= re->r.layers.first; srl; srl= srl->next) {
+ rl= RE_callocN(sizeof(RenderLayer), "new render layer");
+ BLI_addtail(&rr->layers, rl);
+
+ strcpy(rl->name, srl->name);
+ rl->lay= srl->lay;
+ rl->layflag= srl->layflag;
+ rl->passflag= srl->passflag;
+
+ rl->rectf= RE_callocN(rectx*recty*sizeof(float)*4, "layer float rgba");
+ if(srl->passflag & SCE_PASS_Z)
+ rl->rectz= RE_callocN(rectx*recty*sizeof(float), "layer float Z");
+
+ }
+ /* previewrender and envmap don't do layers, so we make a default one */
+ if(rr->layers.first==NULL) {
+ rl= RE_callocN(sizeof(RenderLayer), "new render layer");
+ BLI_addtail(&rr->layers, rl);
+
+ rl->rectf= RE_callocN(rectx*recty*sizeof(float)*4, "prev/env float rgba");
+ rl->rectz= RE_callocN(rectx*recty*sizeof(float), "prev/env float Z");
+
+ /* 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|SCE_PASS_Z;
+
+ }
return rr;
}
/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
-/* no test happens here if it fits... */
+/* no test happens here if it fits... we also assume layers are in sync */
/* is used within threads */
static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
{
- RenderLayer *rl= rr->layers.first;
- RenderLayer *rlp= rrpart->layers.first;
+ RenderLayer *rl, *rlp;
float *rf, *rfp;
- int *rz=NULL, *rzp;
+ float *rz, *rzp;
int y, height, len, copylen;
- if(rlp->rectf==NULL) return;
- if(rl->rectf==NULL) return;
-
- rzp= NULL; //rlp->rectz;
- rfp= rlp->rectf;
-
- copylen=len= rrpart->rectx;
- height= rrpart->recty;
-
- if(rrpart->crop) { /* filters add pixel extra */
-
- if(rzp) rzp+= rrpart->crop + rrpart->crop*len;
- if(rfp) rfp+= 4*(rrpart->crop + rrpart->crop*len);
+ for(rl= rr->layers.first, rlp= rrpart->layers.first; rl && rlp; rl= rl->next, rlp= rlp->next) {
- copylen= len-2*rrpart->crop;
- height -= 2*rrpart->crop;
-
- // rz= re->rectz+ (pa->miny + rrpart->crop)*rr->rectx+ (pa->minx+rrpart->crop);
- rf= rl->rectf+ ( (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop) )*4;
- }
- else {
- // rz= re->rectz + (pa->disprect.ymin*rr->rectx + pa->disprect.xmin);
- rf= rl->rectf+ (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin)*4;
- }
+ /* first combined and z pass */
+ if(rl->rectf && rlp->rectf) {
+ int ofs;
+
+ rzp= rlp->rectz;
+ rfp= rlp->rectf;
+
+ copylen=len= rrpart->rectx;
+ height= rrpart->recty;
+
+ if(rrpart->crop) { /* filters add pixel extra */
+
+ if(rzp) rzp+= rrpart->crop + rrpart->crop*len;
+ if(rfp) rfp+= 4*(rrpart->crop + rrpart->crop*len);
+
+ copylen= len-2*rrpart->crop;
+ height -= 2*rrpart->crop;
+
+ ofs= (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop);
+ rz= rl->rectz+ ofs;
+ rf= rl->rectf+ 4*ofs;
+ }
+ else {
+ ofs= (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin);
+ rz= rl->rectz+ ofs;
+ rf= rl->rectf+ 4*ofs;
+ }
- for(y=0; y<height; y++) {
- if(rzp) {
- memcpy(rz, rzp, 4*copylen);
- rz+= rr->rectx;
- rzp+= len;
- }
- if(rfp) {
- memcpy(rf, rfp, 16*copylen);
- rf+= 4*rr->rectx;
- rfp+= 4*len;
+ for(y=0; y<height; y++) {
+ if(rzp) {
+ memcpy(rz, rzp, 4*copylen);
+ rz+= rr->rectx;
+ rzp+= len;
+ }
+ if(rfp) {
+ memcpy(rf, rfp, 16*copylen);
+ rf+= 4*rr->rectx;
+ rfp+= 4*len;
+ }
+ }
}
}
}
void RE_GetResultImage(Render *re, RenderResult *rr)
{
memset(rr, sizeof(RenderResult), 0);
-
+
if(re && re->result) {
RenderLayer *rl;
rr->rectx= re->result->rectx;
rr->recty= re->result->recty;
+
rr->rectf= re->result->rectf;
rr->rectz= re->result->rectz;
rr->rect32= re->result->rect32;
- /* will become 'active' call */
- rl= re->result->layers.first;
- if(rr->rectf==NULL)
- rr->rectf= rl->rectf;
- if(rr->rectz==NULL)
- rr->rectz= rl->rectz;
+ /* active layer */
+ rl= BLI_findlink(&re->result->layers, re->r.actlay);
+ if(rl) {
+ if(rr->rectf==NULL)
+ rr->rectf= rl->rectf;
+ if(rr->rectz==NULL)
+ rr->rectz= rl->rectz;
+ }
}
}
}
-/* ********** basic thread control API ************ */
-
-#define RE_MAX_THREAD 4
-
-typedef struct ThreadSlot {
- RenderPart *part;
- int avail;
-} ThreadSlot;
-
-static ThreadSlot threadslots[RE_MAX_THREAD];
-
-static void init_threadslots(int tot)
-{
- int a;
-
- if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
- else if(tot<1) tot= 1;
-
- for(a=0; a< RE_MAX_THREAD; a++) {
- threadslots[a].part= NULL;
- if(a<tot)
- threadslots[a].avail= 1;
- else
- threadslots[a].avail= 0;
- }
-}
-
-static int available_threadslots(void)
-{
- int a, counter=0;
- for(a=0; a< RE_MAX_THREAD; a++)
- if(threadslots[a].avail)
- counter++;
- return counter;
-}
-
-static void insert_threadslot(RenderPart *pa)
-{
- int a;
- for(a=0; a< RE_MAX_THREAD; a++) {
- if(threadslots[a].avail) {
- threadslots[a].avail= 0;
- threadslots[a].part= pa;
- pa->thread= a;
- break;
- }
- }
-}
-
-static void remove_threadslot(RenderPart *pa)
-{
- int a;
- for(a=0; a< RE_MAX_THREAD; a++) {
- if(threadslots[a].part==pa) {
- threadslots[a].avail= 1;
- threadslots[a].part= NULL;
- }
- }
-}
-
-/* ********** basic thread control API ************ */
+/* *************************************** */
static int do_part_thread(void *pa_v)
{
}
pa->ready= 1;
- remove_threadslot(pa);
return 0;
}
static void threaded_tile_processor(Render *re)
{
+ ListBase threads;
RenderPart *pa;
int maxthreads=2, rendering=1, counter= 1;
return;
initparts(re);
- init_threadslots(maxthreads);
+ BLI_init_threads(&threads, do_part_thread, maxthreads);
/* assuming no new data gets added to dbase... */
R= *re;
while(rendering) {
/* I noted that test_break() in a thread doesn't make ghost send ESC */
- if(available_threadslots() && !re->test_break()) {
+ if(BLI_available_threads(&threads) && !re->test_break()) {
pa= find_nicest_part(re);
if(pa) {
- insert_threadslot(pa);
- pa->nr= counter++; /* only for stats */
- SDL_CreateThread(do_part_thread, pa);
+ pa->nr= counter++; /* for nicest part, and for stats */
+ pa->thread= BLI_available_thread_index(&threads); /* sample index */
+ BLI_insert_thread(&threads, pa);
}
}
else
for(pa= re->parts.first; pa; pa= pa->next) {
if(pa->ready) {
if(pa->result) {
+ BLI_remove_thread(&threads, pa);
re->display_draw(pa->result, NULL);
free_render_result(pa->result);
pa->result= NULL;
}
/* on break, wait for all slots to get freed */
- if(re->test_break() && available_threadslots()==maxthreads)
+ if(re->test_break() && BLI_available_threads(&threads)==maxthreads)
rendering= 0;
}
if(malloc_lock) SDL_DestroyMutex(malloc_lock); malloc_lock= NULL;
+ BLI_end_threads(&threads);
freeparts(re);
}
static void do_render_final(Render *re, Scene *scene)
{
+ /* we set start time here, for main Blender loops */
+ re->i.starttime= PIL_check_seconds_timer();
+
if(re->r.scemode & R_DOSEQ) {
re->result->rect32= MEM_callocN(sizeof(int)*re->rectx*re->recty, "rectot");
if(!re->test_break())
/* first check if theres nodetree with render result */
int do_render= ntreeCompositNeedsRender(scene->nodetree);
/* but.. do we use nodes? */
- if(scene->use_nodes==NULL) do_render= 1;
+ if(scene->use_nodes==0) do_render= 1;
re->scene= scene;
else
render_one_frame(re);
}
+
+ ntreeCompositTagRender(scene->nodetree);
+ ntreeCompositTagAnimated(scene->nodetree);
+
if(re->r.scemode & R_DOCOMP)
ntreeCompositExecTree(scene->nodetree, &re->r, 0);
}
if(!render_initialize_from_scene(re, scene))
return;
+ /* confusing... scene->r or re->r? make a decision once! */
if(BKE_imtype_is_movie(scene->r.imtype))
- mh->start_movie(&G.scene->r, re->rectx, re->recty);
+ mh->start_movie(&scene->r, re->rectx, re->recty);
- for(scene->r.cfra= sfra; scene->r.cfra<=efra; G.scene->r.cfra++) {
+ for(scene->r.cfra= sfra; scene->r.cfra<=efra; scene->r.cfra++) {
re->r.cfra= scene->r.cfra; /* weak.... */
do_render_final(re, scene);
/* write movie or image */
if(BKE_imtype_is_movie(scene->r.imtype)) {
+ /* note; the way it gets 32 bits rects is weak... */
+ int dofree=0;
if(rres.rect32==NULL) {
rres.rect32= MEM_mallocN(sizeof(int)*rres.rectx*rres.recty, "temp 32 bits rect");
+ dofree= 1;
}
RE_ResultGet32(re, rres.rect32);
mh->append_movie(scene->r.cfra, rres.rect32, rres.rectx, rres.recty);
+ if(dofree) MEM_freeN(rres.rect32);
printf("Append frame %d", scene->r.cfra);
}
else {