Partial fix for T37604: Deadlock when stopping rendered viewport (Blender Internal)
[blender.git] / source / blender / editors / space_view3d / space_view3d.c
index 2ed1ec694d8e6c5609ccdccf51d18f92a76eb7e4..03b89972e559d52c39aaad429bd127728f4495b6 100644 (file)
 
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
-#include "BLI_rand.h"
 #include "BLI_utildefines.h"
 
 #include "BKE_context.h"
 #include "BKE_icons.h"
+#include "BKE_main.h"
 #include "BKE_object.h"
+#include "BKE_scene.h"
 #include "BKE_screen.h"
 
+#include "ED_render.h"
 #include "ED_space_api.h"
 #include "ED_screen.h"
 #include "ED_object.h"
 
+#include "GPU_extensions.h"
 #include "GPU_material.h"
 
 #include "BIF_gl.h"
 #include "WM_types.h"
 
 #include "RE_engine.h"
+#include "RE_pipeline.h"
 
 #include "RNA_access.h"
 
 #include "UI_resources.h"
 
+#ifdef WITH_PYTHON
+#  include "BPY_extern.h"
+#endif
+
 #include "view3d_intern.h"  /* own include */
 
 /* ******************** manage regions ********************* */
@@ -157,12 +165,12 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
 
 /* ideally would return an rv3d but in some cases the region is needed too
  * so return that, the caller can then access the ar->regiondata */
-int ED_view3d_context_user_region(bContext *C, View3D **v3d_r, ARegion **ar_r)
+bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
 {
        ScrArea *sa = CTX_wm_area(C);
 
-       *v3d_r = NULL;
-       *ar_r = NULL;
+       *r_v3d = NULL;
+       *r_ar = NULL;
 
        if (sa && sa->spacetype == SPACE_VIEW3D) {
                ARegion *ar = CTX_wm_region(C);
@@ -171,9 +179,9 @@ int ED_view3d_context_user_region(bContext *C, View3D **v3d_r, ARegion **ar_r)
                if (ar) {
                        RegionView3D *rv3d = ar->regiondata;
                        if (rv3d && rv3d->viewlock == 0) {
-                               *v3d_r = v3d;
-                               *ar_r = ar;
-                               return 1;
+                               *r_v3d = v3d;
+                               *r_ar = ar;
+                               return true;
                        }
                        else {
                                ARegion *ar_unlock_user = NULL;
@@ -194,21 +202,21 @@ int ED_view3d_context_user_region(bContext *C, View3D **v3d_r, ARegion **ar_r)
 
                                /* camera/perspective view get priority when the active region is locked */
                                if (ar_unlock_user) {
-                                       *v3d_r = v3d;
-                                       *ar_r = ar_unlock_user;
-                                       return 1;
+                                       *r_v3d = v3d;
+                                       *r_ar = ar_unlock_user;
+                                       return true;
                                }
 
                                if (ar_unlock) {
-                                       *v3d_r = v3d;
-                                       *ar_r = ar_unlock;
-                                       return 1;
+                                       *r_v3d = v3d;
+                                       *r_ar = ar_unlock;
+                                       return true;
                                }
                        }
                }
        }
 
-       return 0;
+       return false;
 }
 
 /* Most of the time this isn't needed since you could assume the view matrix was
@@ -225,8 +233,8 @@ int ED_view3d_context_user_region(bContext *C, View3D **v3d_r, ARegion **ar_r)
 void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
 {
        /* local viewmat and persmat, to calculate projections */
-       mult_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->obmat);
-       mult_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->obmat);
+       mul_m4_m4m4(rv3d->viewmatob, rv3d->viewmat, ob->obmat);
+       mul_m4_m4m4(rv3d->persmatob, rv3d->persmat, ob->obmat);
 
        /* initializes object space clipping, speeds up clip tests */
        ED_view3d_clipping_local(rv3d, ob->obmat);
@@ -242,6 +250,57 @@ void ED_view3d_init_mats_rv3d_gl(struct Object *ob, struct RegionView3D *rv3d)
        glMultMatrixf(ob->obmat);
 }
 
+#ifdef DEBUG
+/* ensure we correctly initialize */
+void ED_view3d_clear_mats_rv3d(struct RegionView3D *rv3d)
+{
+       zero_m4(rv3d->viewmatob);
+       zero_m4(rv3d->persmatob);
+}
+
+void ED_view3d_check_mats_rv3d(struct RegionView3D *rv3d)
+{
+       BLI_ASSERT_ZERO_M4(rv3d->viewmatob);
+       BLI_ASSERT_ZERO_M4(rv3d->persmatob);
+}
+#endif
+
+static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
+{
+       RegionView3D *rv3d = ar->regiondata;
+
+       if (rv3d->render_engine) {
+#ifdef WITH_PYTHON
+               BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+               WM_jobs_kill_type(wm, ar, WM_JOB_TYPE_RENDER_PREVIEW);
+
+#ifdef WITH_PYTHON
+               BPy_END_ALLOW_THREADS;
+#endif
+
+               if (rv3d->render_engine->re)
+                       RE_Database_Free(rv3d->render_engine->re);
+               RE_engine_free(rv3d->render_engine);
+               rv3d->render_engine = NULL;
+       }
+}
+
+void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
+{
+       wmWindowManager *wm = bmain->wm.first;
+
+       if (v3d->drawtype != OB_RENDER) {
+               ARegion *ar;
+
+               for (ar = sa->regionbase.first; ar; ar = ar->next) {
+                       if (ar->regiondata)
+                               view3d_stop_render_preview(wm, ar);
+               }
+       }
+}
+
 /* ******************** default callbacks for view3d space ***************** */
 
 static SpaceLink *view3d_new(const bContext *C)
@@ -350,7 +409,7 @@ static void view3d_free(SpaceLink *sl)
 
 
 /* spacetype; init callback */
-static void view3d_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
 {
 
 }
@@ -364,11 +423,10 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
        
 // XXX BIF_view3d_previewrender_free(v3do);
        
-       if (v3do->localvd) {
-               v3do->localvd = NULL;
-               v3do->properties_storage = NULL;
-               v3do->lay = v3dn->localvd->lay;
-               v3do->lay &= 0xFFFFFF;
+       if (v3dn->localvd) {
+               v3dn->localvd = NULL;
+               v3dn->properties_storage = NULL;
+               v3dn->lay = v3do->localvd->lay & 0xFFFFFF;
        }
 
        if (v3dn->drawtype == OB_RENDER)
@@ -469,7 +527,19 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
        
 }
 
-static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
+{
+       RegionView3D *rv3d = ar->regiondata;
+
+       view3d_stop_render_preview(wm, ar);
+
+       if (rv3d->gpuoffscreen) {
+               GPU_offscreen_free(rv3d->gpuoffscreen);
+               rv3d->gpuoffscreen = NULL;
+       }
+}
+
+static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
 {
        if (drag->type == WM_DRAG_ID) {
                ID *id = (ID *)drag->poin;
@@ -479,7 +549,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSE
        return 0;
 }
 
-static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
 {
        if (drag->type == WM_DRAG_ID) {
                ID *id = (ID *)drag->poin;
@@ -489,7 +559,7 @@ static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UN
        return 0;
 }
 
-static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
 {
        if (drag->type == WM_DRAG_ID) {
                ID *id = (ID *)drag->poin;
@@ -499,7 +569,7 @@ static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS
        return 0;
 }
 
-static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event))
+static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
 {
        if (drag->type == WM_DRAG_ID) {
                ID *id = (ID *)drag->poin;
@@ -513,23 +583,35 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS
        return 0;
 }
 
+static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+       if (event->ctrl)
+               return false;
 
-static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+       if (!ED_view3d_give_base_under_cursor(C, event->mval)) {
+               return view3d_ima_drop_poll(C, drag, event);
+       }
+       return 0;
+}
+
+static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
 {
        Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
 
-       if (!base || (base && base->object->type == OB_EMPTY))
+       /* either holding and ctrl and no object, or dropping to empty */
+       if ((event->ctrl && !base) || (base && base->object->type == OB_EMPTY))
                return view3d_ima_drop_poll(C, drag, event);
+
        return 0;
 }
 
-static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
 {
        Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
 
        if (base && base->object->type == OB_MESH)
-               return view3d_ima_drop_poll(C, drag, event);
-       return 0;
+               return view3d_ima_drop_poll(C, drag, event);
+       return 0;
 }
 
 static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -574,6 +656,7 @@ static void view3d_dropboxes(void)
        WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy);
        WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy);
        WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
+       WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
        WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
 }
 
@@ -602,6 +685,10 @@ static void view3d_main_area_free(ARegion *ar)
                if (rv3d->sms) {
                        MEM_freeN(rv3d->sms);
                }
+               if (rv3d->gpuoffscreen) {
+                       GPU_offscreen_free(rv3d->gpuoffscreen);
+               }
+
                MEM_freeN(rv3d);
                ar->regiondata = NULL;
        }
@@ -620,6 +707,7 @@ static void *view3d_main_area_duplicate(void *poin)
                        new->clipbb = MEM_dupallocN(rv3d->clipbb);
                
                new->depths = NULL;
+               new->gpuoffscreen = NULL;
                new->ri = NULL;
                new->render_engine = NULL;
                new->gpd = NULL;
@@ -661,8 +749,10 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene
        }
 }
 
-static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn)
+static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn)
 {
+       Scene *scene = sc->scene;
+       View3D *v3d = sa->spacedata.first;
        
        /* context changes */
        switch (wmn->category) {
@@ -697,6 +787,7 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn)
                                case ND_OB_VISIBLE:
                                case ND_LAYER:
                                case ND_RENDER_OPTIONS:
+                               case ND_MARKERS:
                                case ND_MODE:
                                        ED_region_tag_redraw(ar);
                                        break;
@@ -751,6 +842,16 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn)
                        break;
                case NC_MATERIAL:
                        switch (wmn->data) {
+                               case ND_SHADING:
+                               case ND_NODES:
+                                       if ((v3d->drawtype == OB_MATERIAL) ||
+                                           (v3d->drawtype == OB_TEXTURE &&
+                                                (scene->gm.matmode == GAME_MAT_GLSL ||
+                                                 BKE_scene_use_new_shading_nodes(scene))))
+                                       {
+                                               ED_region_tag_redraw(ar);
+                                       }
+                                       break;
                                case ND_SHADING_DRAW:
                                case ND_SHADING_LINKS:
                                        ED_region_tag_redraw(ar);
@@ -762,17 +863,17 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn)
                                case ND_WORLD_DRAW:
                                        /* handled by space_view3d_listener() for v3d access */
                                        break;
-                               case ND_WORLD_STARS:
-                               {
-                                       RegionView3D *rv3d = ar->regiondata;
-                                       if (rv3d->persp == RV3D_CAMOB) {
-                                               ED_region_tag_redraw(ar);
-                                       }
-                               }
                        }
                        break;
                case NC_LAMP:
                        switch (wmn->data) {
+                               case ND_LIGHTING:
+                                       if ((v3d->drawtype == OB_MATERIAL) ||
+                                           (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)))
+                                       {
+                                               ED_region_tag_redraw(ar);
+                                       }
+                                       break;
                                case ND_LIGHTING_DRAW:
                                        ED_region_tag_redraw(ar);
                                        break;
@@ -816,8 +917,8 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn)
                                        /* screen was changed, need to update used layers due to NC_SCENE|ND_LAYER_CONTENT */
                                        /* updates used layers only for View3D in active screen */
                                        if (wmn->reference) {
-                                               bScreen *sc = wmn->reference;
-                                               view3d_recalc_used_layers(ar, wmn, sc->scene);
+                                               bScreen *sc_ref = wmn->reference;
+                                               view3d_recalc_used_layers(ar, wmn, sc_ref->scene);
                                        }
                                        ED_region_tag_redraw(ar);
                                        break;
@@ -859,7 +960,7 @@ static void view3d_header_area_draw(const bContext *C, ARegion *ar)
        ED_region_header(C, ar);
 }
 
-static void view3d_header_area_listener(ARegion *ar, wmNotifier *wmn)
+static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 {
        /* context changes */
        switch (wmn->category) {
@@ -900,7 +1001,7 @@ static void view3d_buttons_area_draw(const bContext *C, ARegion *ar)
        ED_region_panels(C, ar, 1, NULL, -1);
 }
 
-static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn)
+static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 {
        /* context changes */
        switch (wmn->category) {
@@ -1000,7 +1101,7 @@ static void view3d_tools_area_draw(const bContext *C, ARegion *ar)
        ED_region_panels(C, ar, 1, CTX_data_mode_string(C), -1);
 }
 
-static void view3d_props_area_listener(ARegion *ar, wmNotifier *wmn)
+static void view3d_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 {
        /* context changes */
        switch (wmn->category) {
@@ -1020,7 +1121,7 @@ static void view3d_props_area_listener(ARegion *ar, wmNotifier *wmn)
 }
 
 /*area (not region) level listener*/
-static void space_view3d_listener(ScrArea *sa, struct wmNotifier *wmn)
+static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn)
 {
        View3D *v3d = sa->spacedata.first;
 
@@ -1076,17 +1177,17 @@ const char *view3d_context_dir[] = {
 
 static int view3d_context(const bContext *C, const char *member, bContextDataResult *result)
 {
-       View3D *v3d = CTX_wm_view3d(C);
-       Scene *scene = CTX_data_scene(C);
-       Base *base;
        /* fallback to the scene layer, allows duplicate and other object operators to run outside the 3d view */
-       unsigned int lay = v3d ? v3d->lay : scene->lay;
 
        if (CTX_data_dir(member)) {
                CTX_data_dir_set(result, view3d_context_dir);
        }
        else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) {
-               int selected_objects = CTX_data_equals(member, "selected_objects");
+               View3D *v3d = CTX_wm_view3d(C);
+               Scene *scene = CTX_data_scene(C);
+               const unsigned int lay = v3d ? v3d->lay : scene->lay;
+               Base *base;
+               const bool selected_objects = CTX_data_equals(member, "selected_objects");
 
                for (base = scene->base.first; base; base = base->next) {
                        if ((base->flag & SELECT) && (base->lay & lay)) {
@@ -1102,7 +1203,11 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
                return 1;
        }
        else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) {
-               int selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
+               View3D *v3d = CTX_wm_view3d(C);
+               Scene *scene = CTX_data_scene(C);
+               const unsigned int lay = v3d ? v3d->lay : scene->lay;
+               Base *base;
+               const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects");
 
                for (base = scene->base.first; base; base = base->next) {
                        if ((base->flag & SELECT) && (base->lay & lay)) {
@@ -1120,7 +1225,11 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
                return 1;
        }
        else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) {
-               int visible_objects = CTX_data_equals(member, "visible_objects");
+               View3D *v3d = CTX_wm_view3d(C);
+               Scene *scene = CTX_data_scene(C);
+               const unsigned int lay = v3d ? v3d->lay : scene->lay;
+               Base *base;
+               const bool visible_objects = CTX_data_equals(member, "visible_objects");
 
                for (base = scene->base.first; base; base = base->next) {
                        if (base->lay & lay) {
@@ -1136,7 +1245,11 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
                return 1;
        }
        else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) {
-               int selectable_objects = CTX_data_equals(member, "selectable_objects");
+               View3D *v3d = CTX_wm_view3d(C);
+               Scene *scene = CTX_data_scene(C);
+               const unsigned int lay = v3d ? v3d->lay : scene->lay;
+               Base *base;
+               const bool selectable_objects = CTX_data_equals(member, "selectable_objects");
 
                for (base = scene->base.first; base; base = base->next) {
                        if (base->lay & lay) {
@@ -1152,6 +1265,9 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
                return 1;
        }
        else if (CTX_data_equals(member, "active_base")) {
+               View3D *v3d = CTX_wm_view3d(C);
+               Scene *scene = CTX_data_scene(C);
+               const unsigned int lay = v3d ? v3d->lay : scene->lay;
                if (scene->basact && (scene->basact->lay & lay)) {
                        Object *ob = scene->basact->object;
                        /* if hidden but in edit mode, we still display, can happen with animation */
@@ -1162,6 +1278,9 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
                return 1;
        }
        else if (CTX_data_equals(member, "active_object")) {
+               View3D *v3d = CTX_wm_view3d(C);
+               Scene *scene = CTX_data_scene(C);
+               const unsigned int lay = v3d ? v3d->lay : scene->lay;
                if (scene->basact && (scene->basact->lay & lay)) {
                        Object *ob = scene->basact->object;
                        if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0 || (ob->mode & OB_MODE_EDIT))
@@ -1203,6 +1322,7 @@ void ED_spacetype_view3d(void)
        art->keymapflag = ED_KEYMAP_GPENCIL;
        art->draw = view3d_main_area_draw;
        art->init = view3d_main_area_init;
+       art->exit = view3d_main_area_exit;
        art->free = view3d_main_area_free;
        art->duplicate = view3d_main_area_duplicate;
        art->listener = view3d_main_area_listener;