Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Mon, 7 Aug 2017 14:16:43 +0000 (16:16 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Mon, 7 Aug 2017 14:16:43 +0000 (16:16 +0200)
1  2 
intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_sync.cpp
intern/cycles/device/device_cuda.cpp
source/blender/editors/space_clip/space_clip.c
source/blender/editors/space_sequencer/space_sequencer.c
source/blender/windowmanager/intern/wm_files.c
tests/python/CMakeLists.txt

index cfffe5362ca5f7409fdc2c5479220b293d325a3f,c744c1d6932f8042fd773f72744faf024d3fa297..93b90ec650b6b77a279649d33746ba26f39b6322
@@@ -195,6 -195,12 +195,6 @@@ class CyclesRenderSettings(bpy.types.Pr
                  description="Pause all viewport preview renders",
                  default=False,
                  )
 -        cls.preview_active_layer = BoolProperty(
 -                name="Preview Active Layer",
 -                description="Preview active render layer in viewport",
 -                default=False,
 -                )
 -
          cls.aa_samples = IntProperty(
                  name="AA Samples",
                  description="Number of antialiasing samples to render for each pixel",
                  min=0, max=1024,
                  default=8,
                  )
-         cls.use_transparent_shadows = BoolProperty(
-                 name="Transparent Shadows",
-                 description="Use transparency of surfaces for rendering shadows",
-                 default=True,
-                 )
  
          cls.volume_step_size = FloatProperty(
                  name="Step Size",
index 59ee053efb99755262f7b3ef3e94bf94696bf7f4,b9565aa4c7fa468939b84c5b82af25980838ab89..983f817539b467fdc87d790f2adfcf7d8a8c8f05
@@@ -17,7 -17,6 +17,7 @@@
  # <pep8 compliant>
  
  import bpy
 +from bpy_extras.node_utils import find_node_input, find_output_node
  
  from bpy.types import (
          Panel,
@@@ -293,7 -292,6 +293,6 @@@ class CyclesRender_PT_light_paths(Cycle
          sub = col.column(align=True)
          sub.label("Transparency:")
          sub.prop(cscene, "transparent_max_bounces", text="Max")
-         sub.prop(cscene, "use_transparent_shadows", text="Shadows")
  
          col.separator()
  
@@@ -897,22 -895,43 +896,22 @@@ class CYCLES_OT_use_shading_nodes(Opera
          return {'FINISHED'}
  
  
 -def find_node(material, nodetype):
 -    if material and material.node_tree:
 -        ntree = material.node_tree
 -
 -        active_output_node = None
 -        for node in ntree.nodes:
 -            if getattr(node, "type", None) == nodetype:
 -                if getattr(node, "is_active_output", True):
 -                    return node
 -                if not active_output_node:
 -                    active_output_node = node
 -        return active_output_node
 -
 -    return None
 -
 -
 -def find_node_input(node, name):
 -    for input in node.inputs:
 -        if input.name == name:
 -            return input
 -
 -    return None
 -
 -
 -def panel_node_draw(layout, id_data, output_type, input_name):
 +def panel_node_draw(layout, id_data, output_types, input_name):
      if not id_data.use_nodes:
          layout.operator("cycles.use_shading_nodes", icon='NODETREE')
          return False
  
      ntree = id_data.node_tree
  
 -    node = find_node(id_data, output_type)
 -    if not node:
 -        layout.label(text="No output node")
 -    else:
 +    node = find_output_node(ntree, output_types)
 +    if node:
          input = find_node_input(node, input_name)
 -        layout.template_node_view(ntree, node, input)
 +        if input:
 +            layout.template_node_view(ntree, node, input)
 +        else:
 +            layout.label(text="Incompatible output node")
 +    else:
 +        layout.label(text="No output node")
  
      return True
  
@@@ -1001,7 -1020,7 +1000,7 @@@ class CyclesLamp_PT_nodes(CyclesButtons
          layout = self.layout
  
          lamp = context.lamp
 -        if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
 +        if not panel_node_draw(layout, lamp, ('OUTPUT_LAMP',), 'Surface'):
              layout.prop(lamp, "color")
  
  
@@@ -1056,7 -1075,7 +1055,7 @@@ class CyclesWorld_PT_surface(CyclesButt
  
          world = context.world
  
 -        if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
 +        if not panel_node_draw(layout, world, ('OUTPUT_WORLD',), 'Surface'):
              layout.prop(world, "horizon_color", text="Color")
  
  
@@@ -1074,7 -1093,7 +1073,7 @@@ class CyclesWorld_PT_volume(CyclesButto
          layout = self.layout
  
          world = context.world
 -        panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
 +        panel_node_draw(layout, world, ('OUTPUT_WORLD',), 'Volume')
  
  
  class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel):
@@@ -1219,7 -1238,7 +1218,7 @@@ class CyclesMaterial_PT_surface(CyclesB
          layout = self.layout
  
          mat = context.material
 -        if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
 +        if not panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Surface'):
              layout.prop(mat, "diffuse_color")
  
  
@@@ -1239,7 -1258,7 +1238,7 @@@ class CyclesMaterial_PT_volume(CyclesBu
          mat = context.material
          # cmat = mat.cycles
  
 -        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
 +        panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Volume')
  
  
  class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
          layout = self.layout
  
          mat = context.material
 -        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
 +        panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Displacement')
  
  
  class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
@@@ -1644,7 -1663,6 +1643,7 @@@ class CyclesScene_PT_simplify(CyclesBut
          row.prop(rd, "simplify_subdivision", text="Viewport")
          row.prop(rd, "simplify_subdivision_render", text="Render")
  
 +
          col = layout.column(align=True)
          col.label(text="Child Particles")
          row = col.row(align=True)
@@@ -1707,8 -1725,11 +1706,8 @@@ def draw_pause(self, context)
      if scene.render.engine == "CYCLES":
          view = context.space_data
  
 -        if view.viewport_shade == 'RENDERED':
 -            cscene = scene.cycles
 -            layername = scene.render.layers.active.name
 -            layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
 -            layout.prop(cscene, "preview_active_layer", icon="RENDERLAYERS", text=layername)
 +        cscene = scene.cycles
 +        layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
  
  
  def get_panels():
index 15ad4ff301c175b4694a77d2554894826b2c7b9b,e953c685b565be351d680836251f903a8c9c32a5..adbabaccdc1c3246726fbdcd4475fc76eec4aaed
@@@ -44,7 -44,6 +44,7 @@@ CCL_NAMESPACE_BEGI
  
  BlenderSync::BlenderSync(BL::RenderEngine& b_engine,
                           BL::BlendData& b_data,
 +                         BL::Depsgraph& b_depsgraph,
                           BL::Scene& b_scene,
                           Scene *scene,
                           bool preview,
@@@ -52,9 -51,7 +52,9 @@@
                           bool is_cpu)
  : b_engine(b_engine),
    b_data(b_data),
 +  b_depsgraph(b_depsgraph),
    b_scene(b_scene),
 +  b_scene_layer(b_engine.scene_layer()),
    shader_map(&scene->shaders),
    object_map(&scene->objects),
    mesh_map(&scene->meshes),
@@@ -245,7 -242,6 +245,6 @@@ void BlenderSync::sync_integrator(
        integrator->max_volume_bounce = get_int(cscene, "volume_bounces");
  
        integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
-       integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows");
  
        integrator->volume_max_steps = get_int(cscene, "volume_max_steps");
        integrator->volume_step_size = get_float(cscene, "volume_step_size");
@@@ -386,9 -382,26 +385,9 @@@ void BlenderSync::sync_render_layers(BL
  
        /* 3d view */
        if(b_v3d) {
 -              if(RNA_boolean_get(&cscene, "preview_active_layer")) {
 -                      BL::RenderLayers layers(b_scene.render().ptr);
 -                      layername = layers.active().name();
 -                      layer = layername.c_str();
 -              }
 -              else {
 -                      render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view());
 -                      render_layer.layer = render_layer.scene_layer;
 -                      render_layer.exclude_layer = 0;
 -                      render_layer.holdout_layer = 0;
 -                      render_layer.material_override = PointerRNA_NULL;
 -                      render_layer.use_background_shader = true;
 -                      render_layer.use_background_ao = true;
 -                      render_layer.use_hair = true;
 -                      render_layer.use_surfaces = true;
 -                      render_layer.use_viewport_visibility = true;
 -                      render_layer.samples = 0;
 -                      render_layer.bound_samples = false;
 -                      return;
 -              }
 +              BL::RenderLayers layers(b_scene.render().ptr);
 +              layername = layers.active().name();
 +              layer = layername.c_str();
        }
  
        /* render layer */
                        render_layer.use_background_ao = b_rlay->use_ao();
                        render_layer.use_surfaces = b_rlay->use_solid();
                        render_layer.use_hair = b_rlay->use_strand();
 -                      render_layer.use_viewport_visibility = false;
  
                        render_layer.bound_samples = (use_layer_samples == 1);
                        if(use_layer_samples != 2) {
@@@ -826,8 -840,17 +825,8 @@@ SessionParams BlenderSync::get_session_
                params.shadingsystem = SHADINGSYSTEM_OSL;
        
        /* color managagement */
 -#ifdef GLEW_MX
 -      /* When using GLEW MX we need to check whether we've got an OpenGL
 -       * context for current window. This is because command line rendering
 -       * doesn't have OpenGL context actually.
 -       */
 -      if(glewGetContext() != NULL)
 -#endif
 -      {
 -              params.display_buffer_linear = GLEW_ARB_half_float_pixel &&
 -                                             b_engine.support_display_space_shader(b_scene);
 -      }
 +      params.display_buffer_linear = GLEW_ARB_half_float_pixel &&
 +                                     b_engine.support_display_space_shader(b_scene);
  
        if(b_engine.is_preview()) {
                /* For preview rendering we're using same timeout as
index e53aec0fbb97a61c1fd04a45bc0e1bce665b1906,dbf636e1405238a423319eb5b612d33de0a17762..f13506c89603dc8ab30459a3180328a7641bfab8
@@@ -1632,14 -1632,10 +1632,14 @@@ public
                }
        }
  
 -      void draw_pixels(device_memory& mem, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
 +      void draw_pixels(
 +          device_memory& mem, int y,
 +          int w, int h, int width, int height,
 +          int dx, int dy, int dw, int dh, bool transparent,
                const DeviceDrawParams &draw_params)
        {
                if(!background) {
 +                      const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL);
                        PixelMem pmem = pixel_mem_map[mem.device_pointer];
                        float *vpointer;
  
  
                        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
                        glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
 -                      if(mem.data_type == TYPE_HALF)
 +                      if(mem.data_type == TYPE_HALF) {
                                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, (void*)offset);
 -                      else
 +                      }
 +                      else {
                                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
 +                      }
                        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
  
                        glEnable(GL_TEXTURE_2D);
                                glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
                        }
  
 -                      glColor3f(1.0f, 1.0f, 1.0f);
 -
 -                      if(draw_params.bind_display_space_shader_cb) {
 +                      GLint shader_program;
 +                      if(use_fallback_shader) {
 +                              if(!bind_fallback_display_space_shader(dw, dh)) {
 +                                      return;
 +                              }
 +                              shader_program = fallback_shader_program;
 +                      }
 +                      else {
                                draw_params.bind_display_space_shader_cb();
 +                              glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program);
                        }
  
 -                      if(!vertex_buffer)
 +                      if(!vertex_buffer) {
                                glGenBuffers(1, &vertex_buffer);
 +                      }
  
                        glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
                        /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
                                glUnmapBuffer(GL_ARRAY_BUFFER);
                        }
  
 -                      glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
 -                      glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)NULL + 2 * sizeof(float));
 +                      GLuint vertex_array_object;
 +                      GLuint position_attribute, texcoord_attribute;
  
 -                      glEnableClientState(GL_VERTEX_ARRAY);
 -                      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 +                      glGenVertexArrays(1, &vertex_array_object);
 +                      glBindVertexArray(vertex_array_object);
  
 -                      glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 +                      texcoord_attribute = glGetAttribLocation(shader_program, "texCoord");
 +                      position_attribute = glGetAttribLocation(shader_program, "pos");
  
 -                      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 -                      glDisableClientState(GL_VERTEX_ARRAY);
 +                      glEnableVertexAttribArray(texcoord_attribute);
 +                      glEnableVertexAttribArray(position_attribute);
  
 -                      glBindBuffer(GL_ARRAY_BUFFER, 0);
 +                      glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
 +                      glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2));
 +
 +                      glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
  
 -                      if(draw_params.unbind_display_space_shader_cb) {
 +                      if(use_fallback_shader) {
 +                              glUseProgram(0);
 +                      }
 +                      else {
                                draw_params.unbind_display_space_shader_cb();
                        }
  
 -                      if(transparent)
 +                      if(transparent) {
                                glDisable(GL_BLEND);
 +                      }
  
                        glBindTexture(GL_TEXTURE_2D, 0);
                        glDisable(GL_TEXTURE_2D);
                        return;
                }
  
 -              Device::draw_pixels(mem, y, w, h, dx, dy, width, height, transparent, draw_params);
 +              Device::draw_pixels(mem, y, w, h, width, height, dx, dy, dw, dh, transparent, draw_params);
        }
  
        void thread_run(DeviceTask *task)
@@@ -1919,17 -1898,13 +1919,13 @@@ public
                int threads_per_block;
                cuda_assert(cuFuncGetAttribute(&threads_per_block, CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, func));
  
-               int xthreads = (int)sqrt(threads_per_block);
-               int ythreads = (int)sqrt(threads_per_block);
-               int xblocks = (dim.global_size[0] + xthreads - 1)/xthreads;
-               int yblocks = (dim.global_size[1] + ythreads - 1)/ythreads;
+               int xblocks = (dim.global_size[0]*dim.global_size[1] + threads_per_block - 1)/threads_per_block;
  
                cuda_assert(cuFuncSetCacheConfig(func, CU_FUNC_CACHE_PREFER_L1));
  
                cuda_assert(cuLaunchKernel(func,
-                                          xblocks , yblocks, 1, /* blocks */
-                                          xthreads, ythreads, 1, /* threads */
+                                          xblocks, 1, 1, /* blocks */
+                                          threads_per_block, 1, 1, /* threads */
                                           0, 0, args, 0));
  
                device->cuda_pop_context();
index 9af3ebf3cbbcdc934ea2eb3cb86ab5a0026db582,58930fa2cf2083fde1c66d60f646b9e5a1951383..1872fe108cada16bf266a601a3b2e6fc36b74f78
@@@ -60,7 -60,7 +60,7 @@@
  
  #include "IMB_imbuf.h"
  
 -#include "BIF_gl.h"
 +#include "GPU_matrix.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
@@@ -329,7 -329,7 +329,7 @@@ static SpaceLink *clip_duplicate(SpaceL
        return (SpaceLink *)scn;
  }
  
 -static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
 +static void clip_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -821,7 -821,8 +821,8 @@@ static void clip_keymap(struct wmKeyCon
  #endif
  }
  
- static const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
+ /* DO NOT make this static, this hides the symbol and breaks API generation script. */
+ const char *clip_context_dir[] = {"edit_movieclip", "edit_mask", NULL};
  
  static int clip_context(const bContext *C, const char *member, bContextDataResult *result)
  {
@@@ -1213,13 -1214,13 +1214,13 @@@ static void clip_main_region_draw(cons
        show_cursor |= sc->around == V3D_AROUND_CURSOR;
  
        if (show_cursor) {
 -              glPushMatrix();
 -              glTranslatef(x, y, 0);
 -              glScalef(zoomx, zoomy, 0);
 -              glMultMatrixf(sc->stabmat);
 -              glScalef(width, height, 0);
 +              gpuPushMatrix();
 +              gpuTranslate2f(x, y);
 +              gpuScale2f(zoomx, zoomy);
 +              gpuMultMatrix(sc->stabmat);
 +              gpuScale2f(width, height);
                ED_image_draw_cursor(ar, sc->cursor);
 -              glPopMatrix();
 +              gpuPopMatrix();
        }
  
        clip_draw_cache_and_notes(C, sc, ar);
        }
  }
  
 -static void clip_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void clip_main_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -1351,9 -1350,7 +1352,9 @@@ static void clip_preview_region_draw(co
                dopesheet_region_draw(C, ar);
  }
  
 -static void clip_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
 +static void clip_preview_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
 +        wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
  {
  }
  
@@@ -1394,9 -1391,7 +1395,9 @@@ static void clip_channels_region_draw(c
        UI_view2d_view_restore(C);
  }
  
 -static void clip_channels_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn))
 +static void clip_channels_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar),
 +        wmNotifier *UNUSED(wmn), const Scene *UNUSED(scene))
  {
  }
  
@@@ -1413,9 -1408,7 +1414,9 @@@ static void clip_header_region_draw(con
        ED_region_header(C, ar);
  }
  
 -static void clip_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void clip_header_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -1455,9 -1448,7 +1456,9 @@@ static void clip_tools_region_draw(cons
  
  /****************** tool properties region ******************/
  
 -static void clip_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void clip_props_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -1502,9 -1493,7 +1503,9 @@@ static void clip_properties_region_draw
        ED_region_panels(C, ar, NULL, -1, true);
  }
  
 -static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void clip_properties_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
index 5dfcba9b4d1e2bfe04d2fbacd90e1a50eda99099,f1d0f23f8af91183276a822baca2219d9a49b953..3b04e6c80cdd73e16ef1bb2982290774f899dfb6
@@@ -337,8 -337,7 +337,8 @@@ static SpaceLink *sequencer_duplicate(S
        return (SpaceLink *)sseqn;
  }
  
 -static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
 +static void sequencer_listener(
 +        bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -436,7 -435,8 +436,8 @@@ static void sequencer_dropboxes(void
  
  /* ************* end drop *********** */
  
- static const char *sequencer_context_dir[] = {"edit_mask", NULL};
+ /* DO NOT make this static, this hides the symbol and breaks API generation script. */
+ const char *sequencer_context_dir[] = {"edit_mask", NULL};
  
  static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result)
  {
@@@ -491,9 -491,7 +492,9 @@@ static void sequencer_main_region_draw(
        draw_timeline_seq(C, ar);
  }
  
 -static void sequencer_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void sequencer_main_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -599,9 -597,7 +600,9 @@@ static void sequencer_preview_region_dr
        }
  }
  
 -static void sequencer_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void sequencer_preview_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
@@@ -667,9 -663,7 +668,9 @@@ static void sequencer_buttons_region_dr
        ED_region_panels(C, ar, NULL, -1, true);
  }
  
 -static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
 +static void sequencer_buttons_region_listener(
 +        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
 +        wmNotifier *wmn, const Scene *UNUSED(scene))
  {
        /* context changes */
        switch (wmn->category) {
index cedf50a3035e20ef310163c83186d84b51019d66,605a226500f9735ef26c7279d1b74f602631a5d6..221baeadbee874c0872324d3432655874d7016c1
@@@ -69,7 -69,6 +69,7 @@@
  #include "DNA_scene_types.h"
  #include "DNA_screen_types.h"
  #include "DNA_windowmanager_types.h"
 +#include "DNA_workspace_types.h"
  
  #include "BKE_appdir.h"
  #include "BKE_utildefines.h"
@@@ -78,6 -77,7 +78,6 @@@
  #include "BKE_blendfile.h"
  #include "BKE_blender_undo.h"
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_global.h"
  #include "BKE_library.h"
  #include "BKE_main.h"
@@@ -86,7 -86,6 +86,7 @@@
  #include "BKE_sound.h"
  #include "BKE_scene.h"
  #include "BKE_screen.h"
 +#include "BKE_workspace.h"
  
  #include "BLO_readfile.h"
  #include "BLO_writefile.h"
  #include "BPY_extern.h"
  #endif
  
 +#include "DEG_depsgraph.h"
 +
  #include "WM_api.h"
  #include "WM_types.h"
  #include "wm.h"
@@@ -162,7 -159,7 +162,7 @@@ static void wm_window_match_init(bConte
                        CTX_wm_window_set(C, win);  /* needed by operator close callbacks */
                        WM_event_remove_handlers(C, &win->handlers);
                        WM_event_remove_handlers(C, &win->modalhandlers);
 -                      ED_screen_exit(C, win, win->screen);
 +                      ED_screen_exit(C, win, WM_window_get_active_screen(win));
                }
        }
        
@@@ -251,23 -248,16 +251,23 @@@ static void wm_window_match_do(bContex
  
                                /* match oldwm to new dbase, only old files */
                                for (wm = oldwmlist->first; wm; wm = wm->id.next) {
 -                                      
                                        for (win = wm->windows.first; win; win = win->next) {
 +                                              WorkSpace *workspace = WM_window_get_active_workspace(win);
 +
                                                /* all windows get active screen from file */
 -                                              if (screen->winid == 0)
 -                                                      win->screen = screen;
 -                                              else 
 -                                                      win->screen = ED_screen_duplicate(win, screen);
 -                                              
 -                                              BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
 -                                              win->screen->winid = win->winid;
 +                                              if (screen->winid == 0) {
 +                                                      WM_window_set_active_screen(win, workspace, screen);
 +                                              }
 +                                              else {
 +                                                      WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
 +                                                      WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
 +
 +                                                      WM_window_set_active_layout(win, workspace, layout_new);
 +                                              }
 +
 +                                              bScreen *win_screen = WM_window_get_active_screen(win);
 +                                              BLI_strncpy(win->screenname, win_screen->id.name + 2, sizeof(win->screenname));
 +                                              win_screen->winid = win->winid;
                                        }
                                }
                        }
  }
  
  /* in case UserDef was read, we re-initialize all, and do versioning */
 -static void wm_init_userdef(bContext *C, const bool read_userdef_from_memory)
 +static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory)
  {
 -      Main *bmain = CTX_data_main(C);
 -
        /* versioning is here */
        UI_init_userdef();
        
@@@ -470,7 -462,7 +470,7 @@@ static void wm_file_read_post(bContext 
        CTX_wm_window_set(C, wm->windows.first);
  
        ED_editors_init(C);
 -      DAG_on_visible_update(CTX_data_main(C), true);
 +      DEG_on_visible_update(CTX_data_main(C), true);
  
  #ifdef WITH_PYTHON
        if (is_startup_file) {
@@@ -587,7 -579,7 +587,7 @@@ bool WM_file_read(bContext *C, const ch
  
                if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
                        /* in case a userdef is read from regular .blend */
 -                      wm_init_userdef(C, false);
 +                      wm_init_userdef(G.main, false);
                }
                
                if (retval != BKE_BLENDFILE_READ_FAIL) {
@@@ -729,20 -721,20 +729,20 @@@ int wm_homefile_read
        if (filepath_startup_override != NULL) {
                /* pass */
        }
-       else if (app_template_override && app_template_override[0]) {
+       else if (app_template_override) {
+               /* This may be clearing the current template by setting to an empty string. */
                app_template = app_template_override;
        }
        else if (!use_factory_settings && U.app_template[0]) {
                app_template = U.app_template;
        }
  
-       if (app_template != NULL) {
+       if ((app_template != NULL) && (app_template[0] != '\0')) {
                BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system));
                BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
-       }
  
-       /* insert template name into startup file */
-       if (app_template != NULL) {
+               /* Insert template name into startup file. */
                /* note that the path is being set even when 'use_factory_settings == true'
                 * this is done so we can load a templates factory-settings */
                if (!use_factory_settings) {
        G.fileflags &= ~G_FILE_RELATIVE_REMAP;
        
        /* check userdef before open window, keymaps etc */
 -      wm_init_userdef(C, read_userdef_from_memory);
 +      wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
        
        /* match the read WM with current WM */
        wm_window_match_do(C, &wmbase); 
@@@ -983,7 -975,7 +983,7 @@@ static void wm_history_file_update(void
  
  
  /* screen can be NULL */
 -static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
 +static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, SceneLayer *sl, bScreen *screen, BlendThumbnail **thumb_pt)
  {
        /* will be scaled down, but gives some nice oversampling */
        ImBuf *ibuf;
        ARegion *ar = NULL;
        View3D *v3d = NULL;
  
 +      EvaluationContext eval_ctx;
 +
 +      CTX_data_eval_ctx(C, &eval_ctx);
 +
        /* In case we are given a valid thumbnail data, just generate image from it. */
        if (*thumb_pt) {
                thumb = *thumb_pt;
        /* gets scaled to BLEN_THUMB_SIZE */
        if (scene->camera) {
                ibuf = ED_view3d_draw_offscreen_imbuf_simple(
 -                      scene, scene->camera,
 +                      &eval_ctx, scene, sl, scene->camera,
                        BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
                        IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, false, NULL,
                        NULL, NULL, err_out);
        }
        else {
                ibuf = ED_view3d_draw_offscreen_imbuf(
 -                      scene, v3d, ar,
 +                      &eval_ctx, scene, sl, v3d, ar,
                        BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
                        IB_rect, false, R_ALPHAPREMUL, 0, false, NULL,
                        NULL, NULL, err_out);
@@@ -1127,7 -1115,7 +1127,7 @@@ static int wm_file_write(bContext *C, c
        /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
        main_thumb = thumb = CTX_data_main(C)->blen_thumb;
        if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
 -              ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb);
 +              ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_data_scene_layer(C), CTX_wm_screen(C), &thumb);
        }
  
        /* operator now handles overwrite checks */
@@@ -1382,7 -1370,7 +1382,7 @@@ static int wm_homefile_write_exec(bCont
        BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
  
        /* check current window and close it if temp */
 -      if (win && win->screen->temp)
 +      if (win && WM_window_is_temp_screen(win))
                wm_window_close(C, wm, win);
  
        /* update keymaps in user preferences */
@@@ -1517,42 -1505,6 +1517,42 @@@ void WM_OT_save_userpref(wmOperatorTyp
        ot->exec = wm_userpref_write_exec;
  }
  
 +static int wm_workspace_configuration_file_write_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      char filepath[FILE_MAX];
 +
 +      const char *app_template = U.app_template[0] ? U.app_template : NULL;
 +      const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
 +      if (cfgdir == NULL) {
 +              BKE_report(op->reports, RPT_ERROR, "Unable to create workspace configuration file path");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_WORKSPACES_FILE, NULL);
 +      printf("trying to save workspace configuration file at %s ", filepath);
 +
 +      if (BKE_blendfile_workspace_config_write(bmain, filepath, op->reports) != 0) {
 +              printf("ok\n");
 +              return OPERATOR_FINISHED;
 +      }
 +      else {
 +              printf("fail\n");
 +      }
 +
 +      return OPERATOR_CANCELLED;
 +}
 +
 +void WM_OT_save_workspace_file(wmOperatorType *ot)
 +{
 +      ot->name = "Save Workspace Configuration";
 +      ot->idname = "WM_OT_save_workspace_file";
 +      ot->description = "Save workspaces of the current file as part of the user configuration";
 +
 +      ot->invoke = WM_operator_confirm;
 +      ot->exec = wm_workspace_configuration_file_write_exec;
 +}
 +
  static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
  {
        ED_file_read_bookmarks();
index 28ce095b0e81c42795eee09de679c05e9c5726db,ca752993c7912c509ec2a6d10fffbb16daff3d55..afd61d5ab6741a437773653bb9259fbea4cfa3e4
@@@ -518,6 -518,7 +518,7 @@@ if(WITH_CYCLES
                                        -blender "$<TARGET_FILE:blender>"
                                        -testdir "${TEST_SRC_DIR}/cycles/ctests/${subject}"
                                        -idiff "${OPENIMAGEIO_IDIFF}"
+                                       -outdir "${TEST_OUT_DIR}/cycles"
                                )
                        else()
                                add_test(
                                        -blender "$<TARGET_FILE:blender>"
                                        -testdir "${TEST_SRC_DIR}/cycles/ctests/${subject}"
                                        -idiff "${OPENIMAGEIO_IDIFF}"
+                                       -outdir "${TEST_OUT_DIR}/cycles"
                                )
                        endif()
                endmacro()
                if(WITH_OPENGL_TESTS)
                        add_cycles_render_test(opengl)
                endif()
-               add_cycles_render_test(image)
+               add_cycles_render_test(displacement)
+               add_cycles_render_test(image_data_types)
+               add_cycles_render_test(image_mapping)
+               add_cycles_render_test(image_texture_limit)
                add_cycles_render_test(mblur)
                add_cycles_render_test(reports)
                add_cycles_render_test(render)
                add_cycles_render_test(shader)
+               add_cycles_render_test(shadow_catcher)
+               add_cycles_render_test(volume)
        else()
                MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist")
        endif()
@@@ -580,5 -587,3 +587,5 @@@ if(WITH_ALEMBIC
                --with-legacy-depsgraph=${WITH_LEGACY_DEPSGRAPH}
        )
  endif()
 +
 +add_subdirectory(render_layer)