Render Baking upgrade:
- Now baking itself is threaded too (like for render, max 2 cpus. Moving this to 4 cpus is on todo. Goes twice as fast! - fix: ESC from bake was broken... - other fix: toolbox menus didn't treat sublevel string lengths OK, truncating items like for Group library names.
This commit is contained in:
@@ -85,6 +85,7 @@ A sample loop can look like this (pseudo c);
|
||||
************************************************ */
|
||||
static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int thread_levels= 0; /* threads can be invoked inside threads */
|
||||
|
||||
/* just a max for security reasons */
|
||||
#define RE_MAX_THREAD 8
|
||||
@@ -126,6 +127,7 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
|
||||
}
|
||||
|
||||
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
|
||||
thread_levels++;
|
||||
}
|
||||
|
||||
/* amount of available threads */
|
||||
@@ -194,7 +196,9 @@ void BLI_end_threads(ListBase *threadbase)
|
||||
}
|
||||
BLI_freelistN(threadbase);
|
||||
|
||||
MEM_set_lock_callback(NULL, NULL);
|
||||
thread_levels--;
|
||||
if(thread_levels==0)
|
||||
MEM_set_lock_callback(NULL, NULL);
|
||||
}
|
||||
|
||||
void BLI_lock_thread(int type)
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
#include "PIL_time.h"
|
||||
|
||||
/* own include */
|
||||
#include "rendercore.h"
|
||||
|
||||
@@ -3675,7 +3677,11 @@ typedef struct BakeShade {
|
||||
ShadeInput shi;
|
||||
VlakRen *vlr;
|
||||
|
||||
int rectx, recty, quad, type;
|
||||
ZSpan *zspan;
|
||||
Image *ima;
|
||||
|
||||
int rectx, recty, quad, type, vdone, ready;
|
||||
|
||||
unsigned int *rect;
|
||||
float *rect_float;
|
||||
} BakeShade;
|
||||
@@ -3688,6 +3694,10 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
|
||||
VlakRen *vlr= bs->vlr;
|
||||
float l, *v1, *v2, *v3;
|
||||
|
||||
/* fast threadsafe break test */
|
||||
if(R.test_break())
|
||||
return;
|
||||
|
||||
shi->xs= x;
|
||||
shi->ys= y;
|
||||
|
||||
@@ -3768,39 +3778,84 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
|
||||
}
|
||||
}
|
||||
|
||||
/* already have tested for tface and ima */
|
||||
static void shade_tface(BakeShade *bs, VlakRen *vlr)
|
||||
static int get_next_bake_face(BakeShade *bs)
|
||||
{
|
||||
VlakRen *vlr;
|
||||
static int v= 0, vdone= 0;
|
||||
|
||||
if(bs==NULL) {
|
||||
vlr= NULL;
|
||||
v= vdone= 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BLI_lock_thread(LOCK_CUSTOM1);
|
||||
|
||||
for(; v<R.totvlak; v++) {
|
||||
vlr= RE_findOrAddVlak(&R, v);
|
||||
|
||||
if(vlr->ob->flag & SELECT) {
|
||||
if(vlr->tface && vlr->tface->tpage) {
|
||||
Image *ima= vlr->tface->tpage;
|
||||
float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
|
||||
if(ima->ibuf==NULL)
|
||||
continue;
|
||||
|
||||
if(ima->ibuf->rect==NULL && ima->ibuf->rect_float==NULL)
|
||||
continue;
|
||||
|
||||
/* find the image for the first time? */
|
||||
if(ima->id.flag & LIB_DOIT) {
|
||||
ima->id.flag &= ~LIB_DOIT;
|
||||
|
||||
/* we either fill in float or char, this ensures things go fine */
|
||||
if(ima->ibuf->rect_float)
|
||||
imb_freerectImBuf(ima->ibuf);
|
||||
/* clear image */
|
||||
IMB_rectfill(ima->ibuf, vec);
|
||||
|
||||
/* might be read by UI to set active image for display */
|
||||
R.bakebuf= ima;
|
||||
}
|
||||
|
||||
/* do time cursor */
|
||||
vdone++;
|
||||
if((vdone & 1023)==1)
|
||||
R.timecursor(vdone>>10);
|
||||
|
||||
bs->vlr= vlr;
|
||||
|
||||
bs->vdone++; /* only for error message if nothing was rendered */
|
||||
v++;
|
||||
|
||||
BLI_unlock_thread(LOCK_CUSTOM1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_unlock_thread(LOCK_CUSTOM1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* already have tested for tface and ima and zspan */
|
||||
static void shade_tface(BakeShade *bs)
|
||||
{
|
||||
VlakRen *vlr= bs->vlr;
|
||||
MTFace *tface= vlr->tface;
|
||||
Image *ima= tface->tpage;
|
||||
ZSpan *zspan= (ZSpan *)ima->id.newid;
|
||||
float vec[4][2];
|
||||
int a, i1, i2, i3;
|
||||
|
||||
if(ima->ibuf==NULL)
|
||||
return;
|
||||
/* check valid zspan */
|
||||
if(ima!=bs->ima) {
|
||||
bs->ima= ima;
|
||||
/* note, these calls only free/fill contents of zspan struct, not zspan itself */
|
||||
zbuf_free_span(bs->zspan);
|
||||
zbuf_alloc_span(bs->zspan, ima->ibuf->x, ima->ibuf->y);
|
||||
}
|
||||
|
||||
/* signal we find this image for the first time */
|
||||
if(zspan==NULL) {
|
||||
if(ima->ibuf->rect==NULL && ima->ibuf->rect_float==NULL)
|
||||
return;
|
||||
/* we either fill in float or char, this ensures things go fine */
|
||||
if(ima->ibuf->rect_float)
|
||||
imb_freerectImBuf(ima->ibuf);
|
||||
|
||||
zspan= MEM_mallocN(sizeof(ZSpan), "zspan for bake");
|
||||
zbuf_alloc_span(zspan, ima->ibuf->x, ima->ibuf->y);
|
||||
ima->id.newid= (ID *)zspan;
|
||||
|
||||
/* clear image */
|
||||
memset(vec, 0, sizeof(vec));
|
||||
IMB_rectfill(ima->ibuf, vec[0]);
|
||||
|
||||
/* might be read by UI to set active image for display */
|
||||
R.bakebuf= ima;
|
||||
}
|
||||
|
||||
bs->vlr= vlr;
|
||||
bs->rectx= ima->ibuf->x;
|
||||
bs->recty= ima->ibuf->y;
|
||||
bs->rect= ima->ibuf->rect;
|
||||
@@ -3816,68 +3871,98 @@ static void shade_tface(BakeShade *bs, VlakRen *vlr)
|
||||
/* UV indices have to be corrected for possible quad->tria splits */
|
||||
i1= 0; i2= 1; i3= 2;
|
||||
vlr_set_uv_indices(vlr, &i1, &i2, &i3);
|
||||
zspan_scanconvert(zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
|
||||
zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
|
||||
|
||||
if(vlr->v4) {
|
||||
bs->quad= 1;
|
||||
zspan_scanconvert(zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
|
||||
zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
|
||||
}
|
||||
}
|
||||
|
||||
static void *do_bake_thread(void *bs_v)
|
||||
{
|
||||
BakeShade *bs= bs_v;
|
||||
|
||||
while(get_next_bake_face(bs)) {
|
||||
shade_tface(bs);
|
||||
|
||||
/* fast threadsafe break test */
|
||||
if(R.test_break())
|
||||
break;
|
||||
}
|
||||
bs->ready= 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* using object selection tags, the faces with UV maps get baked */
|
||||
/* render should have been setup */
|
||||
/* returns 0 if nothing was handled */
|
||||
int RE_bake_shade_all_selected(Render *re, int type)
|
||||
{
|
||||
BakeShade handle;
|
||||
BakeShade handles[RE_MAXTHREAD];
|
||||
ListBase threads;
|
||||
Image *ima;
|
||||
VlakRen *vlr= NULL;
|
||||
int v, vdone=0;
|
||||
int a, vdone=0, maxthreads= 1;
|
||||
|
||||
/* initialize static vars */
|
||||
get_next_bake_face(NULL);
|
||||
|
||||
/* baker uses this flag to detect if image was initialized */
|
||||
for(ima= G.main->image.first; ima; ima= ima->id.next)
|
||||
ima->id.flag |= LIB_DOIT;
|
||||
|
||||
/* initialize render global */
|
||||
R= *re;
|
||||
R.bakebuf= NULL;
|
||||
|
||||
/* set defaults in handle */
|
||||
memset(&handle, 0, sizeof(BakeShade));
|
||||
handle.shi.lay= re->scene->lay;
|
||||
handle.type= type;
|
||||
|
||||
/* baker abuses newid for zspans */
|
||||
for(ima= G.main->image.first; ima; ima= ima->id.next)
|
||||
ima->id.newid= NULL;
|
||||
|
||||
for(v=0; v<R.totvlak; v++) {
|
||||
if((v & 255)==0)
|
||||
vlr= R.blovl[v>>8];
|
||||
else vlr++;
|
||||
if(re->r.mode & R_THREADS)
|
||||
maxthreads= RE_MAXTHREAD; /* should become button value too */
|
||||
else maxthreads= 1;
|
||||
|
||||
BLI_init_threads(&threads, do_bake_thread, maxthreads);
|
||||
|
||||
/* get the threads running */
|
||||
for(a=0; a<maxthreads; a++) {
|
||||
/* set defaults in handles */
|
||||
memset(&handles[a], 0, sizeof(BakeShade));
|
||||
handles[a].shi.lay= re->scene->lay;
|
||||
handles[a].type= type;
|
||||
handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake");
|
||||
|
||||
if(vlr->ob->flag & SELECT) {
|
||||
if(vlr->tface && vlr->tface->tpage) {
|
||||
shade_tface(&handle, vlr);
|
||||
vdone++;
|
||||
|
||||
if((vdone & 1023)==1)
|
||||
R.timecursor(vdone>>10);
|
||||
|
||||
if(R.test_break()) break;
|
||||
}
|
||||
}
|
||||
BLI_insert_thread(&threads, &handles[a]);
|
||||
}
|
||||
|
||||
/* free zspans, filter images */
|
||||
/* wait for everything to be done */
|
||||
a= 0;
|
||||
while(a!=maxthreads) {
|
||||
|
||||
PIL_sleep_ms(50);
|
||||
|
||||
for(a=0; a<maxthreads; a++)
|
||||
if(handles[a].ready==0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* filter images */
|
||||
for(ima= G.main->image.first; ima; ima= ima->id.next) {
|
||||
if(ima->id.newid) {
|
||||
|
||||
zbuf_free_span((ZSpan *)ima->id.newid);
|
||||
MEM_freeN(ima->id.newid);
|
||||
ima->id.newid= NULL;
|
||||
if((ima->flag & LIB_DOIT)==0) {
|
||||
|
||||
IMB_filter_extend(ima->ibuf);
|
||||
IMB_filter_extend(ima->ibuf); /* 2nd pixel extra */
|
||||
ima->ibuf->userflags |= IB_BITMAPDIRTY;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate return value */
|
||||
for(a=0; a<maxthreads; a++) {
|
||||
vdone+= handles[a].vdone;
|
||||
|
||||
zbuf_free_span(handles[a].zspan);
|
||||
MEM_freeN(handles[a].zspan);
|
||||
}
|
||||
|
||||
BLI_end_threads(&threads);
|
||||
return vdone;
|
||||
}
|
||||
|
||||
|
||||
@@ -5467,7 +5467,7 @@ void ui_check_but(uiBut *but)
|
||||
}
|
||||
|
||||
if(but->strwidth==0) but->drawstr[0]= 0;
|
||||
else if(but->type==BUTM); // clip string
|
||||
else if(but->type==BUTM || but->type==BLOCK); // no clip string, uiTextBoundsBlock is used (hack!)
|
||||
else {
|
||||
|
||||
/* calc but->ofs, to draw the string shorter if too long */
|
||||
|
||||
@@ -807,6 +807,12 @@ EditVert *editmesh_get_x_mirror_vert(Object *ob, float *co)
|
||||
|
||||
/* ****************** render BAKING ********************** */
|
||||
|
||||
/* threaded break test */
|
||||
static volatile int g_break= 0;
|
||||
static int thread_break(void)
|
||||
{
|
||||
return g_break;
|
||||
}
|
||||
|
||||
static ScrArea *biggest_image_area(void)
|
||||
{
|
||||
@@ -849,8 +855,10 @@ void objects_bake_render(void)
|
||||
event= pupmenu("Bake Selected Meshes %t|Full Render %x1|Ambient Occlusion %x2|Normals %x3|Texture Only %x4");
|
||||
if(event>0) {
|
||||
Render *re= RE_NewRender("_Bake View_");
|
||||
ScrArea *area;
|
||||
int tot;
|
||||
ScrArea *area= biggest_image_area();
|
||||
ListBase threads;
|
||||
BakeRender bkr;
|
||||
int timer, tot;
|
||||
|
||||
if(event==1) event= RE_BAKE_ALL;
|
||||
else if(event==2) event= RE_BAKE_AO;
|
||||
@@ -867,42 +875,38 @@ void objects_bake_render(void)
|
||||
|
||||
waitcursor(1);
|
||||
RE_timecursor_cb(re, set_timecursor);
|
||||
RE_test_break_cb(re, blender_test_break);
|
||||
RE_test_break_cb(re, thread_break);
|
||||
g_break= 0;
|
||||
G.afbreek= 0; /* blender_test_break uses this global */
|
||||
|
||||
RE_Database_Baking(re, G.scene, event);
|
||||
|
||||
/* live updates, threaded */
|
||||
area= biggest_image_area();
|
||||
if(area) {
|
||||
ListBase threads;
|
||||
BakeRender bkr;
|
||||
int timer;
|
||||
/* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */
|
||||
|
||||
BLI_init_threads(&threads, do_bake_render, 1);
|
||||
bkr.re= re;
|
||||
bkr.event= event;
|
||||
bkr.ready= 0;
|
||||
BLI_insert_thread(&threads, &bkr);
|
||||
|
||||
while(bkr.ready==0) {
|
||||
PIL_sleep_ms(50);
|
||||
if(bkr.ready)
|
||||
break;
|
||||
|
||||
BLI_init_threads(&threads, do_bake_render, 1);
|
||||
bkr.re= re;
|
||||
bkr.event= event;
|
||||
bkr.ready= 0;
|
||||
BLI_insert_thread(&threads, &bkr);
|
||||
g_break= blender_test_break();
|
||||
|
||||
while(bkr.ready==0) {
|
||||
PIL_sleep_ms(50);
|
||||
if(bkr.ready)
|
||||
break;
|
||||
timer++;
|
||||
if(timer==20) {
|
||||
Image *ima= RE_bake_shade_get_image();
|
||||
if(ima) ((SpaceImage *)area->spacedata.first)->image= ima;
|
||||
scrarea_do_windraw(area);
|
||||
myswapbuffers();
|
||||
timer= 0;
|
||||
}
|
||||
timer++;
|
||||
if(timer==20) {
|
||||
Image *ima= RE_bake_shade_get_image();
|
||||
if(ima) ((SpaceImage *)area->spacedata.first)->image= ima;
|
||||
scrarea_do_windraw(area);
|
||||
myswapbuffers();
|
||||
timer= 0;
|
||||
}
|
||||
BLI_end_threads(&threads);
|
||||
tot= bkr.tot;
|
||||
}
|
||||
else /* no thread bake */
|
||||
tot= RE_bake_shade_all_selected(re, event);
|
||||
BLI_end_threads(&threads);
|
||||
tot= bkr.tot;
|
||||
|
||||
RE_Database_Free(re);
|
||||
waitcursor(0);
|
||||
|
||||
@@ -1821,7 +1821,14 @@ static TBitem *create_group_all_sublevels(ListBase *storage)
|
||||
/* first all levels. libs with groups are not tagged */
|
||||
for(lib= G.main->library.first; lib; lib= lib->id.next) {
|
||||
if(!(lib->id.flag & LIB_DOIT)) {
|
||||
gm->name= BLI_last_slash(lib->filename)+1;
|
||||
char *str;
|
||||
/* do some tricks to get .blend file name without extension */
|
||||
link= MEM_callocN(sizeof(Link) + 128, "string");
|
||||
BLI_addtail(storage, link);
|
||||
str= (char *)(link+1);
|
||||
BLI_strncpy(str, BLI_last_slash(lib->filename)+1, 128);
|
||||
if(strlen(str)>6) str[strlen(str)-6]= 0;
|
||||
gm->name= str;
|
||||
gm->retval= -1;
|
||||
gm->poin= create_group_sublevel(storage, lib);
|
||||
gm++;
|
||||
|
||||
Reference in New Issue
Block a user