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:
2006-11-28 10:16:24 +00:00
parent 859dc7918b
commit c1258980a4
5 changed files with 195 additions and 95 deletions

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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++;