diff options
author | Ton Roosendaal <ton@blender.org> | 2009-01-22 17:59:49 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2009-01-22 17:59:49 +0300 |
commit | 9cc59fb0c329bb788defe9c56b69d0919caaba96 (patch) | |
tree | f6f1c48441ba6de4f2ff1faf19a0540ce1dc6ba5 /source/blender/windowmanager | |
parent | a017982074b3b11fd0157d8d604e02858411db70 (diff) |
2.5
Added WM Jobs manager
- WM can manage threaded jobs for you; just provide a couple
of components to get it work:
- customdata, free callback for it
- timer step, notifier code
- start callback, update callback
- Once started, each job runs an own timer, and will for
every time step check necessary updates, or close the
job when ready.
- No drawing happens in jobs, that's for notifiers!
- Every job stores an owner pointer, and based on this owner
it will prevent multiple jobs to enter the stack.
Instead it will re-use a running job, signal it to stop
and allow caller to re-initialize it even.
- Check new wm_jobs.c for more explanation. Jobs API is still
under construction.
Fun: BLI_addtail(&wm->jobs, steve); :)
Put Node shader previews back using wmJobs
- Preview calculating is now fully threaded (1 thread still)
- Thanks to new event system + notifiers, you can see
previews update even while dragging sliders!
- Currently it only starts when you change a node setting.
Warning: the thread render shares Node data, so don't delete
nodes while it renders! This topic is on the todo to make safe.
Also:
- bug in region initialize (do_versions) showed channel list in
node editor wrong.
- flagged the channel list 'hidden' now, it was really in the
way! This is for later to work on anyway.
- recoded Render API callbacks so it gets handlers passed on,
no globals to use anymore, remember?
- previewrender code gets now so much nicer! Will remove a lot
of stuff from code soon.
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r-- | source/blender/windowmanager/WM_api.h | 17 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 7 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_jobs.c | 270 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 4 | ||||
-rw-r--r-- | source/blender/windowmanager/wm.h | 4 | ||||
-rw-r--r-- | source/blender/windowmanager/wm_event_types.h | 2 |
7 files changed, 301 insertions, 5 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index d7559eac306..13104b58a04 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -36,9 +36,13 @@ struct IDProperty; struct wmEvent; struct wmEventHandler; struct wmGesture; +struct wmJob; +struct wmNotifier; struct rcti; struct PointerRNA; +typedef struct wmJob wmJob; + /* general API */ void WM_setprefsize (int stax, int stay, int sizx, int sizy); @@ -168,5 +172,18 @@ void wmOrtho2 (float x1, float x2, float y1, float y2); void WM_set_framebuffer_index_color(int index); int WM_framebuffer_to_index(unsigned int col); + /* threaded Jobs Manager */ + +struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void *owner); + +void WM_jobs_customdata(struct wmJob *, void *customdata, void (*free)(void *)); +void WM_jobs_timer(struct wmJob *, double timestep, unsigned int note); +void WM_jobs_callbacks(struct wmJob *, + void (*startjob)(void *, short *, short *), + void (*listener)(struct wmJob *, struct wmNotifier *), + void (*update)(void *)); + +void WM_jobs_start(struct wmJob *); + #endif /* WM_API_H */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 69e974e3863..6fc67242d69 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -517,7 +517,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) static int wm_event_always_pass(wmEvent *event) { /* some events we always pass on, to ensure proper communication */ - return ELEM4(event->type, TIMER, TIMER0, TIMER1, TIMER2); + return ELEM5(event->type, TIMER, TIMER0, TIMER1, TIMER2, TIMERJOBS); } /* Warning: this function removes a modal handler, when finished */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 4f8e84df08c..dc36cf2d62c 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -82,6 +82,7 @@ #include "wm_files.h" #include "wm_window.h" +#include "ED_previewrender.h" #include "ED_space_api.h" #include "ED_screen.h" #include "ED_util.h" @@ -142,7 +143,7 @@ void WM_init(bContext *C) sound_init_listener(); // init_node_butfuncs(); -// XXX BIF_preview_init_dbase(); + ED_preview_init_dbase(); GPU_extensions_init(); @@ -215,7 +216,8 @@ void WM_exit(bContext *C) #endif // fastshade_free_render(); /* shaded view */ - free_blender(); /* blender.c, does entire library */ + ED_preview_free_dbase(); /* frees a Main dbase, before free_blender! */ + free_blender(); /* blender.c, does entire library and spacetypes */ // free_matcopybuf(); // free_ipocopybuf(); free_actcopybuf(); @@ -260,7 +262,6 @@ void WM_exit(bContext *C) UI_exit(); BLI_freelistN(&U.themes); -// XXX BIF_preview_free_dbase(); RNA_exit(); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c new file mode 100644 index 00000000000..1f320df7587 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -0,0 +1,270 @@ +/** + * $Id: + * + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_windowmanager_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_threads.h" + +#include "BKE_blender.h" +#include "BKE_context.h" +#include "BKE_idprop.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm_window.h" +#include "wm_event_system.h" +#include "wm_event_types.h" +#include "wm.h" + +#include "ED_screen.h" + +#include "RNA_types.h" + +/* ********************** Threaded Jobs Manager ****************************** */ + +/* +Add new job +- register in WM +- configure callbacks + +Start or re-run job +- if job running + - signal job to end + - add timer notifier to verify when it has ended, to start it +- else + - start job + - add timer notifier to handle progress + +Stop job + - signal job to end + on end, job will tag itself as sleeping + +Remove job +- signal job to end + on end, job will remove itself + +When job is done: +- it puts timer to sleep (or removes?) + + */ + +struct wmJob { + struct wmJob *next, *prev; + + /* job originating from, keep track of this when deleting windows */ + wmWindow *win; + + /* should store entire own context, for start, free or listeners */ + void *customdata; + void (*startjob)(void *, short *stop, short *do_update); + void (*free)(void *); + + /* running jobs each have own timer */ + double timestep; + wmTimer *wt; + /* the notifier event timers should send */ + unsigned int note; + + /* managing */ + void (*listener)(struct wmJob *, struct wmNotifier *); + + /* update gets called if thread defines so, and max once per timerstep */ + /* no drawing, send notifiers! */ + void (*update)(void *); + +/* internal */ + void *owner; + short running, ready, do_update, stop; + + /* once running, we store this separately */ + void *run_customdata; + void (*run_free)(void *); + + /* we use BLI_threads api, but per job only 1 thread runs */ + ListBase threads; + +}; + +/* ******************* public API ***************** */ + +/* returns current or adds new job, but doesnt run it */ +wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner) +{ + wmJob *steve; + + for(steve= wm->jobs.first; steve; steve= steve->next) + if(steve->owner==owner) + break; + + if(steve==NULL) { + steve= MEM_callocN(sizeof(wmJob), "new job"); + + BLI_addtail(&wm->jobs, steve); + steve->win= win; + steve->owner= owner; + } + + return steve; +} + +void WM_jobs_customdata(wmJob *steve, void *customdata, void (*free)(void *)) +{ + /* pending job? just free */ + if(steve->customdata) + steve->free(steve->customdata); + + steve->customdata= customdata; + steve->free= free; + + if(steve->running) { + /* signal job to end */ + steve->stop= 1; + } +} + +void WM_jobs_timer(wmJob *steve, double timestep, unsigned int note) +{ + steve->timestep = timestep; + steve->note = note; +} + +void WM_jobs_callbacks(wmJob *steve, + void (*startjob)(void *, short *, short *), + void (*listener)(struct wmJob *, struct wmNotifier *), + void (*update)(void *)) +{ + steve->startjob= startjob; + steve->listener= listener; + steve->update= update; +} + +static void *do_job_thread(void *job_v) +{ + wmJob *steve= job_v; + + steve->stop= steve->ready= 0; + steve->startjob(steve->run_customdata, &steve->stop, &steve->do_update); + steve->ready= 1; + + return NULL; +} + +void WM_jobs_start(wmJob *steve) +{ + if(steve->running) { + /* signal job to end and restart */ + steve->stop= 1; + } + else { + if(steve->customdata && steve->startjob) { + + /* copy to ensure proper free in end */ + steve->run_customdata= steve->customdata; + steve->run_free= steve->free; + steve->free= NULL; + steve->customdata= NULL; + steve->running= 1; + + BLI_init_threads(&steve->threads, do_job_thread, 1); + BLI_insert_thread(&steve->threads, steve); + + /* restarted job has timer already */ + if(steve->wt==NULL) + steve->wt= WM_event_add_window_timer(steve->win, TIMERJOBS, steve->timestep); + } + else printf("job fails, not initialized\n"); + } +} + +/* hardcoded to event TIMERJOBS */ +static int wm_jobs_timer(bContext *C, wmOperator *op, wmEvent *evt) +{ + wmWindowManager *wm= CTX_wm_manager(C); + wmJob *steve= wm->jobs.first; + + for(; steve; steve= steve->next) { + + if(evt->customdata==steve->wt) { + /* running threads */ + if(steve->threads.first) { + + if(steve->do_update) { + if(steve->update) + steve->update(steve->customdata); + if(steve->note) + WM_event_add_notifier(C, steve->note, NULL); + steve->do_update= 0; + } + + if(steve->ready) { + /* free own data */ + steve->run_free(steve->run_customdata); + steve->run_customdata= NULL; + steve->run_free= NULL; + + steve->running= 0; + BLI_end_threads(&steve->threads); + + /* new job added for steve? */ + if(steve->customdata) { + WM_jobs_start(steve); + } + else { + WM_event_remove_window_timer(steve->win, steve->wt); + steve->wt= NULL; + + /* remove steve */ + BLI_remlink(&wm->jobs, steve); + MEM_freeN(steve); + } + } + } + return OPERATOR_FINISHED; + } + } + return OPERATOR_PASS_THROUGH; +} + +void WM_OT_jobs_timer(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Jobs timer"; + ot->idname= "WM_OT_jobs_timer"; + + /* api callbacks */ + ot->invoke= wm_jobs_timer; + + ot->poll= ED_operator_screenactive; + +} diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 1ce6aaf837b..58f2be80922 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -874,6 +874,7 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_tweak_gesture); WM_operatortype_append(WM_OT_open_recentfile); WM_operatortype_append(WM_OT_open_mainfile); + WM_operatortype_append(WM_OT_jobs_timer); WM_operatortype_append(WM_OT_save_as_mainfile); } @@ -882,6 +883,9 @@ void wm_window_keymap(wmWindowManager *wm) { ListBase *keymap= WM_keymap_listbase(wm, "Window", 0, 0); + /* items to make WM work */ + WM_keymap_verify_item(keymap, "WM_OT_jobs_timer", TIMERJOBS, KM_ANY, KM_ANY, 0); + /* note, this doesn't replace existing keymap items */ WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", AKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); WM_keymap_verify_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index c063226b96f..ecb40f34174 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -59,5 +59,9 @@ void wm_gesture_draw(struct wmWindow *win); int wm_gesture_evaluate(bContext *C, wmGesture *gesture); void wm_gesture_tag_redraw(bContext *C); +/* wm_jobs.h */ +void WM_OT_jobs_timer(struct wmOperatorType *ot); + + #endif /* WM_H */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 6a8174b351a..41c451755fc 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -75,7 +75,7 @@ #define TIMER0 0x0111 /* timer event, slot for internal use */ #define TIMER1 0x0112 /* timer event, slot for internal use */ #define TIMER2 0x0113 /* timer event, slot for internal use */ -#define TIMER3 0x0114 /* timer event, slot for internal use */ +#define TIMERJOBS 0x0114 /* timer event, internal use */ /* standard keyboard */ |