Progress indicators for threaded jobs

Now, rather than the bit-too-alarming stop sign, threaded wmJobs 
display a progress indicator in the header. This is an optional feature
for each job type and still uses the same hardcoded ui template
(could use further work here...).

Currently implemented for:
Render - parts completed, then nodes comped
Compositor - nodes comped
Fluid Sim - frames simulated
Texture Bake - faces baked

Example: http://mke3.net/blender/devel/2.5/progress.mov
This commit is contained in:
2010-05-27 08:22:16 +00:00
parent ec70356424
commit 6e92ddf8b3
31 changed files with 6879 additions and 6661 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View File

@@ -554,6 +554,10 @@ class USERPREF_PT_theme(bpy.types.Panel):
ui = theme.user_interface.wcol_scroll
col.label(text="Scroll Bar:")
ui_items_general(col, ui)
ui = theme.user_interface.wcol_progress
col.label(text="Progress Bar:")
ui_items_general(col, ui)
ui = theme.user_interface.wcol_list_item
col.label(text="List Item:")

View File

@@ -2434,7 +2434,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
bNode *node;
ListBase threads;
ThreadData thdata;
int totnode, rendering= 1;
int totnode, curnode, rendering= 1;
if(ntree==NULL) return;
@@ -2455,7 +2455,7 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
BLI_srandom(rd->cfra);
/* sets need_exec tags in nodes */
totnode= setExecutableNodes(ntree, &thdata);
curnode = totnode= setExecutableNodes(ntree, &thdata);
BLI_init_threads(&threads, exec_composite_node, rd->threads);
@@ -2465,14 +2465,14 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
node= getExecutableNode(ntree);
if(node) {
if(ntree->timecursor)
ntree->timecursor(ntree->tch, totnode);
if(ntree->progress)
ntree->progress(ntree->prh, (1.0 - curnode/(float)totnode));
if(ntree->stats_draw) {
char str[64];
sprintf(str, "Compositing %d %s", totnode, node->name);
sprintf(str, "Compositing %d %s", curnode, node->name);
ntree->stats_draw(ntree->sdh, str);
}
totnode--;
curnode--;
node->threaddata = &thdata;
node->exec= NODE_PROCESSING;

View File

@@ -2082,7 +2082,7 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
ntree->init= 0; /* to set callbacks and force setting types */
ntree->owntype= NULL;
ntree->timecursor= NULL;
ntree->progress= NULL;
ntree->adt= newdataadr(fd, ntree->adt);
direct_link_animdata(fd, ntree->adt);

File diff suppressed because it is too large Load Diff

View File

@@ -220,6 +220,7 @@ typedef struct uiLayout uiLayout;
#define HISTOGRAM (47<<9)
#define WAVEFORM (48<<9)
#define VECTORSCOPE (49<<9)
#define PROGRESSBAR (50<<9)
#define BUTTYPE (63<<9)
@@ -247,8 +248,9 @@ void uiDrawMenuBox(float minx, float miny, float maxx, float maxy, short flag, s
void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
/* state for scrolldrawing */
#define UI_SCROLL_PRESSED 1
#define UI_SCROLL_ARROWS 2
#define UI_SCROLL_PRESSED 1
#define UI_SCROLL_ARROWS 2
#define UI_SCROLL_NO_OUTLINE 4
void uiWidgetScrollDraw(struct uiWidgetColors *wcol, struct rcti *rect, struct rcti *slider, int state);
/* Menu Callbacks */

View File

@@ -2376,7 +2376,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short
}
}
if((block->flag & UI_BLOCK_LOOP) || ELEM7(but->type, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM, SEARCH_MENU))
if((block->flag & UI_BLOCK_LOOP) || ELEM8(but->type, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR))
but->flag |= (UI_TEXT_LEFT|UI_ICON_LEFT);
else if(but->type==BUT_TOGDUAL)
but->flag |= UI_ICON_LEFT;

View File

@@ -184,11 +184,16 @@ static void button_timers_tooltip_remove(bContext *C, uiBut *but);
/* ******************** menu navigation helpers ************** */
static int ui_but_editable(uiBut *but)
{
return ELEM5(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX, PROGRESSBAR);
}
static uiBut *ui_but_prev(uiBut *but)
{
while(but->prev) {
but= but->prev;
if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
if(!ui_but_editable(but)) return but;
}
return NULL;
}
@@ -197,7 +202,7 @@ static uiBut *ui_but_next(uiBut *but)
{
while(but->next) {
but= but->next;
if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
if(!ui_but_editable(but)) return but;
}
return NULL;
}
@@ -208,7 +213,7 @@ static uiBut *ui_but_first(uiBlock *block)
but= block->buttons.first;
while(but) {
if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
if(!ui_but_editable(but)) return but;
but= but->next;
}
return NULL;
@@ -220,7 +225,7 @@ static uiBut *ui_but_last(uiBlock *block)
but= block->buttons.last;
while(but) {
if(!ELEM4(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX)) return but;
if(!ui_but_editable(but)) return but;
but= but->prev;
}
return NULL;
@@ -4313,6 +4318,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, wmEvent *event)
case ROW:
case LISTROW:
case BUT_IMAGE:
case PROGRESSBAR:
retval= ui_do_but_EXIT(C, but, data, event);
break;
case HISTOGRAM:

View File

@@ -87,7 +87,8 @@ typedef enum {
UI_WTYPE_NORMAL,
UI_WTYPE_BOX,
UI_WTYPE_SCROLL,
UI_WTYPE_LISTITEM
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
} uiWidgetTypeEnum;

View File

@@ -2423,24 +2423,40 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
wmWindowManager *wm= CTX_wm_manager(C);
ScrArea *sa= CTX_wm_area(C);
uiBlock *block;
void *owner;
int handle_event;
block= uiLayoutGetBlock(layout);
uiBlockSetCurLayout(block, layout);
uiBlockSetHandleFunc(block, do_running_jobs, NULL);
if(sa->spacetype==SPACE_NODE) {
if(WM_jobs_test(wm, sa))
uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Composite", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop composite");
owner = sa;
handle_event= B_STOPCOMPO;
} else {
owner = scene;
handle_event= B_STOPRENDER;
}
else {
if(WM_jobs_test(wm, scene))
uiDefIconTextBut(block, BUT, B_STOPRENDER, ICON_CANCEL, "Render", 0,0,75,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop rendering");
if(WM_jobs_test(wm, screen))
uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
if(screen->animtimer)
uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, "Anim Player", 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
if(WM_jobs_test(wm, owner)) {
uiLayout *abs;
abs = uiLayoutAbsolute(layout, 0);
uiDefIconBut(block, BUT, handle_event, ICON_PANEL_CLOSE,
0, UI_UNIT_Y*0.1, UI_UNIT_X*0.8, UI_UNIT_Y*0.8, NULL, 0.0f, 0.0f, 0, 0, "Stop this job");
uiDefBut(block, PROGRESSBAR, 0, WM_jobs_name(wm, owner),
UI_UNIT_X, 0, 100, UI_UNIT_Y, NULL, 0.0f, 0.0f, WM_jobs_progress(wm, owner), 0, "Progress");
uiLayoutRow(layout, 0);
}
if(WM_jobs_test(wm, screen))
uiDefIconTextBut(block, BUT, B_STOPCAST, ICON_CANCEL, "Capture", 0,0,85,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop screencast");
if(screen->animtimer)
uiDefIconTextBut(block, BUT, B_STOPANIM, ICON_CANCEL, "Anim Player", 0,0,100,UI_UNIT_Y, NULL, 0.0f, 0.0f, 0, 0, "Stop animation playback");
uiItemS(layout);
}
/************************* Reports for Last Operator Template **************************/

View File

@@ -1276,6 +1276,19 @@ static struct uiWidgetColors wcol_scroll= {
5, -5
};
static struct uiWidgetColors wcol_progress= {
{0, 0, 0, 255},
{190, 190, 190, 255},
{100, 100, 100, 180},
{68, 68, 68, 255},
{0, 0, 0, 255},
{255, 255, 255, 255},
0,
0, 0
};
static struct uiWidgetColors wcol_list_item= {
{0, 0, 0, 255},
{0, 0, 0, 0},
@@ -1322,6 +1335,7 @@ void ui_widget_color_init(ThemeUI *tui)
tui->wcol_box= wcol_box;
tui->wcol_scroll= wcol_scroll;
tui->wcol_list_item= wcol_list_item;
tui->wcol_progress= wcol_progress;
tui->wcol_state= wcol_state;
}
@@ -1954,6 +1968,7 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int stat
uiWidgetBase wtb;
float rad;
int horizontal;
short outline=0;
widget_init(&wtb);
@@ -1995,6 +2010,10 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int stat
/* draw */
wtb.emboss= 0; /* only emboss once */
/* exception for progress bar */
if (state & UI_SCROLL_NO_OUTLINE)
SWAP(short, outline, wtb.outline);
round_box_edges(&wtb, 15, slider, rad);
if(state & UI_SCROLL_ARROWS) {
@@ -2013,6 +2032,9 @@ void uiWidgetScrollDraw(uiWidgetColors *wcol, rcti *rect, rcti *slider, int stat
}
}
widgetbase_draw(&wtb, wcol);
if (state & UI_SCROLL_NO_OUTLINE)
SWAP(short, outline, wtb.outline);
}
}
@@ -2077,9 +2099,35 @@ static void widget_scroll(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
uiWidgetScrollDraw(wcol, rect, &rect1, state);
}
static void widget_progressbar(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
rcti rect_prog = *rect, rect_bar = *rect;
float value = but->a1;
float w, min;
/* make the progress bar a proportion of the original height */
/* hardcoded 4px high for now */
rect_prog.ymax = rect_prog.ymin + 4;
rect_bar.ymax = rect_bar.ymin + 4;
w = value * (rect_prog.xmax - rect_prog.xmin);
/* ensure minimium size */
min= rect_prog.ymax - rect_prog.ymin;
w = MAX2(w, min);
rect_bar.xmax = rect_bar.xmin + w;
uiWidgetScrollDraw(wcol, &rect_prog, &rect_bar, UI_SCROLL_NO_OUTLINE);
/* raise text a bit */
rect->ymin += 6;
rect->xmin -= 6;
}
static void widget_link(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
if(but->flag & UI_SELECT) {
rcti rectlink;
@@ -2094,7 +2142,6 @@ static void widget_link(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state,
}
}
static void widget_numslider(uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
uiWidgetBase wtb, wtb1;
@@ -2541,6 +2588,11 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.wcol_theme= &btheme->tui.wcol_list_item;
wt.draw= widget_list_itembut;
break;
case UI_WTYPE_PROGRESSBAR:
wt.wcol_theme= &btheme->tui.wcol_progress;
wt.custom= widget_progressbar;
break;
}
return &wt;
@@ -2756,6 +2808,11 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case BUT_CURVE:
ui_draw_but_CURVE(ar, but, &tui->wcol_regular, rect);
break;
case PROGRESSBAR:
wt= widget_type(UI_WTYPE_PROGRESSBAR);
fstyle= &style->widgetlabel;
break;
case SCROLL:
wt= widget_type(UI_WTYPE_SCROLL);

View File

@@ -1463,6 +1463,28 @@ void init_userdef_do_versions(void)
SETCOL(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255);
}
}
if (G.main->versionfile <= 252 || (G.main->versionfile == 252 && G.main->subversionfile < 5)) {
bTheme *btheme;
/* interface_widgets.c */
struct uiWidgetColors wcol_progress= {
{0, 0, 0, 255},
{190, 190, 190, 255},
{100, 100, 100, 180},
{68, 68, 68, 255},
{0, 0, 0, 255},
{255, 255, 255, 255},
0,
5, -5
};
for(btheme= U.themes.first; btheme; btheme= btheme->next) {
/* init progress bar theme */
btheme->tui.wcol_progress= wcol_progress;
}
}
/* GL Texture Garbage Collection (variable abused above!) */
if (U.textimeout == 0) {

View File

@@ -102,7 +102,8 @@ typedef struct BakeRender {
short *stop;
short *do_update;
float *progress;
ListBase threads;
/* backup */
@@ -185,19 +186,20 @@ static void *do_bake_render(void *bake_v)
{
BakeRender *bkr= bake_v;
bkr->tot= RE_bake_shade_all_selected(bkr->re, bkr->scene->r.bake_mode, bkr->actob, NULL);
bkr->tot= RE_bake_shade_all_selected(bkr->re, bkr->scene->r.bake_mode, bkr->actob, NULL, bkr->progress);
bkr->ready= 1;
return NULL;
}
static void bake_startjob(void *bkv, short *stop, short *do_update)
static void bake_startjob(void *bkv, short *stop, short *do_update, float *progress)
{
BakeRender *bkr= bkv;
Scene *scene= bkr->scene;
bkr->stop= stop;
bkr->do_update= do_update;
bkr->progress= progress;
RE_test_break_cb(bkr->re, NULL, thread_break);
G.afbreek= 0; /* blender_test_break uses this global */
@@ -205,7 +207,7 @@ static void bake_startjob(void *bkv, short *stop, short *do_update)
RE_Database_Baking(bkr->re, scene, scene->lay, scene->r.bake_mode, bkr->actob);
/* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */
bkr->tot= RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update);
bkr->tot= RE_bake_shade_all_selected(bkr->re, scene->r.bake_mode, bkr->actob, bkr->do_update, bkr->progress);
}
static void bake_update(void *bkv)
@@ -260,7 +262,7 @@ static int objects_bake_render_invoke(bContext *C, wmOperator *op, wmEvent *_eve
bkr->reports= op->reports;
/* setup job */
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
WM_jobs_customdata(steve, bkr, bake_freejob);
WM_jobs_timer(steve, 0.2, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */
WM_jobs_callbacks(steve, bake_startjob, NULL, bake_update, NULL);

View File

@@ -708,7 +708,7 @@ typedef struct FluidBakeJob {
/* from wmJob */
void *owner;
short *stop, *do_update;
float *progress;
int current_frame;
elbeemSimulationSettings *settings;
} FluidBakeJob;
@@ -732,19 +732,21 @@ static int fluidbake_breakjob(void *customdata)
}
/* called by fluidbake, wmJob sends notifier */
static void fluidbake_updatejob(void *customdata, char *str)
static void fluidbake_updatejob(void *customdata, float progress)
{
FluidBakeJob *fb= customdata;
*(fb->do_update)= 1;
*(fb->progress)= progress;
}
static void fluidbake_startjob(void *customdata, short *stop, short *do_update)
static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
FluidBakeJob *fb= customdata;
fb->stop= stop;
fb->do_update = do_update;
fb->progress = progress;
G.afbreek= 0; /* XXX shared with render - replace with job 'stop' switch */
@@ -753,14 +755,24 @@ static void fluidbake_startjob(void *customdata, short *stop, short *do_update)
*stop = 0;
}
static void fluidbake_endjob(void *customdata)
{
FluidBakeJob *fb= customdata;
if (fb->settings) {
MEM_freeN(fb->settings);
fb->settings = NULL;
}
}
int runSimulationCallback(void *data, int status, int frame) {
FluidBakeJob *fb = (FluidBakeJob *)data;
//elbeemSimulationSettings *settings = fb->settings;
elbeemSimulationSettings *settings = fb->settings;
//printf("elbeem blender cb s%d, f%d, domainid:%d \n", status,frame, settings->domainId ); // DEBUG
if (status == FLUIDSIM_CBSTATUS_NEWFRAME)
fluidbake_updatejob(fb, "");
if (status == FLUIDSIM_CBSTATUS_NEWFRAME) {
fluidbake_updatejob(fb, frame / (float)settings->noOfFrames);
}
if (fluidbake_breakjob(fb)) {
return FLUIDSIM_CBRET_ABORT;
@@ -799,9 +811,9 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
wmJob *steve;
FluidBakeJob *fb;
elbeemSimulationSettings fsset;
elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings");
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, 0);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Sim", WM_JOB_PROGRESS);
fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job");
if(getenv(strEnvName)) {
@@ -902,7 +914,7 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
for(i=2; i<=allchannelSize; i++) {
timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0];
}
} else {
fsset->} else {
for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; }
}
@@ -936,76 +948,77 @@ int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain)
}
/* ******** export domain to elbeem ******** */
elbeemResetSettings(&fsset);
fsset.version = 1;
elbeemResetSettings(fsset);
fsset->version = 1;
// setup global settings
copy_v3_v3(fsset.geoStart, domainSettings->bbStart);
copy_v3_v3(fsset.geoSize, domainSettings->bbSize);
copy_v3_v3(fsset->geoStart, domainSettings->bbStart);
copy_v3_v3(fsset->geoSize, domainSettings->bbSize);
// simulate with 50^3
fsset.resolutionxyz = (int)domainSettings->resolutionxyz;
fsset.previewresxyz = (int)domainSettings->previewresxyz;
fsset->resolutionxyz = (int)domainSettings->resolutionxyz;
fsset->previewresxyz = (int)domainSettings->previewresxyz;
fsset.realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
fsset.viscosity = get_fluid_viscosity(domainSettings);
get_fluid_gravity(fsset.gravity, scene, domainSettings);
fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings);
fsset->viscosity = get_fluid_viscosity(domainSettings);
get_fluid_gravity(fsset->gravity, scene, domainSettings);
// simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
fsset.animStart = domainSettings->animStart;
fsset.aniFrameTime = channels->aniFrameTime;
fsset.noOfFrames = noFrames; // is otherwise subtracted in parser
fsset->animStart = domainSettings->animStart;
fsset->aniFrameTime = channels->aniFrameTime;
fsset->noOfFrames = noFrames; // is otherwise subtracted in parser
strcpy(targetFile, targetDir);
strcat(targetFile, suffixSurface);
// defaults for compressibility and adaptive grids
fsset.gstar = domainSettings->gstar;
fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels
fsset.generateParticles = domainSettings->generateParticles;
fsset.numTracerParticles = domainSettings->generateTracers;
fsset.surfaceSmoothing = domainSettings->surfaceSmoothing;
fsset.surfaceSubdivs = domainSettings->surfaceSubdivs;
fsset.farFieldSize = domainSettings->farFieldSize;
strcpy( fsset.outputPath, targetFile);
fsset->gstar = domainSettings->gstar;
fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels
fsset->generateParticles = domainSettings->generateParticles;
fsset->numTracerParticles = domainSettings->generateTracers;
fsset->surfaceSmoothing = domainSettings->surfaceSmoothing;
fsset->surfaceSubdivs = domainSettings->surfaceSubdivs;
fsset->farFieldSize = domainSettings->farFieldSize;
strcpy( fsset->outputPath, targetFile);
// domain channels
fsset.channelSizeFrameTime =
fsset.channelSizeViscosity =
fsset.channelSizeGravity = channels->length;
fsset.channelFrameTime = channels->DomainTime;
fsset.channelViscosity = channels->DomainViscosity;
fsset.channelGravity = channels->DomainGravity;
fsset->channelSizeFrameTime =
fsset->channelSizeViscosity =
fsset->channelSizeGravity = channels->length;
fsset->channelFrameTime = channels->DomainTime;
fsset->channelViscosity = channels->DomainViscosity;
fsset->channelGravity = channels->DomainGravity;
fsset.runsimCallback = &runSimulationCallback;
fsset.runsimUserData = fb;
fsset->runsimCallback = &runSimulationCallback;
fsset->runsimUserData = fb;
if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
fsset.domainobsPartslip = domainSettings->partSlipValue;
fsset.generateVertexVectors = (domainSettings->domainNovecgen==0);
if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
fsset->domainobsPartslip = domainSettings->partSlipValue;
fsset->generateVertexVectors = (domainSettings->domainNovecgen==0);
// init blender domain transform matrix
{ int j;
for(i=0; i<4; i++) {
for(j=0; j<4; j++) {
fsset.surfaceTrafo[i*4+j] = invDomMat[j][i];
fsset->surfaceTrafo[i*4+j] = invDomMat[j][i];
}
} }
/* ******** init solver with settings ******** */
elbeemInit();
elbeemAddDomain(&fsset);
elbeemAddDomain(fsset);
/* ******** export all fluid objects to elbeem ******** */
export_fluid_objects(fobjects, scene, channels->length);
/* custom data for fluid bake job */
fb->settings = &fsset;
fb->settings = fsset;
/* setup job */
WM_jobs_customdata(steve, fb, fluidbake_free);
WM_jobs_timer(steve, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME);
WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, NULL);
WM_jobs_callbacks(steve, fluidbake_startjob, NULL, NULL, fluidbake_endjob);
WM_jobs_start(CTX_wm_manager(C), steve);

View File

@@ -441,6 +441,7 @@ typedef struct RenderJob {
ImageUser iuser;
short *stop;
short *do_update;
float *progress;
ReportList *reports;
} RenderJob;
@@ -519,6 +520,14 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
}
static void render_progress_update(void *rjv, float progress)
{
RenderJob *rj= rjv;
if (rj->progress)
*rj->progress = progress;
}
static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
{
RenderJob *rj= rjv;
@@ -540,13 +549,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
BKE_image_release_ibuf(ima, lock);
}
static void render_startjob(void *rjv, short *stop, short *do_update)
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
{
RenderJob *rj= rjv;
// Main *mainp= BKE_undo_get_main(&rj->scene);
rj->stop= stop;
rj->do_update= do_update;
rj->progress= progress;
if(rj->anim)
RE_BlenderAnim(rj->re, rj->scene, rj->lay, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->r.frame_step, rj->reports);
@@ -663,7 +673,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
rj->reports= op->reports;
/* setup job */
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Render", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
WM_jobs_customdata(steve, rj, render_freejob);
WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
WM_jobs_callbacks(steve, render_startjob, NULL, NULL, render_endjob);
@@ -679,6 +689,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
RE_test_break_cb(re, rj, render_breakjob);
RE_display_draw_cb(re, rj, image_rect_update);
RE_stats_draw_cb(re, rj, image_renderinfo_cb);
RE_progress_cb(re, rj, render_progress_update);
rj->re= re;
G.afbreek= 0;

View File

@@ -1090,7 +1090,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
/* use same function for icon & shader, so the job manager
does not run two of them at the same time. */
static void common_preview_startjob(void *customdata, short *stop, short *do_update)
static void common_preview_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
ShaderPreview *sp= customdata;
@@ -1107,7 +1107,7 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
wmJob *steve;
ShaderPreview *sp;
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, WM_JOB_EXCL_RENDER);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER);
sp= MEM_callocN(sizeof(ShaderPreview), "shader preview");
/* customdata for preview thread */
@@ -1132,7 +1132,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
wmJob *steve;
ShaderPreview *sp;
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, WM_JOB_EXCL_RENDER);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER);
sp= MEM_callocN(sizeof(ShaderPreview), "shader preview");
/* customdata for preview thread */

View File

@@ -215,7 +215,7 @@ static void screenshot_updatejob(void *sjv)
/* only this runs inside thread */
static void screenshot_startjob(void *sjv, short *stop, short *do_update)
static void screenshot_startjob(void *sjv, short *stop, short *do_update, float *progress)
{
ScreenshotJob *sj= sjv;
RenderData rd= sj->scene->r;
@@ -296,7 +296,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update)
static int screencast_exec(bContext *C, wmOperator *op)
{
bScreen *screen= CTX_wm_screen(C);
wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, 0);
wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, "Screencast", 0);
ScreenshotJob *sj= MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
/* setup sj */

View File

@@ -1269,7 +1269,7 @@ static void thumbnail_joblist_free(ThumbnailJob *tj)
BLI_freelistN(&tj->loadimages);
}
static void thumbnails_startjob(void *tjv, short *stop, short *do_update)
static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *progress)
{
ThumbnailJob *tj= tjv;
FileImage* limg = tj->loadimages.first;
@@ -1349,7 +1349,7 @@ void thumbnails_start(struct FileList* filelist, const struct bContext* C)
BKE_reports_init(&tj->reports, RPT_PRINT);
/* setup job */
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, 0);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails", 0);
WM_jobs_customdata(steve, tj, thumbnails_free);
WM_jobs_timer(steve, 0.5, NC_WINDOW, NC_WINDOW);
WM_jobs_callbacks(steve, thumbnails_startjob, NULL, thumbnails_update, NULL);

View File

@@ -156,6 +156,10 @@ static void info_header_listener(ARegion *ar, wmNotifier *wmn)
if(ELEM(wmn->data, ND_SCREENCAST, ND_ANIMPLAY))
ED_region_tag_redraw(ar);
break;
case NC_WM:
if(wmn->data == ND_JOB)
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
if(wmn->data==ND_RENDER_RESULT)
ED_region_tag_redraw(ar);

View File

@@ -88,6 +88,7 @@ typedef struct CompoJob {
bNodeTree *localtree;
short *stop;
short *do_update;
float *progress;
} CompoJob;
/* called by compo, only to check job 'stop' value */
@@ -133,9 +134,16 @@ static void compo_updatejob(void *cjv)
ntreeLocalSync(cj->localtree, cj->ntree);
}
static void compo_progressjob(void *cjv, float progress)
{
CompoJob *cj= cjv;
*(cj->progress) = progress;
}
/* only this runs inside thread */
static void compo_startjob(void *cjv, short *stop, short *do_update)
static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
{
CompoJob *cj= cjv;
bNodeTree *ntree= cj->localtree;
@@ -145,11 +153,14 @@ static void compo_startjob(void *cjv, short *stop, short *do_update)
cj->stop= stop;
cj->do_update= do_update;
cj->progress= progress;
ntree->test_break= compo_breakjob;
ntree->tbh= cj;
ntree->stats_draw= compo_redrawjob;
ntree->sdh= cj;
ntree->progress= compo_progressjob;
ntree->prh= cj;
// XXX BIF_store_spare();
@@ -157,6 +168,7 @@ static void compo_startjob(void *cjv, short *stop, short *do_update)
ntree->test_break= NULL;
ntree->stats_draw= NULL;
ntree->progress= NULL;
}
@@ -166,7 +178,7 @@ void snode_composite_job(const bContext *C, ScrArea *sa)
wmJob *steve;
CompoJob *cj;
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, WM_JOB_EXCL_RENDER);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Compositing", WM_JOB_EXCL_RENDER|WM_JOB_PROGRESS);
cj= MEM_callocN(sizeof(CompoJob), "compo job");
/* customdata for preview thread */

View File

@@ -186,10 +186,10 @@ typedef struct bNodeTree {
int pad2[2];
/* callbacks */
void (*timecursor)(void *, int nr);
void (*progress)(void *, float progress);
void (*stats_draw)(void *, char *str);
int (*test_break)(void *);
void *tbh, *tch, *sdh;
void *tbh, *prh, *sdh;
} bNodeTree;

View File

@@ -139,8 +139,8 @@ typedef struct ThemeUI {
uiWidgetColors wcol_radio, wcol_option, wcol_toggle;
uiWidgetColors wcol_num, wcol_numslider;
uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item;
uiWidgetColors wcol_box, wcol_scroll, wcol_list_item;
uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item;
uiWidgetStateColors wcol_state;
char iconfile[80]; // FILE_MAXFILE length

View File

@@ -524,6 +524,13 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ThemeWidgetColors");
RNA_def_property_ui_text(prop, "Scroll Widget Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop= RNA_def_property(srna, "wcol_progress", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "wcol_progress");
RNA_def_property_struct_type(prop, "ThemeWidgetColors");
RNA_def_property_ui_text(prop, "Progress Bar Widget Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop= RNA_def_property(srna, "wcol_list_item", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);

View File

@@ -230,7 +230,7 @@ void RE_display_init_cb (struct Render *re, void *handle, void (*f)(void *handle
void RE_display_clear_cb(struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr));
void RE_display_draw_cb (struct Render *re, void *handle, void (*f)(void *handle, RenderResult *rr, volatile struct rcti *rect));
void RE_stats_draw_cb (struct Render *re, void *handle, void (*f)(void *handle, RenderStats *rs));
void RE_timecursor_cb (struct Render *re, void *handle, void (*f)(void *handle, int));
void RE_progress_cb (struct Render *re, void *handle, void (*f)(void *handle, float));
void RE_test_break_cb (struct Render *re, void *handle, int (*f)(void *handle));
void RE_error_cb (struct Render *re, void *handle, void (*f)(void *handle, char *str));

View File

@@ -199,7 +199,7 @@ struct Image;
struct Object;
void RE_shade_external(struct Render *re, struct ShadeInput *shi, struct ShadeResult *shr);
int RE_bake_shade_all_selected(struct Render *re, int type, struct Object *actob, short *do_update);
int RE_bake_shade_all_selected(struct Render *re, int type, struct Object *actob, short *do_update, float *progress);
struct Image *RE_bake_shade_get_image(void);
#endif /* RE_SHADER_EXT_H */

View File

@@ -234,8 +234,8 @@ struct Render
void (*stats_draw)(void *handle, RenderStats *ri);
void *sdh;
void (*timecursor)(void *handle, int i);
void *tch;
void (*progress)(void *handle, float i);
void *prh;
int (*test_break)(void *handle);
void *tbh;

View File

@@ -131,7 +131,7 @@ static int thread_break(void *unused)
static void result_nothing(void *unused, RenderResult *rr) {}
static void result_rcti_nothing(void *unused, RenderResult *rr, volatile struct rcti *rect) {}
static void stats_nothing(void *unused, RenderStats *rs) {}
static void int_nothing(void *unused, int val) {}
static void float_nothing(void *unused, float val) {}
static void print_error(void *unused, char *str) {printf("ERROR: %s\n", str);}
static int default_break(void *unused) {return G.afbreek == 1;}
@@ -1162,7 +1162,7 @@ Render *RE_NewRender(const char *name)
re->display_init= result_nothing;
re->display_clear= result_nothing;
re->display_draw= result_rcti_nothing;
re->timecursor= int_nothing;
re->progress= float_nothing;
re->test_break= default_break;
re->error= print_error;
if(G.background)
@@ -1170,7 +1170,7 @@ Render *RE_NewRender(const char *name)
else
re->stats_draw= stats_nothing;
/* clear callback handles */
re->dih= re->dch= re->ddh= re->sdh= re->tch= re->tbh= re->erh= NULL;
re->dih= re->dch= re->ddh= re->sdh= re->prh= re->tbh= re->erh= NULL;
/* init some variables */
re->ycor= 1.0f;
@@ -1374,10 +1374,10 @@ void RE_stats_draw_cb(Render *re, void *handle, void (*f)(void *handle, RenderSt
re->stats_draw= f;
re->sdh= handle;
}
void RE_timecursor_cb(Render *re, void *handle, void (*f)(void *handle, int))
void RE_progress_cb(Render *re, void *handle, void (*f)(void *handle, float))
{
re->timecursor= f;
re->tch= handle;
re->progress= f;
re->prh= handle;
}
void RE_test_break_cb(Render *re, void *handle, int (*f)(void *handle))
@@ -1694,6 +1694,7 @@ static void threaded_tile_processor(Render *re)
free_render_result(&pa->fullresult, pa->result);
pa->result= NULL;
re->i.partsdone++;
re->progress(re->prh, re->i.partsdone / (float)re->i.totpart);
hasdrawn= 1;
}
}
@@ -2376,8 +2377,11 @@ static void do_render_composite_fields_blur_3d(Render *re)
if(!re->test_break(re->tbh)) {
ntree->stats_draw= render_composit_stats;
ntree->test_break= re->test_break;
ntree->progress= re->progress;
ntree->sdh= re->sdh;
ntree->tbh= re->tbh;
ntree->prh= re->prh;
/* in case it was never initialized */
R.sdh= re->sdh;
R.stats_draw= re->stats_draw;
@@ -2393,7 +2397,8 @@ static void do_render_composite_fields_blur_3d(Render *re)
ntree->stats_draw= NULL;
ntree->test_break= NULL;
ntree->tbh= ntree->sdh= NULL;
ntree->progress= NULL;
ntree->tbh= ntree->sdh= ntree->prh= NULL;
}
}
else if(re->r.scemode & R_FULL_SAMPLE)

View File

@@ -2619,7 +2619,7 @@ static void *do_bake_thread(void *bs_v)
/* 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, Object *actob, short *do_update)
int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_update, float *progress)
{
BakeShade *handles;
ListBase threads;
@@ -2680,12 +2680,18 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
/* wait for everything to be done */
a= 0;
while(a!=re->r.threads) {
PIL_sleep_ms(50);
for(a=0; a<re->r.threads; a++)
/* calculate progress */
for(vdone=0, a=0; a<re->r.threads; a++)
vdone+= handles[a].vdone;
if (progress)
*progress = (float)(vdone / (float)re->totvlak);
for(a=0; a<re->r.threads; a++) {
if(handles[a].ready==0)
break;
}
}
/* filter and refresh images */
@@ -2733,12 +2739,10 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
}
/* calculate return value */
for(a=0; a<re->r.threads; a++) {
vdone+= handles[a].vdone;
for(a=0; a<re->r.threads; a++) {
zbuf_free_span(handles[a].zspan);
MEM_freeN(handles[a].zspan);
}
}
MEM_freeN(handles);

View File

@@ -299,15 +299,18 @@ int WM_framebuffer_to_index(unsigned int col);
/* threaded Jobs Manager */
#define WM_JOB_PRIORITY 1
#define WM_JOB_EXCL_RENDER 2
#define WM_JOB_PROGRESS 4
struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void *owner, int flag);
struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void *owner, char *name, int flag);
int WM_jobs_test(struct wmWindowManager *wm, void *owner);
float WM_jobs_progress(struct wmWindowManager *wm, void *owner);
char *WM_jobs_name(struct wmWindowManager *wm, void *owner);
void WM_jobs_customdata(struct wmJob *, void *customdata, void (*free)(void *));
void WM_jobs_timer(struct wmJob *, double timestep, unsigned int note, unsigned int endnote);
void WM_jobs_callbacks(struct wmJob *,
void (*startjob)(void *, short *, short *),
void (*startjob)(void *, short *, short *, float *),
void (*initjob)(void *),
void (*update)(void *),
void (*endjob)(void *));

View File

@@ -158,6 +158,7 @@ typedef struct wmNotifier {
#define ND_FILESAVE (2<<16)
#define ND_DATACHANGED (3<<16)
#define ND_HISTORY (4<<16)
#define ND_JOB (5<<16)
/* NC_SCREEN screen */
#define ND_SCREENBROWSE (1<<16)

View File

@@ -26,6 +26,8 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include "DNA_windowmanager_types.h"
#include "MEM_guardedalloc.h"
@@ -89,7 +91,7 @@ struct wmJob {
/* to prevent cpu overhead, use this one which only gets called when job really starts, not in thread */
void (*initjob)(void *);
/* this runs inside thread, and does full job */
void (*startjob)(void *, short *stop, short *do_update);
void (*startjob)(void *, short *stop, short *do_update, float *progress);
/* update gets called if thread defines so, and max once per timerstep */
/* it runs outside thread, blocking blender, no drawing! */
void (*update)(void *);
@@ -109,6 +111,10 @@ struct wmJob {
void *owner;
int flag;
short suspended, running, ready, do_update, stop;
float progress;
/* for display in header, identification */
char name[128];
/* once running, we store this separately */
void *run_customdata;
@@ -119,18 +125,32 @@ struct wmJob {
};
/* finds:
* 1st priority: job with same owner and name
* 2nd priority: job with same owner
*/
static wmJob *wm_job_find(wmWindowManager *wm, void *owner, char *name)
{
wmJob *steve, *found=NULL;
for(steve= wm->jobs.first; steve; steve= steve->next)
if(steve->owner==owner) {
found= steve;
if (name && strcmp(steve->name, name)==0)
return steve;
}
return found;
}
/* ******************* public API ***************** */
/* returns current or adds new job, but doesnt run it */
/* every owner only gets a single job, adding a new one will stop running stop and
when stopped it starts the new one */
wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, int flag)
wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, char *name, int flag)
{
wmJob *steve;
for(steve= wm->jobs.first; steve; steve= steve->next)
if(steve->owner==owner)
break;
wmJob *steve= wm_job_find(wm, owner, name);
if(steve==NULL) {
steve= MEM_callocN(sizeof(wmJob), "new job");
@@ -139,6 +159,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, int flag)
steve->win= win;
steve->owner= owner;
steve->flag= flag;
BLI_strncpy(steve->name, name, sizeof(steve->name));
}
return steve;
@@ -156,6 +177,26 @@ int WM_jobs_test(wmWindowManager *wm, void *owner)
return 0;
}
float WM_jobs_progress(wmWindowManager *wm, void *owner)
{
wmJob *steve= wm_job_find(wm, owner, NULL);
if (steve && steve->flag & WM_JOB_PROGRESS)
return steve->progress;
return 0.0;
}
char *WM_jobs_name(wmWindowManager *wm, void *owner)
{
wmJob *steve= wm_job_find(wm, owner, NULL);
if (steve)
return steve->name;
return NULL;
}
void WM_jobs_customdata(wmJob *steve, void *customdata, void (*free)(void *))
{
/* pending job? just free */
@@ -179,7 +220,7 @@ void WM_jobs_timer(wmJob *steve, double timestep, unsigned int note, unsigned in
}
void WM_jobs_callbacks(wmJob *steve,
void (*startjob)(void *, short *, short *),
void (*startjob)(void *, short *, short *, float *),
void (*initjob)(void *),
void (*update)(void *),
void (*endjob)(void *))
@@ -194,7 +235,7 @@ static void *do_job_thread(void *job_v)
{
wmJob *steve= job_v;
steve->startjob(steve->run_customdata, &steve->stop, &steve->do_update);
steve->startjob(steve->run_customdata, &steve->stop, &steve->do_update, &steve->progress);
steve->ready= 1;
return NULL;
@@ -248,6 +289,7 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *steve)
steve->stop= 0;
steve->ready= 0;
steve->progress= 0.0;
BLI_init_threads(&steve->threads, do_job_thread, 1);
BLI_insert_thread(&steve->threads, steve);
@@ -354,6 +396,9 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
steve->update(steve->run_customdata);
if(steve->note)
WM_event_add_notifier(C, steve->note, NULL);
if (steve->flag & WM_JOB_PROGRESS)
WM_event_add_notifier(C, NC_WM|ND_JOB, NULL);
steve->do_update= 0;
}
@@ -375,6 +420,8 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt)
if(steve->endnote)
WM_event_add_notifier(C, steve->endnote, NULL);
WM_event_add_notifier(C, NC_WM|ND_JOB, NULL);
/* new job added for steve? */
if(steve->customdata) {
WM_jobs_start(wm, steve);