Merge branch 'master' into blender2.8
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 22 Mar 2018 15:41:37 +0000 (16:41 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 22 Mar 2018 15:41:37 +0000 (16:41 +0100)
1  2 
release/scripts/startup/bl_operators/clip.py
release/scripts/startup/bl_ui/properties_render.py
source/blender/depsgraph/intern/eval/deg_eval.cc
source/blender/editors/armature/armature_edit.c
source/blender/editors/armature/armature_utils.c
source/blender/editors/include/ED_armature.h
source/blender/windowmanager/intern/wm_window.c

index f13c1fb3130f01de2b7869a240ecc2848890d23a,35b8a08bf21780472532ec984fc9862ec2901c41..e67b275a3ee34b76c222eb7a5eeb4819f3f97f91
@@@ -235,7 -235,7 +235,7 @@@ class CLIP_OT_track_to_empty(Operator)
          ob = None
  
          ob = bpy.data.objects.new(name=track.name, object_data=None)
 -        ob.select = True
 +        ob.select_set(action='SELECT')
          context.scene.objects.link(ob)
          context.scene.objects.active = ob
  
@@@ -302,7 -302,7 +302,7 @@@ class CLIP_OT_bundles_to_mesh(Operator)
              matrix = camera.matrix_world * reconstructed_matrix.inverted()
  
          for track in tracking_object.tracks:
-             if track.has_bundle and track.select == True:
+             if track.has_bundle and track.select:
                  new_verts.append(track.bundle)
  
          if new_verts:
@@@ -515,7 -515,7 +515,7 @@@ object's movement caused by this constr
          # XXX, should probably use context.selected_editable_objects
          # since selected objects can be from a lib or in hidden layer!
          for ob in scene.objects:
 -            if ob.select:
 +            if ob.select_set(action='SELECT'):
                  self._bake_object(scene, ob)
  
          return {'FINISHED'}
@@@ -612,24 -612,24 +612,24 @@@ class CLIP_OT_setup_tracking_scene(Oper
          CLIP_set_viewport_background(context, True, sc.clip, sc.clip_user)
  
      @staticmethod
 -    def _setupRenderLayers(context):
 +    def _setupViewLayers(context):
          scene = context.scene
 -        rlayers = scene.render.layers
 +        view_layers = scene.view_layers
  
 -        if not scene.render.layers.get("Foreground"):
 -            if len(rlayers) == 1:
 -                fg = rlayers[0]
 +        if not view_layers.get("Foreground"):
 +            if len(view_layers) == 1:
 +                fg = view_layers[0]
                  fg.name = 'Foreground'
              else:
 -                fg = scene.render.layers.new("Foreground")
 +                fg = view_layers.new("Foreground")
  
              fg.use_sky = True
              fg.layers = [True] + [False] * 19
              fg.layers_zmask = [False] * 10 + [True] + [False] * 9
              fg.use_pass_vector = True
  
 -        if not scene.render.layers.get("Background"):
 -            bg = scene.render.layers.new("Background")
 +        if not view_layers.get("Background"):
 +            bg = view_layers.new("Background")
              bg.use_pass_shadow = True
              bg.use_pass_ambient_occlusion = True
              bg.layers = [False] * 10 + [True] + [False] * 9
      def _setupObjects(self, context):
          scene = context.scene
  
 -        fg = scene.render.layers.get("Foreground")
 -        bg = scene.render.layers.get("Background")
 +        fg = scene.view_layers.get("Foreground")
 +        bg = scene.view_layers.get("Background")
  
          all_layers = self._mergeLayers(fg.layers, bg.layers)
  
          self._setupWorld(context)
          self._setupCamera(context)
          self._setupViewport(context)
 -        self._setupRenderLayers(context)
 +        self._setupViewLayers(context)
          self._setupNodes(context)
          self._setupObjects(context)
  
index 12b0df795c75991fdbab452c14ec98ed4b16ef79,41ebf8196d28e211272371b3bca1799d09bece93..ed926b51a9c147c6cd09da3da5ad6ba03e67a24a
@@@ -52,33 -52,12 +52,33 @@@ class RenderButtonsPanel
      @classmethod
      def poll(cls, context):
          scene = context.scene
 -        return scene and (scene.render.engine in cls.COMPAT_ENGINES)
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +
 +class RENDER_PT_context(Panel):
 +    bl_space_type = 'PROPERTIES'
 +    bl_region_type = 'WINDOW'
 +    bl_context = "render"
 +    bl_options = {'HIDE_HEADER'}
 +    bl_label = ""
 +
 +    @classmethod
 +    def poll(cls, context):
 +        return context.scene
 +
 +    def draw(self, context):
 +        layout = self.layout
 +
 +        scene = context.scene
 +        view_render = scene.view_render
 +
 +        if view_render.has_multiple_engines:
 +            layout.prop(view_render, "engine", text="")
  
  
  class RENDER_PT_render(RenderButtonsPanel, Panel):
      bl_label = "Render"
 -    COMPAT_ENGINES = {'BLENDER_RENDER'}
 +    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  
      def draw(self, context):
          layout = self.layout
  
  class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
      bl_label = "Dimensions"
 -    COMPAT_ENGINES = {'BLENDER_RENDER'}
 +    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  
      _frame_rate_args_prev = None
      _preset_class = None
@@@ -228,10 -207,8 +228,10 @@@ class RENDER_PT_motion_blur(RenderButto
  
      @classmethod
      def poll(cls, context):
 -        rd = context.scene.render
 -        return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES)
 +        scene = context.scene
 +        rd = scene.render
 +        view_render = scene.view_render
 +        return not rd.use_full_sample and (view_render.engine in cls.COMPAT_ENGINES)
  
      def draw_header(self, context):
          rd = context.scene.render
@@@ -322,7 -299,7 +322,7 @@@ class RENDER_PT_performance(RenderButto
  class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
      bl_label = "Post Processing"
      bl_options = {'DEFAULT_CLOSED'}
 -    COMPAT_ENGINES = {'BLENDER_RENDER'}
 +    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  
      def draw(self, context):
          layout = self.layout
  
          split.prop(rd, "dither_intensity", text="Dither", slider=True)
  
 +        if context.scene.view_render.engine == 'BLENDER_EEVEE':
 +            return
 +
          layout.separator()
  
          split = layout.split()
  class RENDER_PT_stamp(RenderButtonsPanel, Panel):
      bl_label = "Metadata"
      bl_options = {'DEFAULT_CLOSED'}
 -    COMPAT_ENGINES = {'BLENDER_RENDER'}
 +    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  
      def draw(self, context):
          layout = self.layout
  
  class RENDER_PT_output(RenderButtonsPanel, Panel):
      bl_label = "Output"
 -    COMPAT_ENGINES = {'BLENDER_RENDER'}
 +    COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
  
      def draw(self, context):
          layout = self.layout
@@@ -469,7 -443,8 +469,8 @@@ class RENDER_PT_encoding(RenderButtonsP
              layout.prop(ffmpeg, "use_lossless_output")
  
          # Output quality
-         if needs_codec and ffmpeg.codec in {'H264', 'MPEG4'}:
+         use_crf = needs_codec and ffmpeg.codec in {'H264', 'MPEG4'}
+         if use_crf:
              layout.prop(ffmpeg, "constant_rate_factor")
  
          # Encoding speed
          pbox.prop(ffmpeg, "max_b_frames", text="")
          pbox.enabled = ffmpeg.use_max_b_frames
  
-         if ffmpeg.constant_rate_factor == 'NONE':
+         if not use_crf or ffmpeg.constant_rate_factor == 'NONE':
              split = layout.split()
              col = split.column()
              col.label(text="Rate:")
@@@ -580,332 -555,10 +581,332 @@@ class RENDER_PT_bake(RenderButtonsPanel
              sub.prop(rd, "bake_user_scale", text="User Scale")
  
  
 +class RENDER_PT_clay_layer_settings(RenderButtonsPanel, Panel):
 +    bl_label = "Clay Layer Settings"
 +    COMPAT_ENGINES = {'BLENDER_CLAY'}
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        props = context.scene.layer_properties['BLENDER_CLAY']
 +
 +        col = layout.column()
 +        col.prop(props, "ssao_samples")
 +
 +
 +class RENDER_PT_clay_collection_settings(RenderButtonsPanel, Panel):
 +    bl_label = "Clay Collection Settings"
 +    COMPAT_ENGINES = {'BLENDER_CLAY'}
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        props = context.scene.collection_properties['BLENDER_CLAY']
 +
 +        col = layout.column()
 +        col.template_icon_view(props, "matcap_icon")
 +        col.prop(props, "matcap_rotation")
 +        col.prop(props, "matcap_hue")
 +        col.prop(props, "matcap_saturation")
 +        col.prop(props, "matcap_value")
 +        col.prop(props, "ssao_factor_cavity")
 +        col.prop(props, "ssao_factor_edge")
 +        col.prop(props, "ssao_distance")
 +        col.prop(props, "ssao_attenuation")
 +        col.prop(props, "hair_brightness_randomness")
 +
 +
 +class RENDER_PT_eevee_ambient_occlusion(RenderButtonsPanel, Panel):
 +    bl_label = "Ambient Occlusion"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "gtao_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        layout.active = props.gtao_enable
 +        col = layout.column()
 +        col.prop(props, "gtao_use_bent_normals")
 +        col.prop(props, "gtao_bounce")
 +        col.prop(props, "gtao_distance")
 +        col.prop(props, "gtao_factor")
 +        col.prop(props, "gtao_quality")
 +
 +
 +class RENDER_PT_eevee_motion_blur(RenderButtonsPanel, Panel):
 +    bl_label = "Motion Blur"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "motion_blur_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        layout.active = props.motion_blur_enable
 +        col = layout.column()
 +        col.prop(props, "motion_blur_samples")
 +        col.prop(props, "motion_blur_shutter")
 +
 +
 +class RENDER_PT_eevee_depth_of_field(RenderButtonsPanel, Panel):
 +    bl_label = "Depth of Field"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "dof_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        layout.active = props.dof_enable
 +        col = layout.column()
 +        col.prop(props, "bokeh_max_size")
 +        col.prop(props, "bokeh_threshold")
 +
 +
 +class RENDER_PT_eevee_bloom(RenderButtonsPanel, Panel):
 +    bl_label = "Bloom"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "bloom_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        layout.active = props.bloom_enable
 +        col = layout.column()
 +        col.prop(props, "bloom_threshold")
 +        col.prop(props, "bloom_knee")
 +        col.prop(props, "bloom_radius")
 +        col.prop(props, "bloom_color")
 +        col.prop(props, "bloom_intensity")
 +        col.prop(props, "bloom_clamp")
 +
 +
 +class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel):
 +    bl_label = "Volumetric"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "volumetric_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        layout.active = props.volumetric_enable
 +        col = layout.column()
 +        col.prop(props, "volumetric_start")
 +        col.prop(props, "volumetric_end")
 +        col.prop(props, "volumetric_tile_size")
 +        col.prop(props, "volumetric_samples")
 +        col.prop(props, "volumetric_sample_distribution")
 +        col.prop(props, "volumetric_lights")
 +        col.prop(props, "volumetric_light_clamp")
 +        col.prop(props, "volumetric_shadows")
 +        col.prop(props, "volumetric_shadow_samples")
 +        col.prop(props, "volumetric_colored_transmittance")
 +
 +
 +class RENDER_PT_eevee_subsurface_scattering(RenderButtonsPanel, Panel):
 +    bl_label = "Subsurface Scattering"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "sss_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        col = layout.column()
 +        col.prop(props, "sss_samples")
 +        col.prop(props, "sss_jitter_threshold")
 +        col.prop(props, "sss_separate_albedo")
 +
 +
 +class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):
 +    bl_label = "Screen Space Reflections"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw_header(self, context):
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +        self.layout.prop(props, "ssr_enable", text="")
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        col = layout.column()
 +        col.active = props.ssr_enable
 +        col.prop(props, "ssr_refraction")
 +        col.prop(props, "ssr_halfres")
 +        col.prop(props, "ssr_quality")
 +        col.prop(props, "ssr_max_roughness")
 +        col.prop(props, "ssr_thickness")
 +        col.prop(props, "ssr_border_fade")
 +        col.prop(props, "ssr_firefly_fac")
 +
 +
 +class RENDER_PT_eevee_shadows(RenderButtonsPanel, Panel):
 +    bl_label = "Shadows"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        col = layout.column()
 +        col.prop(props, "shadow_method")
 +        col.prop(props, "shadow_size")
 +        col.prop(props, "shadow_high_bitdepth")
 +
 +
 +class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel):
 +    bl_label = "Sampling"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        col = layout.column()
 +        col.prop(props, "taa_samples")
 +        col.prop(props, "taa_render_samples")
 +
 +
 +class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel):
 +    bl_label = "Indirect Lighting"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        props = scene.layer_properties['BLENDER_EEVEE']
 +
 +        col = layout.column()
 +        col.prop(props, "gi_diffuse_bounces")
 +        col.prop(props, "gi_cubemap_resolution")
 +        col.prop(props, "gi_visibility_resolution")
 +
 +
 +class RENDER_PT_eevee_film(RenderButtonsPanel, Panel):
 +    bl_label = "Film"
 +    bl_options = {'DEFAULT_CLOSED'}
 +    COMPAT_ENGINES = {'BLENDER_EEVEE'}
 +
 +    @classmethod
 +    def poll(cls, context):
 +        scene = context.scene
 +        return scene and (scene.view_render.engine in cls.COMPAT_ENGINES)
 +
 +    def draw(self, context):
 +        layout = self.layout
 +        scene = context.scene
 +        rd = scene.render
 +
 +        split = layout.split()
 +
 +        col = split.column()
 +        col.prop(rd, "filter_size")
 +
 +        col = split.column()
 +        col.prop(rd, "alpha_mode", text="Alpha")
 +
 +
  classes = (
      RENDER_MT_presets,
      RENDER_MT_ffmpeg_presets,
      RENDER_MT_framerate_presets,
 +    RENDER_PT_context,
      RENDER_PT_render,
      RENDER_PT_dimensions,
      RENDER_PT_antialiasing,
      RENDER_PT_output,
      RENDER_PT_encoding,
      RENDER_PT_bake,
 +    RENDER_PT_clay_layer_settings,
 +    RENDER_PT_clay_collection_settings,
 +    RENDER_PT_eevee_sampling,
 +    RENDER_PT_eevee_film,
 +    RENDER_PT_eevee_shadows,
 +    RENDER_PT_eevee_indirect_lighting,
 +    RENDER_PT_eevee_subsurface_scattering,
 +    RENDER_PT_eevee_screen_space_reflections,
 +    RENDER_PT_eevee_ambient_occlusion,
 +    RENDER_PT_eevee_volumetric,
 +    RENDER_PT_eevee_motion_blur,
 +    RENDER_PT_eevee_depth_of_field,
 +    RENDER_PT_eevee_bloom,
  )
  
  if __name__ == "__main__":  # only for live edit.
index a8fa73654a410f2bab4be5047bd78222eb4abdfe,92518ba73e421892c338e8277f35b7a17e142065..f3b45303e35a59844b975bbc856ba00acde2f3b6
  #include "BLI_task.h"
  #include "BLI_ghash.h"
  
 -extern "C" {
 -#include "BKE_depsgraph.h"
 -#include "BKE_global.h"
 -} /* extern "C" */
 +#include "DNA_object_types.h"
  
  #include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_query.h"
  
  #include "atomic_ops.h"
  
@@@ -66,11 -68,13 +66,11 @@@ namespace DEG 
  static void schedule_children(TaskPool *pool,
                                Depsgraph *graph,
                                OperationDepsNode *node,
 -                              const unsigned int layers,
                                const int thread_id);
  
  struct DepsgraphEvalState {
        EvaluationContext *eval_ctx;
        Depsgraph *graph;
 -      unsigned int layers;
        bool do_stats;
  };
  
@@@ -94,12 -98,13 +94,12 @@@ static void deg_task_run_func(TaskPool 
        }
        /* Schedule children. */
        BLI_task_pool_delayed_push_begin(pool, thread_id);
 -      schedule_children(pool, state->graph, node, state->layers, thread_id);
 +      schedule_children(pool, state->graph, node, thread_id);
        BLI_task_pool_delayed_push_end(pool, thread_id);
  }
  
  typedef struct CalculatePengindData {
        Depsgraph *graph;
 -      unsigned int layers;
  } CalculatePengindData;
  
  static void calculate_pending_func(
  {
        CalculatePengindData *data = (CalculatePengindData *)data_v;
        Depsgraph *graph = data->graph;
 -      unsigned int layers = data->layers;
        OperationDepsNode *node = graph->operations[i];
 -      IDDepsNode *id_node = node->owner->owner;
  
        node->num_links_pending = 0;
        node->scheduled = false;
  
        /* count number of inputs that need updates */
 -      if ((id_node->layers & layers) != 0 &&
 -          (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
 -      {
 +      if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
                foreach (DepsRelation *rel, node->inlinks) {
                        if (rel->from->type == DEG_NODE_TYPE_OPERATION &&
                            (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
                        {
                                OperationDepsNode *from = (OperationDepsNode *)rel->from;
 -                              IDDepsNode *id_from_node = from->owner->owner;
 -                              if ((id_from_node->layers & layers) != 0 &&
 -                                  (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
 -                              {
 +                              if ((from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
                                        ++node->num_links_pending;
                                }
                        }
        }
  }
  
 -static void calculate_pending_parents(Depsgraph *graph, unsigned int layers)
 +static void calculate_pending_parents(Depsgraph *graph)
  {
        const int num_operations = graph->operations.size();
        CalculatePengindData data;
        data.graph = graph;
 -      data.layers = layers;
        ParallelRangeSettings settings;
        BLI_parallel_range_settings_defaults(&settings);
        settings.min_iter_per_thread = 1024;
  static void initialize_execution(DepsgraphEvalState *state, Depsgraph *graph)
  {
        const bool do_stats = state->do_stats;
 -      calculate_pending_parents(graph, state->layers);
 +      calculate_pending_parents(graph);
        /* Clear tags and other things which needs to be clear. */
        foreach (OperationDepsNode *node, graph->operations) {
                node->done = 0;
   *   dec_parents: Decrement pending parents count, true when child nodes are
   *                scheduled after a task has been completed.
   */
 -static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
 +static void schedule_node(TaskPool *pool, Depsgraph *graph,
                            OperationDepsNode *node, bool dec_parents,
                            const int thread_id)
  {
 -      unsigned int id_layers = node->owner->owner->layers;
 -
 -      if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0 &&
 -          (id_layers & layers) != 0)
 -      {
 +      if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0) {
                if (dec_parents) {
                        BLI_assert(node->num_links_pending > 0);
                        atomic_sub_and_fetch_uint32(&node->num_links_pending, 1);
                        if (!is_scheduled) {
                                if (node->is_noop()) {
                                        /* skip NOOP node, schedule children right away */
 -                                      schedule_children(pool, graph, node, layers, thread_id);
 +                                      schedule_children(pool, graph, node, thread_id);
                                }
                                else {
                                        /* children are scheduled once this task is completed */
        }
  }
  
 -static void schedule_graph(TaskPool *pool,
 -                           Depsgraph *graph,
 -                           const unsigned int layers)
 +static void schedule_graph(TaskPool *pool, Depsgraph *graph)
  {
        foreach (OperationDepsNode *node, graph->operations) {
 -              schedule_node(pool, graph, layers, node, false, 0);
 +              schedule_node(pool, graph, node, false, 0);
        }
  }
  
  static void schedule_children(TaskPool *pool,
                                Depsgraph *graph,
                                OperationDepsNode *node,
 -                              const unsigned int layers,
                                const int thread_id)
  {
        foreach (DepsRelation *rel, node->outlinks) {
                }
                schedule_node(pool,
                              graph,
 -                            layers,
                              child,
                              (rel->flag & DEPSREL_FLAG_CYCLIC) == 0,
                              thread_id);
   * \note Time sources should be all valid!
   */
  void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
 -                             Depsgraph *graph,
 -                             const unsigned int layers)
 +                             Depsgraph *graph)
  {
        /* Nothing to update, early out. */
        if (BLI_gset_len(graph->entry_tags) == 0) {
                return;
        }
 -      DEG_DEBUG_PRINTF(EVAL, "%s: layers:%u, graph->layers:%u\n",
 -                       __func__,
 -                       layers,
 -                       graph->layers);
        const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
+       const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0;
        /* Set time for the current graph evaluation context. */
        TimeSourceDepsNode *time_src = graph->find_time_source();
 +      eval_ctx->depsgraph = (::Depsgraph *)graph;
 +      eval_ctx->view_layer = DEG_get_evaluated_view_layer((::Depsgraph *)graph);
        eval_ctx->ctime = time_src->cfra;
        /* Set up evaluation context for depsgraph itself. */
        DepsgraphEvalState state;
        state.eval_ctx = eval_ctx;
        state.graph = graph;
 -      state.layers = layers;
        state.do_stats = do_time_debug;
        /* Set up task scheduler and pull for threaded evaluation. */
        TaskScheduler *task_scheduler;
        /* Prepare all nodes for evaluation. */
        initialize_execution(&state, graph);
        /* Do actual evaluation now. */
 -      schedule_graph(task_pool, graph, layers);
 +      schedule_graph(task_pool, graph);
        BLI_task_pool_work_and_wait(task_pool);
        BLI_task_pool_free(task_pool);
        /* Finalize statistics gathering. This is because we only gather single
        if (need_free_scheduler) {
                BLI_task_scheduler_free(task_scheduler);
        }
+       if (do_time_debug) {
+               printf("Depsgraph updated in %f seconds.\n",
+                      PIL_check_seconds_timer() - start_time);
+       }
  }
  
  }  // namespace DEG
index 6c8779202e9713785ef8dfee6201cd8e381ac0db,9a4a0eecfcdabba420e34dac95b3221f323eaffb..bb3c4164fc16fd216e0374f69e91f21face4dec7
@@@ -50,7 -50,6 +50,7 @@@
  #include "BKE_context.h"
  #include "BKE_global.h"
  #include "BKE_report.h"
 +#include "BKE_object.h"
  
  #include "RNA_access.h"
  #include "RNA_define.h"
@@@ -139,16 -138,17 +139,16 @@@ void ED_armature_transform(struct bArma
  
  /* exported for use in editors/object/ */
  /* 0 == do center, 1 == center new, 2 == center cursor */
 -void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
 +void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int around)
  {
 -      Object *obedit = scene->obedit; // XXX get from context
 +      const bool is_editmode = BKE_object_is_in_editmode(ob);
        EditBone *ebone;
        bArmature *arm = ob->data;
        float cent[3];
  
        /* Put the armature into editmode */
 -      if (ob != obedit) {
 +      if (is_editmode == false) {
                ED_armature_to_edit(arm);
 -              obedit = NULL; /* we cant use this so behave as if there is no obedit */
        }
  
        /* Find the centerpoint */
        }
        
        /* Turn the list into an armature */
 -      if (obedit == NULL) {
 +      if (is_editmode == false) {
                ED_armature_from_edit(arm);
                ED_armature_edit_free(arm);
        }
  
        /* Adjust object location for new centerpoint */
 -      if (centermode && obedit == NULL) {
 +      if (centermode && (is_editmode == false)) {
                mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
                add_v3_v3(ob->loc, cent);
        }
@@@ -1458,8 -1458,9 +1458,9 @@@ static int armature_dissolve_selected_e
                if (ebone->flag & BONE_DONE) {
                        copy_v3_v3(ebone->parent->tail, ebone->tail);
                        ebone->parent->rad_tail = ebone->rad_tail;
+                       SET_FLAG_FROM_TEST(ebone->parent->flag, ebone->flag & BONE_TIPSEL, BONE_TIPSEL);
  
-                       ED_armature_edit_bone_remove(arm, ebone);
+                       ED_armature_edit_bone_remove_ex(arm, ebone, false);
                        changed = true;
                }
        }
                for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
                        if (ebone->parent &&
                            ebone->parent->temp.ebone &&
-                           (ebone->flag & BONE_CONNECTED) == 0)
+                           (ebone->flag & BONE_CONNECTED))
                        {
-                               ebone->flag |= BONE_CONNECTED;
-                               ebone->rad_head = ebone->parent->rad_head;
+                               ebone->rad_head = ebone->parent->rad_tail;
                        }
                }
  
index 23a49d282e1ba2e5ebe6cf1217fae744b7d6c10e,3928cb2d85d798e3db9fe8c7205203e7da831e9c..eaff0b10a028f18e06441e1d83dc49ed05be5d3d
  #include "BKE_armature.h"
  #include "BKE_context.h"
  #include "BKE_deform.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_global.h"
  #include "BKE_idprop.h"
  #include "BKE_main.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "ED_armature.h"
  #include "ED_util.h"
  
@@@ -134,7 -133,10 +134,10 @@@ void bone_free(bArmature *arm, EditBon
        BLI_freelinkN(arm->edbo, bone);
  }
  
- void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
+ /**
+  * \param clear_connected: When false caller is responsible for keeping the flag in a valid state.
+  */
+ void ED_armature_edit_bone_remove_ex(bArmature *arm, EditBone *exBone, bool clear_connected)
  {
        EditBone *curBone;
  
        for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
                if (curBone->parent == exBone) {
                        curBone->parent = exBone->parent;
-                       curBone->flag &= ~BONE_CONNECTED;
+                       if (clear_connected) {
+                               curBone->flag &= ~BONE_CONNECTED;
+                       }
                }
        }
  
        bone_free(arm, exBone);
  }
  
+ void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
+ {
+       ED_armature_edit_bone_remove_ex(arm, exBone, true);
+ }
  bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child)
  {
        for (ebone_child = ebone_child->parent; ebone_child; ebone_child = ebone_child->parent) {
@@@ -675,7 -684,7 +685,7 @@@ void ED_armature_from_edit(bArmature *a
                }
        }
        
 -      DAG_id_tag_update(&arm->id, 0);
 +      DEG_id_tag_update(&arm->id, 0);
  }
  
  void ED_armature_edit_free(struct bArmature *arm)
index 51d8f8edb448411938c21ba7ee5210bd220b5999,91c9a36c31f589e756550384a0e0863f38639199..a35380ca547bb57c900f0eec72dd9008b042fee6
@@@ -39,7 -39,6 +39,7 @@@ struct Base
  struct bContext;
  struct Bone;
  struct bPoseChannel;
 +struct EvaluationContext;
  struct IDProperty;
  struct ListBase;
  struct MeshDeformModifierData;
@@@ -47,11 -46,9 +47,11 @@@ struct DerivedMesh
  struct Object;
  struct ReportList;
  struct Scene;
 +struct ViewLayer;
  struct ViewContext;
  struct wmKeyConfig;
  struct wmOperator;
 +struct Main;
  
  typedef struct EditBone {
        struct EditBone *next, *prev;
        
        short segments;
  
 +      /* Used for display */
 +      float disp_mat[4][4];  /*  in Armature space, rest pos matrix */
 +      float disp_tail_mat[4][4];  /*  in Armature space, rest pos matrix */
 +      /* 32 == MAX_BBONE_SUBDIV */
 +      float disp_bbone_mat[32][4][4]; /*  in Armature space, rest pos matrix */
 +
        /* Used to store temporary data */
        union {
                struct EditBone *ebone;
@@@ -142,8 -133,7 +142,8 @@@ void ED_armature_deselect_all(struct Ob
  void ED_armature_deselect_all_visible(struct Object *obedit);
  
  bool ED_do_pose_selectbuffer(
 -        struct Scene *scene, struct Base *base, const unsigned int *buffer, short hits,
 +        const struct EvaluationContext *eval_ctx,
 +        struct ViewLayer *view_layer, struct Base *base, const unsigned int *buffer, short hits,
          bool extend, bool deselect, bool toggle, bool do_nearest);
  bool ED_armature_select_pick(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
  int join_armature_exec(struct bContext *C, struct wmOperator *op);
@@@ -156,6 -146,8 +156,8 @@@ void ED_armature_validate_active(struc
  
  EditBone *ED_armature_edit_bone_add_primitive(struct Object *obedit_arm, float length, bool view_aligned);
  EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name);
+ void ED_armature_edit_bone_remove_ex(struct bArmature *arm, EditBone *exBone, bool clear_connected);
  void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone);
  
  bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child);
@@@ -168,7 -160,7 +170,7 @@@ void ED_armature_ebone_from_mat3(EditBo
  void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]);
  
  void transform_armature_mirror_update(struct Object *obedit);
 -void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
 +void ED_armature_origin_set(struct Object *ob, float cursor[3], int centermode, int around);
  
  void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props);
  void ED_armature_apply_transform(struct Object *ob, float mat[4][4], const bool do_props);
@@@ -178,9 -170,8 +180,9 @@@ void ED_armature_transform(struct bArma
  #define ARM_GROUPS_ENVELOPE 2
  #define ARM_GROUPS_AUTO     3
  
 -void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob,
 -                                  struct Object *par, const int mode, const bool mirror);
 +void create_vgroups_from_armature(
 +        struct ReportList *reports, const struct EvaluationContext *eval_ctx, struct Scene *scene,
 +        struct Object *ob, struct Object *par, const int mode, const bool mirror);
  
  /* if bone is already in list, pass it as param to ignore it */
  void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
@@@ -206,7 -197,7 +208,7 @@@ void ED_armature_exit_posemode(struct b
  void ED_armature_enter_posemode(struct bContext *C, struct Base *base);
  void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility);
  void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
 -void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob);
 +void ED_pose_recalculate_paths(struct bContext *C, struct Scene *scene, struct Object *ob);
  struct Object *ED_pose_object_from_context(struct bContext *C);
  
  /* sketch */
index 06028cbc6c746ea13c3033c4d1d45e3223090e8b,6573ae0f4a1eb4b30ab92392a8914a9e6e8bc843..a173281b7d05439b0ed0682cd6ae0192f2df9d23
@@@ -38,7 -38,6 +38,7 @@@
  #include "DNA_listBase.h"     
  #include "DNA_screen_types.h"
  #include "DNA_windowmanager_types.h"
 +#include "DNA_workspace_types.h"
  
  #include "MEM_guardedalloc.h"
  
  
  #include "BKE_blender.h"
  #include "BKE_context.h"
 +#include "BKE_icons.h"
  #include "BKE_library.h"
  #include "BKE_global.h"
  #include "BKE_main.h"
 -
 +#include "BKE_screen.h"
 +#include "BKE_workspace.h"
  
  #include "RNA_access.h"
 +#include "RNA_define.h"
 +#include "RNA_enum_types.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
  #include "wm.h"
  #include "wm_draw.h"
  #include "wm_window.h"
 -#include "wm_subwindow.h"
  #include "wm_event_system.h"
  
 +#include "ED_scene.h"
  #include "ED_screen.h"
  #include "ED_fileselect.h"
  
  #include "UI_interface.h"
 -#include "UI_resources.h"
 +#include "UI_interface_icons.h"
  
  #include "PIL_time.h"
  
 +#include "GPU_batch.h"
  #include "GPU_draw.h"
  #include "GPU_extensions.h"
  #include "GPU_init_exit.h"
 -#include "GPU_glew.h"
 +#include "GPU_immediate.h"
  #include "BLF_api.h"
  
 +#include "UI_resources.h"
 +
 +#include "../../../intern/gawain/gawain/gwn_context.h"
 +
  /* for assert */
  #ifndef NDEBUG
  #  include "BLI_threads.h"
@@@ -172,23 -162,12 +172,23 @@@ static void wm_window_check_position(rc
  }
  
  
 -static void wm_ghostwindow_destroy(wmWindow *win) 
 +static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
  {
        if (win->ghostwin) {
 +              /* We need this window's opengl context active to discard it. */
 +              GHOST_ActivateWindowDrawingContext(win->ghostwin);
 +              GWN_context_active_set(win->gwnctx);
 +
 +              /* Delete local gawain objects.  */
 +              GWN_context_discard(win->gwnctx);
 +
                GHOST_DisposeWindow(g_system, win->ghostwin);
                win->ghostwin = NULL;
 -              win->multisamples = 0;
 +              win->gwnctx = NULL;
 +
 +              /* prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
 +              wm->windrawable = NULL;
 +              wm->winactive = NULL;
        }
  }
  
@@@ -207,6 -186,11 +207,6 @@@ void wm_window_free(bContext *C, wmWind
                        CTX_wm_window_set(C, NULL);
        }
  
 -      /* always set drawable and active to NULL,
 -       * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
 -      wm->windrawable = NULL;
 -      wm->winactive = NULL;
 -
        /* end running jobs, a job end also removes its timer */
        for (wt = wm->timers.first; wt; wt = wtnext) {
                wtnext = wt->next;
        if (win->eventstate) MEM_freeN(win->eventstate);
        
        wm_event_free_all(win);
 -      wm_subwindows_free(win);
  
        wm_draw_data_free(win);
  
 -      wm_ghostwindow_destroy(win);
 +      wm_ghostwindow_destroy(wm, win);
  
 +      BKE_workspace_instance_hook_free(G.main, win->workspace_hook);
        MEM_freeN(win->stereo3d_format);
  
        MEM_freeN(win);
@@@ -250,57 -234,35 +250,57 @@@ static int find_free_winid(wmWindowMana
  /* don't change context itself */
  wmWindow *wm_window_new(bContext *C)
  {
 +      Main *bmain = CTX_data_main(C);
        wmWindowManager *wm = CTX_wm_manager(C);
        wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
 -      
 +
        BLI_addtail(&wm->windows, win);
        win->winid = find_free_winid(wm);
  
        win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
 +      win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
  
        return win;
  }
  
 +/**
 + * A higher level version of copy that tests the new window can be added.
 + */
 +static wmWindow *wm_window_new_test(bContext *C)
 +{
 +      wmWindow *win = wm_window_new(C);
 +
 +      WM_check(C);
 +
 +      if (win->ghostwin) {
 +              WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
 +              return win;
 +      }
 +      else {
 +              wmWindowManager *wm = CTX_wm_manager(C);
 +              wm_window_close(C, wm, win);
 +              return NULL;
 +      }
 +}
  
  /* part of wm_window.c api */
 -wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
 +wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout)
  {
        wmWindow *win_dst = wm_window_new(C);
 -      
 +      WorkSpace *workspace = WM_window_get_active_workspace(win_src);
 +      WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
 +      Scene *scene = WM_window_get_active_scene(win_src);
 +      WorkSpaceLayout *layout_new;
 +
        win_dst->posx = win_src->posx + 10;
        win_dst->posy = win_src->posy;
        win_dst->sizex = win_src->sizex;
        win_dst->sizey = win_src->sizey;
 -      
 -      /* duplicate assigns to window */
 -      win_dst->screen = ED_screen_duplicate(win_dst, win_src->screen);
 -      BLI_strncpy(win_dst->screenname, win_dst->screen->id.name + 2, sizeof(win_dst->screenname));
 -      win_dst->screen->winid = win_dst->winid;
  
 -      win_dst->screen->do_refresh = true;
 -      win_dst->screen->do_draw = true;
 +      win_dst->scene = scene;
 +      WM_window_set_active_workspace(win_dst, workspace);
 +      layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old;
 +      WM_window_set_active_layout(win_dst, workspace, layout_new);
  
        win_dst->drawmethod = U.wmdrawmethod;
  
   * A higher level version of copy that tests the new window can be added.
   * (called from the operator directly)
   */
 -wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src)
 +wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout)
  {
        wmWindowManager *wm = CTX_wm_manager(C);
        wmWindow *win_dst;
  
 -      win_dst = wm_window_copy(C, win_src);
 +      win_dst = wm_window_copy(C, win_src, duplicate_layout);
  
        WM_check(C);
  
@@@ -366,6 -328,8 +366,8 @@@ static void wm_block_confirm_quit_save(
  
        WM_operator_properties_create_ptr(&props_ptr, ot);
        RNA_boolean_set(&props_ptr, "exit", true);
+       /* No need for second confirmation popup. */
+       RNA_boolean_set(&props_ptr, "check_existing", false);
        WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
        WM_operator_properties_free(&props_ptr);
  }
@@@ -462,7 -426,7 +464,7 @@@ void wm_window_close(bContext *C, wmWin
        for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
                if (tmpwin == win)
                        continue;
 -              if (tmpwin->screen->temp == 0)
 +              if (WM_window_is_temp_screen(tmpwin) == false)
                        break;
        }
  
                WM_exit(C);
        }
        else {
 -              /* We're just closing a window */
 -              bScreen *screen = win->screen;
 -              
 +              bScreen *screen = WM_window_get_active_screen(win);
 +              WorkSpace *workspace = WM_window_get_active_workspace(win);
 +              WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
 +
                BLI_remlink(&wm->windows, win);
                
                wm_draw_window_clear(win);
  
                /* for regular use this will _never_ be NULL,
                 * however we may be freeing an improperly initialized window. */
 -              if (win->screen) {
 -                      ED_screen_exit(C, win, win->screen);
 +              if (screen) {
 +                      ED_screen_exit(C, win, screen);
                }
 -              
 +
 +              if (tmpwin) {
 +                      gpu_batch_presets_reset();
 +                      immDeactivate();
 +              }
 +
                wm_window_free(C, wm, win);
 -      
 +
 +              /* keep imediatemode active before the next `wm_window_make_drawable` call */
 +              if (tmpwin) {
 +                      GHOST_ActivateWindowDrawingContext(tmpwin->ghostwin);
 +                      GWN_context_active_set(tmpwin->gwnctx);
 +                      immActivate();
 +              }
 +
                /* if temp screen, delete it after window free (it stops jobs that can access it) */
                if (screen && screen->temp) {
                        Main *bmain = CTX_data_main(C);
 -                      BKE_libblock_free(bmain, screen);
 +
 +                      BLI_assert(BKE_workspace_layout_screen_get(layout) == screen);
 +                      BKE_workspace_layout_remove(bmain, workspace, layout);
                }
 -      }               
 +      }
  }
  
  void wm_window_title(wmWindowManager *wm, wmWindow *win)
  {
 -      if (win->screen && win->screen->temp) {
 +      if (WM_window_is_temp_screen(win)) {
                /* nothing to do for 'temp' windows,
                 * because WM_window_open_temp always sets window title  */
        }
@@@ -602,8 -551,16 +604,8 @@@ static void wm_window_ghostwindow_add(w
  {
        GHOST_WindowHandle ghostwin;
        GHOST_GLSettings glSettings = {0};
 -      static int multisamples = -1;
        int scr_w, scr_h, posy;
        
 -      /* force setting multisamples only once, it requires restart - and you cannot 
 -       * mix it, either all windows have it, or none (tested in OSX opengl) */
 -      if (multisamples == -1)
 -              multisamples = U.ogl_multisamples;
 -
 -      glSettings.numOfAASamples = multisamples;
 -
        /* a new window is created when pageflip mode is required for a window */
        if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
                glSettings.flags |= GHOST_glStereoVisual;
                                      (GHOST_TWindowState)win->windowstate,
                                      GHOST_kDrawingContextTypeOpenGL,
                                      glSettings);
 -      
 +
        if (ghostwin) {
                GHOST_RectangleHandle bounds;
 +
 +              win->gwnctx = GWN_context_create();
                
                /* the new window has already been made drawable upon creation */
                wm->windrawable = win;
                if (win->eventstate == NULL)
                        win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
  
 -              /* store multisamples window was created with, in case user prefs change */
 -              win->multisamples = multisamples;
 -              
                /* store actual window size in blender window */
                bounds = GHOST_GetClientBounds(win->ghostwin);
  
@@@ -821,10 -779,8 +823,10 @@@ wmWindow *WM_window_open(bContext *C, c
   */
  wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
  {
 +      Main *bmain = CTX_data_main(C);
        wmWindow *win_prev = CTX_wm_window(C);
        wmWindow *win;
 +      bScreen *screen;
        ScrArea *sa;
        Scene *scene = CTX_data_scene(C);
        const char *title;
        
        /* test if we have a temp screen already */
        for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
 -              if (win->screen->temp)
 +              if (WM_window_is_temp_screen(win))
                        break;
        
        /* add new window? */
                win->posy = rect.ymin;
        }
  
 +      screen = WM_window_get_active_screen(win);
 +
        win->sizex = BLI_rcti_size_x(&rect);
        win->sizey = BLI_rcti_size_y(&rect);
  
                wm_window_set_size(win, win->sizex, win->sizey);
                wm_window_raise(win);
        }
 -      
 -      if (win->screen == NULL) {
 -              /* add new screen */
 -              win->screen = ED_screen_add(win, scene, "temp");
 +
 +      if (WM_window_get_active_workspace(win) == NULL) {
 +              WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
 +              WM_window_set_active_workspace(win, workspace);
        }
 -      else {
 -              /* switch scene for rendering */
 -              if (win->screen->scene != scene)
 -                      ED_screen_set_scene(C, win->screen, scene);
 +
 +      if (screen == NULL) {
 +              /* add new screen layout */
 +              WorkSpace *workspace = WM_window_get_active_workspace(win);
 +              WorkSpaceLayout *layout = ED_workspace_layout_add(workspace, win, "temp");
 +
 +              screen = BKE_workspace_layout_screen_get(layout);
 +              WM_window_set_active_layout(win, workspace, layout);
        }
  
 -      win->screen->temp = 1; 
 -      
 +      if (win->scene == NULL) {
 +              win->scene = scene;
 +      }
 +      /* In case we reuse an already existing temp window (see win lookup above). */
 +      else if (WM_window_get_active_scene(win) != scene) {
 +              WM_window_change_active_scene(bmain, C, win, scene);
 +      }
 +
 +      screen->temp = 1;
 +
        /* make window active, and validate/resize */
        CTX_wm_window_set(C, win);
        WM_check(C);
         */
  
        /* ensure it shows the right spacetype editor */
 -      sa = win->screen->areabase.first;
 +      sa = screen->areabase.first;
        CTX_wm_area_set(C, sa);
        
        if (type == WM_WINDOW_RENDER) {
                ED_area_newspace(C, sa, SPACE_USERPREF, false);
        }
        
 -      ED_screen_set(C, win->screen);
 +      ED_screen_change(C, screen);
        ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
        
        if (sa->spacetype == SPACE_IMAGE)
@@@ -950,107 -892,17 +952,107 @@@ int wm_window_close_exec(bContext *C, w
        return OPERATOR_FINISHED;
  }
  
 -/* operator callback */
 -int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
 +static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *workspace)
 +{
 +      ListBase *listbase = BKE_workspace_layouts_get(workspace);
 +      const int layout_id = RNA_enum_get(op->ptr, "screen");
 +      int i = 0;
 +
 +      for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
 +              if (i++ == layout_id) {
 +                      return layout;
 +              }
 +      }
 +
 +      BLI_assert(0);
 +      return NULL;
 +}
 +
 +/* new window operator callback */
 +int wm_window_new_exec(bContext *C, wmOperator *op)
  {
        wmWindow *win_src = CTX_wm_window(C);
 -      bool ok;
 +      WorkSpace *workspace = WM_window_get_active_workspace(win_src);
 +      WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace);
 +      bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
 +      wmWindow *win_dst;
 +
 +      if ((win_dst = wm_window_new_test(C))) {
 +              if (screen_new->winid) {
 +                      /* layout/screen is already used, duplicate it */
 +                      layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst);
 +                      screen_new = BKE_workspace_layout_screen_get(layout_new);
 +              }
 +              /* New window with a different screen but same workspace */
 +              WM_window_set_active_workspace(win_dst, workspace);
 +              WM_window_set_active_screen(win_dst, workspace, screen_new);
 +              win_dst->scene = win_src->scene;
 +              screen_new->winid = win_dst->winid;
 +              CTX_wm_window_set(C, win_dst);
 +              ED_screen_refresh(CTX_wm_manager(C), win_dst);
 +      }
  
 -      ok = (wm_window_copy_test(C, win_src) != NULL);
 +      return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +}
  
 -      return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
 +{
 +      wmWindow *win = CTX_wm_window(C);
 +      WorkSpace *workspace = WM_window_get_active_workspace(win);
 +      ListBase *listbase = BKE_workspace_layouts_get(workspace);
 +
 +      if (BLI_listbase_count_ex(listbase, 2) == 1) {
 +              RNA_enum_set(op->ptr, "screen", 0);
 +              return wm_window_new_exec(C, op);
 +      }
 +      else {
 +              return WM_enum_search_invoke_previews(C, op, 6, 2);
 +      }
  }
  
 +const EnumPropertyItem *wm_window_new_screen_itemf(
 +        bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free)
 +{
 +      if (C == NULL) {
 +              return DummyRNA_NULL_items;
 +      }
 +      wmWindow *win = CTX_wm_window(C);
 +      WorkSpace *workspace = WM_window_get_active_workspace(win);
 +      ListBase *listbase = BKE_workspace_layouts_get(workspace);
 +      EnumPropertyItem *item = NULL;
 +      EnumPropertyItem tmp = {0, "", 0, "", ""};
 +      int value = 0, totitem = 0;
 +      int count_act_screens = 0;
 +      /* XXX setting max number of windows to 20. We'd need support
 +       * for dynamic strings in EnumPropertyItem.name to avoid this. */
 +      static char active_screens[20][MAX_NAME + 12];
 +
 +      for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) {
 +              bScreen *screen = BKE_workspace_layout_screen_get(layout);
 +              const char *layout_name = BKE_workspace_layout_name_get(layout);
 +
 +              if (screen->winid) {
 +                      BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", layout_name);
 +                      tmp.name = active_screens[count_act_screens++];
 +              }
 +              else {
 +                      tmp.name = layout_name;
 +              }
 +
 +              tmp.value = value;
 +              tmp.identifier = layout_name;
 +              UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false);
 +              tmp.icon = BKE_icon_id_ensure(&screen->id);
 +
 +              RNA_enum_item_add(&item, &totitem, &tmp);
 +              value++;
 +      }
 +
 +      RNA_enum_item_end(&item, &totitem);
 +      *r_free = true;
 +
 +      return item;
 +}
  
  /* fullscreen operator callback */
  int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@@@ -1145,43 -997,18 +1147,43 @@@ void wm_window_make_drawable(wmWindowMa
  {
        if (win != wm->windrawable && win->ghostwin) {
  //            win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
 -              
 +
                wm->windrawable = win;
                if (G.debug & G_DEBUG_EVENTS) {
                        printf("%s: set drawable %d\n", __func__, win->winid);
                }
 +
 +              gpu_batch_presets_reset();
 +              immDeactivate();
                GHOST_ActivateWindowDrawingContext(win->ghostwin);
 -              
 +              GWN_context_active_set(win->gwnctx);
 +              immActivate();
 +
                /* this can change per window */
                WM_window_set_dpi(win);
        }
  }
  
 +/* Reset active the current window opengl drawing context. */
 +void wm_window_reset_drawable(void)
 +{
 +      BLI_assert(BLI_thread_is_main());
 +      wmWindowManager *wm = G.main->wm.first;
 +
 +      if (wm == NULL)
 +              return;
 +
 +      wmWindow *win = wm->windrawable;
 +
 +      if (win && win->ghostwin) {
 +              gpu_batch_presets_reset();
 +              immDeactivate();
 +              GHOST_ActivateWindowDrawingContext(win->ghostwin);
 +              GWN_context_active_set(win->gwnctx);
 +              immActivate();
 +      }
 +}
 +
  /* called by ghost, here we handle events for windows themselves or send to event system */
  /* mouse coordinate converversion happens here */
  static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
                
                /* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
                 * Can happen on file read (especially full size window)  */
 -              if ((wm->initialized & WM_INIT_WINDOW) == 0) {
 +              if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
                        return 1;
                }
                if (!ghostwin) {
  
                                /* stop screencast if resize */
                                if (type == GHOST_kEventWindowSize) {
 -                                      WM_jobs_stop(wm, win->screen, NULL);
 +                                      WM_jobs_stop(wm, WM_window_get_active_screen(win), NULL);
                                }
  
                                WM_window_set_dpi(win);
                                            win->posx != posx ||
                                            win->posy != posy)
                                        {
 +                                              const bScreen *screen = WM_window_get_active_screen(win);
 +
                                                win->sizex = sizex;
                                                win->sizey = sizey;
                                                win->posx = posx;
                                        
                                                wm_window_make_drawable(wm, win);
                                                wm_draw_window_clear(win);
 +                                              BKE_icon_changed(screen->id.icon_id);
                                                WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
                                                WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
                                                
                                WM_window_set_dpi(win);
  
                                if (U.pixelsize != prev_pixelsize) {
 +                                      BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
 +
                                        // close all popups since they are positioned with the pixel
                                        // size baked in and it's difficult to correct them
                                        wmWindow *oldWindow = CTX_wm_window(C);
@@@ -1951,6 -1773,7 +1953,6 @@@ void wm_window_raise(wmWindow *win
  
  void wm_window_swap_buffers(wmWindow *win)
  {
 -      
  #ifdef WIN32
        glDisable(GL_SCISSOR_TEST);
        GHOST_SwapWindowBuffers(win->ghostwin);
@@@ -2068,107 -1891,6 +2070,107 @@@ bool WM_window_is_fullscreen(wmWindow *
        return win->windowstate == GHOST_kWindowStateFullScreen;
  }
  
 +/**
 + * Some editor data may need to be synced with scene data (3D View camera and layers).
 + * This function ensures data is synced for editors in visible workspaces and their visible layouts.
 + */
 +void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
 +{
 +      for (wmWindow *win = win_lb->first; win; win = win->next) {
 +              if (WM_window_get_active_scene(win) == scene) {
 +                      ED_workspace_scene_data_sync(win->workspace_hook, scene);
 +              }
 +      }
 +}
 +
 +Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
 +{
 +      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +              if (WM_window_get_active_screen(win) == screen) {
 +                      return WM_window_get_active_scene(win);
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
 +{
 +      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +              if (WM_window_get_active_screen(win) == screen) {
 +                      return WM_window_get_active_workspace(win);
 +              }
 +      }
 +      return NULL;
 +}
 +
 +eObjectMode WM_windows_object_mode_get(const struct wmWindowManager *wm)
 +{
 +      eObjectMode object_mode = 0;
 +      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +              const WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
 +              if (workspace != NULL) {
 +                      object_mode |= workspace->object_mode;
 +              }
 +      }
 +      return object_mode;
 +}
 +
 +Scene *WM_window_get_active_scene(const wmWindow *win)
 +{
 +      return win->scene;
 +}
 +
 +/**
 + * \warning Only call outside of area/region loops
 + */
 +void WM_window_change_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene_new)
 +{
 +      const bScreen *screen = WM_window_get_active_screen(win);
 +      Scene *scene_old = win->scene;
 +
 +      ED_scene_change_update(bmain, C, win, screen, scene_old, scene_new);
 +}
 +
 +WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
 +{
 +      return BKE_workspace_active_get(win->workspace_hook);
 +}
 +void WM_window_set_active_workspace(wmWindow *win, WorkSpace *workspace)
 +{
 +      BKE_workspace_active_set(win->workspace_hook, workspace);
 +}
 +
 +WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
 +{
 +      const WorkSpace *workspace = WM_window_get_active_workspace(win);
 +      return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook) : NULL);
 +}
 +void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
 +{
 +      BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
 +}
 +
 +/**
 + * Get the active screen of the active workspace in \a win.
 + */
 +bScreen *WM_window_get_active_screen(const wmWindow *win)
 +{
 +      const WorkSpace *workspace = WM_window_get_active_workspace(win);
 +      /* May be NULL in rare cases like closing Blender */
 +      return (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL);
 +}
 +void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
 +{
 +      BKE_workspace_active_screen_set(win->workspace_hook, workspace, screen);
 +}
 +
 +bool WM_window_is_temp_screen(const wmWindow *win)
 +{
 +      const bScreen *screen = WM_window_get_active_screen(win);
 +      return (screen && screen->temp != 0);
 +}
 +
  
  #ifdef WITH_INPUT_IME
  /* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */
@@@ -2187,30 -1909,3 +2189,30 @@@ void wm_window_IME_end(wmWindow *win
        win->ime_data = NULL;
  }
  #endif  /* WITH_INPUT_IME */
 +
 +/* ****** direct opengl context management ****** */
 +
 +void *WM_opengl_context_create(void)
 +{
 +      /* On Windows there is a problem creating contexts that share lists
 +       * from one context that is current in another thread.
 +       * So we should call this function only on the main thread.
 +       */
 +      BLI_assert(BLI_thread_is_main());
 +      return GHOST_CreateOpenGLContext(g_system);
 +}
 +
 +void WM_opengl_context_dispose(void *context)
 +{
 +      GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context);
 +}
 +
 +void WM_opengl_context_activate(void *context)
 +{
 +      GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context);
 +}
 +
 +void WM_opengl_context_release(void *context)
 +{
 +      GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context);
 +}