Merge branch 'blender2.7'
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 30 Jan 2019 17:36:54 +0000 (18:36 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 30 Jan 2019 17:36:54 +0000 (18:36 +0100)
1  2 
intern/cycles/blender/addon/properties.py
intern/cycles/blender/blender_python.cpp
intern/cycles/blender/blender_sync.cpp
intern/cycles/device/device.cpp
intern/cycles/device/device.h

  # <pep8 compliant>
  
  import bpy
 -from bpy.props import (BoolProperty,
 -                       EnumProperty,
 -                       FloatProperty,
 -                       IntProperty,
 -                       PointerProperty,
 -                       StringProperty)
 +from bpy.props import (
 +    BoolProperty,
 +    EnumProperty,
 +    FloatProperty,
 +    IntProperty,
 +    PointerProperty,
 +    StringProperty,
 +)
 +
 +from math import pi
  
  # enums
  
@@@ -158,591 -154,586 +158,591 @@@ enum_texture_limit = 
  
  
  class CyclesRenderSettings(bpy.types.PropertyGroup):
 -    @classmethod
 -    def register(cls):
 -        bpy.types.Scene.cycles = PointerProperty(
 -            name="Cycles Render Settings",
 -            description="Cycles render settings",
 -            type=cls,
 -        )
 -        cls.device = EnumProperty(
 -            name="Device",
 -            description="Device to use for rendering",
 -            items=enum_devices,
 -            default='CPU',
 -        )
 -        cls.feature_set = EnumProperty(
 -            name="Feature Set",
 -            description="Feature set to use for rendering",
 -            items=enum_feature_set,
 -            default='SUPPORTED',
 -        )
 -        cls.shading_system = BoolProperty(
 -            name="Open Shading Language",
 -            description="Use Open Shading Language (CPU rendering only)",
 -        )
  
 -        cls.progressive = EnumProperty(
 -            name="Integrator",
 -            description="Method to sample lights and materials",
 -            items=enum_integrator,
 -            default='PATH',
 -        )
 +    device: EnumProperty(
 +        name="Device",
 +        description="Device to use for rendering",
 +        items=enum_devices,
 +        default='CPU',
 +    )
 +    feature_set: EnumProperty(
 +        name="Feature Set",
 +        description="Feature set to use for rendering",
 +        items=enum_feature_set,
 +        default='SUPPORTED',
 +    )
 +    shading_system: BoolProperty(
 +        name="Open Shading Language",
 +        description="Use Open Shading Language (CPU rendering only)",
 +    )
  
 -        cls.use_square_samples = BoolProperty(
 -            name="Square Samples",
 -            description="Square sampling values for easier artist control",
 -            default=False,
 -        )
 +    progressive: EnumProperty(
 +        name="Integrator",
 +        description="Method to sample lights and materials",
 +        items=enum_integrator,
 +        default='PATH',
 +    )
  
 -        cls.samples = IntProperty(
 -            name="Samples",
 -            description="Number of samples to render for each pixel",
 -            min=1, max=2147483647,
 -            default=128,
 -        )
 -        cls.preview_samples = IntProperty(
 -            name="Preview Samples",
 -            description="Number of samples to render in the viewport, unlimited if 0",
 -            min=0, max=2147483647,
 -            default=32,
 -        )
 -        cls.preview_pause = BoolProperty(
 -            name="Pause Preview",
 -            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,
 -        )
 +    use_square_samples: BoolProperty(
 +        name="Square Samples",
 +        description="Square sampling values for easier artist control",
 +        default=False,
 +    )
  
 -        cls.aa_samples = IntProperty(
 -            name="AA Samples",
 -            description="Number of antialiasing samples to render for each pixel",
 -            min=1, max=2097151,
 -            default=128,
 -        )
 -        cls.preview_aa_samples = IntProperty(
 -            name="AA Samples",
 -            description="Number of antialiasing samples to render in the viewport, unlimited if 0",
 -            min=0, max=2097151,
 -            default=32,
 -        )
 -        cls.diffuse_samples = IntProperty(
 -            name="Diffuse Samples",
 -            description="Number of diffuse bounce samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 -        cls.glossy_samples = IntProperty(
 -            name="Glossy Samples",
 -            description="Number of glossy bounce samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 -        cls.transmission_samples = IntProperty(
 -            name="Transmission Samples",
 -            description="Number of transmission bounce samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 -        cls.ao_samples = IntProperty(
 -            name="Ambient Occlusion Samples",
 -            description="Number of ambient occlusion samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 -        cls.mesh_light_samples = IntProperty(
 -            name="Mesh Light Samples",
 -            description="Number of mesh emission light samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 +    samples: IntProperty(
 +        name="Samples",
 +        description="Number of samples to render for each pixel",
 +        min=1, max=2147483647,
 +        default=128,
 +    )
 +    preview_samples: IntProperty(
 +        name="Preview Samples",
 +        description="Number of samples to render in the viewport, unlimited if 0",
 +        min=0, max=2147483647,
 +        default=32,
 +    )
 +    preview_pause: BoolProperty(
 +        name="Pause Preview",
 +        description="Pause all viewport preview renders",
 +        default=False,
 +    )
 +    aa_samples: IntProperty(
 +        name="AA Samples",
 +        description="Number of antialiasing samples to render for each pixel",
 +        min=1, max=2097151,
 +        default=128,
 +    )
 +    preview_aa_samples: IntProperty(
 +        name="AA Samples",
 +        description="Number of antialiasing samples to render in the viewport, unlimited if 0",
 +        min=0, max=2097151,
 +        default=32,
 +    )
 +    diffuse_samples: IntProperty(
 +        name="Diffuse Samples",
 +        description="Number of diffuse bounce samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
 +    glossy_samples: IntProperty(
 +        name="Glossy Samples",
 +        description="Number of glossy bounce samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
 +    transmission_samples: IntProperty(
 +        name="Transmission Samples",
 +        description="Number of transmission bounce samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
 +    ao_samples: IntProperty(
 +        name="Ambient Occlusion Samples",
 +        description="Number of ambient occlusion samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
 +    mesh_light_samples: IntProperty(
 +        name="Mesh Light Samples",
 +        description="Number of mesh emission light samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
  
 -        cls.subsurface_samples = IntProperty(
 -            name="Subsurface Samples",
 -            description="Number of subsurface scattering samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 +    subsurface_samples: IntProperty(
 +        name="Subsurface Samples",
 +        description="Number of subsurface scattering samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
  
 -        cls.volume_samples = IntProperty(
 -            name="Volume Samples",
 -            description="Number of volume scattering samples to render for each AA sample",
 -            min=1, max=1024,
 -            default=1,
 -        )
 +    volume_samples: IntProperty(
 +        name="Volume Samples",
 +        description="Number of volume scattering samples to render for each AA sample",
 +        min=1, max=1024,
 +        default=1,
 +    )
  
 -        cls.sampling_pattern = EnumProperty(
 -            name="Sampling Pattern",
 -            description="Random sampling pattern used by the integrator",
 -            items=enum_sampling_pattern,
 -            default='SOBOL',
 -        )
 +    sampling_pattern: EnumProperty(
 +        name="Sampling Pattern",
 +        description="Random sampling pattern used by the integrator",
 +        items=enum_sampling_pattern,
 +        default='SOBOL',
 +    )
  
 -        cls.use_layer_samples = EnumProperty(
 -            name="Layer Samples",
 -            description="How to use per render layer sample settings",
 -            items=enum_use_layer_samples,
 -            default='USE',
 -        )
 +    use_layer_samples: EnumProperty(
 +        name="Layer Samples",
 +        description="How to use per view layer sample settings",
 +        items=enum_use_layer_samples,
 +        default='USE',
 +    )
  
 -        cls.sample_all_lights_direct = BoolProperty(
 -            name="Sample All Direct Lights",
 -            description="Sample all lights (for direct samples), rather than randomly picking one",
 -            default=True,
 -        )
 +    sample_all_lights_direct: BoolProperty(
 +        name="Sample All Direct Lights",
 +        description="Sample all lights (for direct samples), rather than randomly picking one",
 +        default=True,
 +    )
  
 -        cls.sample_all_lights_indirect = BoolProperty(
 -            name="Sample All Indirect Lights",
 -            description="Sample all lights (for indirect samples), rather than randomly picking one",
 -            default=True,
 -        )
 -        cls.light_sampling_threshold = FloatProperty(
 -            name="Light Sampling Threshold",
 -            description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). "
 -            "Zero disables the test and never ignores lights",
 -            min=0.0, max=1.0,
 -            default=0.01,
 -        )
 +    sample_all_lights_indirect: BoolProperty(
 +        name="Sample All Indirect Lights",
 +        description="Sample all lights (for indirect samples), rather than randomly picking one",
 +        default=True,
 +    )
 +    light_sampling_threshold: FloatProperty(
 +        name="Light Sampling Threshold",
 +        description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). "
 +        "Zero disables the test and never ignores lights",
 +        min=0.0, max=1.0,
 +        default=0.01,
 +    )
  
 -        cls.caustics_reflective = BoolProperty(
 -            name="Reflective Caustics",
 -            description="Use reflective caustics, resulting in a brighter image (more noise but added realism)",
 -            default=True,
 -        )
 +    caustics_reflective: BoolProperty(
 +        name="Reflective Caustics",
 +        description="Use reflective caustics, resulting in a brighter image (more noise but added realism)",
 +        default=True,
 +    )
  
 -        cls.caustics_refractive = BoolProperty(
 -            name="Refractive Caustics",
 -            description="Use refractive caustics, resulting in a brighter image (more noise but added realism)",
 -            default=True,
 -        )
 +    caustics_refractive: BoolProperty(
 +        name="Refractive Caustics",
 +        description="Use refractive caustics, resulting in a brighter image (more noise but added realism)",
 +        default=True,
 +    )
  
 -        cls.blur_glossy = FloatProperty(
 -            name="Filter Glossy",
 -            description="Adaptively blur glossy shaders after blurry bounces, "
 -            "to reduce noise at the cost of accuracy",
 -            min=0.0, max=10.0,
 -            default=1.0,
 -        )
 +    blur_glossy: FloatProperty(
 +        name="Filter Glossy",
 +        description="Adaptively blur glossy shaders after blurry bounces, "
 +        "to reduce noise at the cost of accuracy",
 +        min=0.0, max=10.0,
 +        default=1.0,
 +    )
  
 -        cls.max_bounces = IntProperty(
 -            name="Max Bounces",
 -            description="Total maximum number of bounces",
 -            min=0, max=1024,
 -            default=12,
 -        )
 +    max_bounces: IntProperty(
 +        name="Max Bounces",
 +        description="Total maximum number of bounces",
 +        min=0, max=1024,
 +        default=12,
 +    )
  
 -        cls.diffuse_bounces = IntProperty(
 -            name="Diffuse Bounces",
 -            description="Maximum number of diffuse reflection bounces, bounded by total maximum",
 -            min=0, max=1024,
 -            default=4,
 -        )
 -        cls.glossy_bounces = IntProperty(
 -            name="Glossy Bounces",
 -            description="Maximum number of glossy reflection bounces, bounded by total maximum",
 -            min=0, max=1024,
 -            default=4,
 -        )
 -        cls.transmission_bounces = IntProperty(
 -            name="Transmission Bounces",
 -            description="Maximum number of transmission bounces, bounded by total maximum",
 -            min=0, max=1024,
 -            default=12,
 -        )
 -        cls.volume_bounces = IntProperty(
 -            name="Volume Bounces",
 -            description="Maximum number of volumetric scattering events",
 -            min=0, max=1024,
 -            default=0,
 -        )
 +    diffuse_bounces: IntProperty(
 +        name="Diffuse Bounces",
 +        description="Maximum number of diffuse reflection bounces, bounded by total maximum",
 +        min=0, max=1024,
 +        default=4,
 +    )
 +    glossy_bounces: IntProperty(
 +        name="Glossy Bounces",
 +        description="Maximum number of glossy reflection bounces, bounded by total maximum",
 +        min=0, max=1024,
 +        default=4,
 +    )
 +    transmission_bounces: IntProperty(
 +        name="Transmission Bounces",
 +        description="Maximum number of transmission bounces, bounded by total maximum",
 +        min=0, max=1024,
 +        default=12,
 +    )
 +    volume_bounces: IntProperty(
 +        name="Volume Bounces",
 +        description="Maximum number of volumetric scattering events",
 +        min=0, max=1024,
 +        default=0,
 +    )
  
 -        cls.transparent_max_bounces = IntProperty(
 -            name="Transparent Max Bounces",
 -            description="Maximum number of transparent bounces",
 -            min=0, max=1024,
 -            default=8,
 -        )
 +    transparent_max_bounces: IntProperty(
 +        name="Transparent Max Bounces",
 +        description="Maximum number of transparent bounces",
 +        min=0, max=1024,
 +        default=8,
 +    )
  
 -        cls.volume_step_size = FloatProperty(
 -            name="Step Size",
 -            description="Distance between volume shader samples when rendering the volume "
 -            "(lower values give more accurate and detailed results, but also increased render time)",
 -            default=0.1,
 -            min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4
 -        )
 +    volume_step_size: FloatProperty(
 +        name="Step Size",
 +        description="Distance between volume shader samples when rendering the volume "
 +        "(lower values give more accurate and detailed results, but also increased render time)",
 +        default=0.1,
 +        min=0.0000001, max=100000.0, soft_min=0.01, soft_max=1.0, precision=4,
 +        unit='LENGTH'
 +    )
  
 -        cls.volume_max_steps = IntProperty(
 -            name="Max Steps",
 -            description="Maximum number of steps through the volume before giving up, "
 -            "to avoid extremely long render times with big objects or small step sizes",
 -            default=1024,
 -            min=2, max=65536
 -        )
 +    volume_max_steps: IntProperty(
 +        name="Max Steps",
 +        description="Maximum number of steps through the volume before giving up, "
 +        "to avoid extremely long render times with big objects or small step sizes",
 +        default=1024,
 +        min=2, max=65536
 +    )
  
 -        cls.dicing_rate = FloatProperty(
 -            name="Dicing Rate",
 -            description="Size of a micropolygon in pixels",
 -            min=0.1, max=1000.0, soft_min=0.5,
 -            default=1.0,
 -            subtype="PIXEL"
 -        )
 -        cls.preview_dicing_rate = FloatProperty(
 -            name="Preview Dicing Rate",
 -            description="Size of a micropolygon in pixels during preview render",
 -            min=0.1, max=1000.0, soft_min=0.5,
 -            default=8.0,
 -            subtype="PIXEL"
 -        )
 +    dicing_rate: FloatProperty(
 +        name="Dicing Rate",
 +        description="Size of a micropolygon in pixels",
 +        min=0.1, max=1000.0, soft_min=0.5,
 +        default=1.0,
 +        subtype='PIXEL'
 +    )
 +    preview_dicing_rate: FloatProperty(
 +        name="Preview Dicing Rate",
 +        description="Size of a micropolygon in pixels during preview render",
 +        min=0.1, max=1000.0, soft_min=0.5,
 +        default=8.0,
 +        subtype='PIXEL'
 +    )
  
 -        cls.max_subdivisions = IntProperty(
 -            name="Max Subdivisions",
 -            description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation",
 -            min=0, max=16,
 -            default=12,
 -        )
 +    max_subdivisions: IntProperty(
 +        name="Max Subdivisions",
 +        description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation",
 +        min=0, max=16,
 +        default=12,
 +    )
  
 -        cls.dicing_camera = PointerProperty(
 -            name="Dicing Camera",
 -            description="Camera to use as reference point when subdividing geometry, useful to avoid crawling "
 -            "artifacts in animations when the scene camera is moving",
 -            type=bpy.types.Object,
 -            poll=lambda self, obj: obj.type == 'CAMERA',
 -        )
 -        cls.offscreen_dicing_scale = FloatProperty(
 -            name="Offscreen Dicing Scale",
 -            description="Multiplier for dicing rate of geometry outside of the camera view. The dicing rate "
 -            "of objects is gradually increased the further they are outside the camera view. "
 -            "Lower values provide higher quality reflections and shadows for off screen objects, "
 -            "while higher values use less memory",
 -            min=1.0, soft_max=25.0,
 -            default=4.0,
 -        )
 +    dicing_camera: PointerProperty(
 +        name="Dicing Camera",
 +        description="Camera to use as reference point when subdividing geometry, useful to avoid crawling "
 +        "artifacts in animations when the scene camera is moving",
 +        type=bpy.types.Object,
 +        poll=lambda self, obj: obj.type == 'CAMERA',
 +    )
 +    offscreen_dicing_scale: FloatProperty(
 +        name="Offscreen Dicing Scale",
 +        description="Multiplier for dicing rate of geometry outside of the camera view. The dicing rate "
 +        "of objects is gradually increased the further they are outside the camera view. "
 +        "Lower values provide higher quality reflections and shadows for off screen objects, "
 +        "while higher values use less memory",
 +        min=1.0, soft_max=25.0,
 +        default=4.0,
 +    )
  
 -        cls.film_exposure = FloatProperty(
 -            name="Exposure",
 -            description="Image brightness scale",
 -            min=0.0, max=10.0,
 -            default=1.0,
 -        )
 -        cls.film_transparent = BoolProperty(
 -            name="Transparent",
 -            description="World background is transparent, for compositing the render over another background",
 -            default=False,
 -        )
 -        cls.film_transparent_glass = BoolProperty(
 -            name="Transparent Glass",
 -            description="Render transmissive surfaces as transparent, for compositing glass over another background",
 -            default=False,
 -        )
 -        cls.film_transparent_roughness = FloatProperty(
 -            name="Transparent Roughness Threshold",
 -            description="For transparent transmission, keep surfaces with roughness above the threshold opaque",
 -            min=0.0, max=1.0,
 -            default=0.1,
 -        )
 +    film_exposure: FloatProperty(
 +        name="Exposure",
 +        description="Image brightness scale",
 +        min=0.0, max=10.0,
 +        default=1.0,
 +    )
 +    film_transparent: BoolProperty(
 +        name="Transparent",
 +        description="World background is transparent, for compositing the render over another background",
 +        default=False,
 +    )
 +    film_transparent_glass: BoolProperty(
 +        name="Transparent Glass",
 +        description="Render transmissive surfaces as transparent, for compositing glass over another background",
 +        default=False,
 +    )
 +    film_transparent_roughness: FloatProperty(
 +        name="Transparent Roughness Threshold",
 +        description="For transparent transmission, keep surfaces with roughness above the threshold opaque",
 +        min=0.0, max=1.0,
 +        default=0.1,
 +    )
  
 -        # Really annoyingly, we have to keep it around for a few releases,
 -        # otherwise forward compatibility breaks in really bad manner: CRASH!
 -        #
 -        # TODO(sergey): Remove this during 2.8x series of Blender.
 -        cls.filter_type = EnumProperty(
 -            name="Filter Type",
 -            description="Pixel filter type",
 -            items=enum_filter_types,
 -            default='BLACKMAN_HARRIS',
 -        )
 +    # Really annoyingly, we have to keep it around for a few releases,
 +    # otherwise forward compatibility breaks in really bad manner: CRASH!
 +    #
 +    # TODO(sergey): Remove this during 2.8x series of Blender.
 +    filter_type: EnumProperty(
 +        name="Filter Type",
 +        description="Pixel filter type",
 +        items=enum_filter_types,
 +        default='BLACKMAN_HARRIS',
 +    )
  
 -        cls.pixel_filter_type = EnumProperty(
 -            name="Filter Type",
 -            description="Pixel filter type",
 -            items=enum_filter_types,
 -            default='BLACKMAN_HARRIS',
 -        )
 +    pixel_filter_type: EnumProperty(
 +        name="Filter Type",
 +        description="Pixel filter type",
 +        items=enum_filter_types,
 +        default='BLACKMAN_HARRIS',
 +    )
  
 -        cls.filter_width = FloatProperty(
 -            name="Filter Width",
 -            description="Pixel filter width",
 -            min=0.01, max=10.0,
 -            default=1.5,
 -        )
 +    filter_width: FloatProperty(
 +        name="Filter Width",
 +        description="Pixel filter width",
 +        min=0.01, max=10.0,
 +        default=1.5,
 +        subtype='PIXEL'
 +    )
  
 -        cls.seed = IntProperty(
 -            name="Seed",
 -            description="Seed value for integrator to get different noise patterns",
 -            min=0, max=2147483647,
 -            default=0,
 -        )
 +    seed: IntProperty(
 +        name="Seed",
 +        description="Seed value for integrator to get different noise patterns",
 +        min=0, max=2147483647,
 +        default=0,
 +    )
  
 -        cls.use_animated_seed = BoolProperty(
 -            name="Use Animated Seed",
 -            description="Use different seed values (and hence noise patterns) at different frames",
 -            default=False,
 -        )
 +    use_animated_seed: BoolProperty(
 +        name="Use Animated Seed",
 +        description="Use different seed values (and hence noise patterns) at different frames",
 +        default=False,
 +    )
  
 -        cls.sample_clamp_direct = FloatProperty(
 -            name="Clamp Direct",
 -            description="If non-zero, the maximum value for a direct sample, "
 -            "higher values will be scaled down to avoid too "
 -            "much noise and slow convergence at the cost of accuracy",
 -            min=0.0, max=1e8,
 -            default=0.0,
 -        )
 +    sample_clamp_direct: FloatProperty(
 +        name="Clamp Direct",
 +        description="If non-zero, the maximum value for a direct sample, "
 +        "higher values will be scaled down to avoid too "
 +        "much noise and slow convergence at the cost of accuracy",
 +        min=0.0, max=1e8,
 +        default=0.0,
 +    )
  
 -        cls.sample_clamp_indirect = FloatProperty(
 -            name="Clamp Indirect",
 -            description="If non-zero, the maximum value for an indirect sample, "
 -            "higher values will be scaled down to avoid too "
 -            "much noise and slow convergence at the cost of accuracy",
 -            min=0.0, max=1e8,
 -            default=10.0,
 -        )
 +    sample_clamp_indirect: FloatProperty(
 +        name="Clamp Indirect",
 +        description="If non-zero, the maximum value for an indirect sample, "
 +        "higher values will be scaled down to avoid too "
 +        "much noise and slow convergence at the cost of accuracy",
 +        min=0.0, max=1e8,
 +        default=10.0,
 +    )
  
 -        cls.debug_tile_size = IntProperty(
 -            name="Tile Size",
 -            description="",
 -            min=1, max=4096,
 -            default=1024,
 -        )
 +    debug_tile_size: IntProperty(
 +        name="Tile Size",
 +        description="",
 +        min=1, max=4096,
 +        default=1024,
 +    )
  
 -        cls.preview_start_resolution = IntProperty(
 -            name="Start Resolution",
 -            description="Resolution to start rendering preview at, "
 -            "progressively increasing it to the full viewport size",
 -            min=8, max=16384,
 -            default=64,
 -        )
 +    preview_start_resolution: IntProperty(
 +        name="Start Resolution",
 +        description="Resolution to start rendering preview at, "
 +        "progressively increasing it to the full viewport size",
 +        min=8, max=16384,
 +        default=64,
 +        subtype='PIXEL'
 +    )
  
 -        cls.debug_reset_timeout = FloatProperty(
 -            name="Reset timeout",
 -            description="",
 -            min=0.01, max=10.0,
 -            default=0.1,
 -        )
 -        cls.debug_cancel_timeout = FloatProperty(
 -            name="Cancel timeout",
 -            description="",
 -            min=0.01, max=10.0,
 -            default=0.1,
 -        )
 -        cls.debug_text_timeout = FloatProperty(
 -            name="Text timeout",
 -            description="",
 -            min=0.01, max=10.0,
 -            default=1.0,
 -        )
 +    debug_reset_timeout: FloatProperty(
 +        name="Reset timeout",
 +        description="",
 +        min=0.01, max=10.0,
 +        default=0.1,
 +    )
 +    debug_cancel_timeout: FloatProperty(
 +        name="Cancel timeout",
 +        description="",
 +        min=0.01, max=10.0,
 +        default=0.1,
 +    )
 +    debug_text_timeout: FloatProperty(
 +        name="Text timeout",
 +        description="",
 +        min=0.01, max=10.0,
 +        default=1.0,
 +    )
  
 -        cls.debug_bvh_type = EnumProperty(
 -            name="Viewport BVH Type",
 -            description="Choose between faster updates, or faster render",
 -            items=enum_bvh_types,
 -            default='DYNAMIC_BVH',
 -        )
 -        cls.debug_use_spatial_splits = BoolProperty(
 -            name="Use Spatial Splits",
 -            description="Use BVH spatial splits: longer builder time, faster render",
 -            default=False,
 -        )
 -        cls.debug_use_hair_bvh = BoolProperty(
 -            name="Use Hair BVH",
 -            description="Use special type BVH optimized for hair (uses more ram but renders faster)",
 -            default=True,
 -        )
 -        cls.use_bvh_embree = BoolProperty(
 -            name="Use Embree",
 -            description="Use Embree as ray accelerator",
 -            default=False,
 -        )
 -        cls.debug_bvh_time_steps = IntProperty(
 -            name="BVH Time Steps",
 -            description="Split BVH primitives by this number of time steps to speed up render time in cost of memory",
 -            default=0,
 -            min=0, max=16,
 -        )
 -        cls.tile_order = EnumProperty(
 -            name="Tile Order",
 -            description="Tile order for rendering",
 -            items=enum_tile_order,
 -            default='HILBERT_SPIRAL',
 -            options=set(),  # Not animatable!
 -        )
 -        cls.use_progressive_refine = BoolProperty(
 -            name="Progressive Refine",
 -            description="Instead of rendering each tile until it is finished, "
 -            "refine the whole image progressively "
 -            "(this renders somewhat slower, "
 -            "but time can be saved by manually stopping the render when the noise is low enough)",
 -            default=False,
 -        )
 +    debug_bvh_type: EnumProperty(
 +        name="Viewport BVH Type",
 +        description="Choose between faster updates, or faster render",
 +        items=enum_bvh_types,
 +        default='DYNAMIC_BVH',
 +    )
 +    use_bvh_embree: BoolProperty(
 +        name="Use Embree",
 +        description="Use Embree as ray accelerator",
 +        default=False,
 +    )
 +    debug_use_spatial_splits: BoolProperty(
 +        name="Use Spatial Splits",
 +        description="Use BVH spatial splits: longer builder time, faster render",
 +        default=False,
 +    )
 +    debug_use_hair_bvh: BoolProperty(
 +        name="Use Hair BVH",
 +        description="Use special type BVH optimized for hair (uses more ram but renders faster)",
 +        default=True,
 +    )
 +    debug_bvh_time_steps: IntProperty(
 +        name="BVH Time Steps",
 +        description="Split BVH primitives by this number of time steps to speed up render time in cost of memory",
 +        default=0,
 +        min=0, max=16,
 +    )
 +    tile_order: EnumProperty(
 +        name="Tile Order",
 +        description="Tile order for rendering",
 +        items=enum_tile_order,
 +        default='HILBERT_SPIRAL',
 +        options=set(),  # Not animatable!
 +    )
 +    use_progressive_refine: BoolProperty(
 +        name="Progressive Refine",
 +        description="Instead of rendering each tile until it is finished, "
 +        "refine the whole image progressively "
 +        "(this renders somewhat slower, "
 +        "but time can be saved by manually stopping the render when the noise is low enough)",
 +        default=False,
 +    )
  
 -        cls.bake_type = EnumProperty(
 -            name="Bake Type",
 -            default='COMBINED',
 -            description="Type of pass to bake",
 -            items=(
 -                ('COMBINED', "Combined", ""),
 -                ('AO', "Ambient Occlusion", ""),
 -                ('SHADOW', "Shadow", ""),
 -                ('NORMAL', "Normal", ""),
 -                ('UV', "UV", ""),
 -                ('ROUGHNESS', "Roughness", ""),
 -                ('EMIT', "Emit", ""),
 -                ('ENVIRONMENT', "Environment", ""),
 -                ('DIFFUSE', "Diffuse", ""),
 -                ('GLOSSY', "Glossy", ""),
 -                ('TRANSMISSION', "Transmission", ""),
 -                ('SUBSURFACE', "Subsurface", ""),
 -            ),
 -        )
 +    bake_type: EnumProperty(
 +        name="Bake Type",
 +        default='COMBINED',
 +        description="Type of pass to bake",
 +        items=(
 +            ('COMBINED', "Combined", ""),
 +            ('AO', "Ambient Occlusion", ""),
 +            ('SHADOW', "Shadow", ""),
 +            ('NORMAL', "Normal", ""),
 +            ('UV', "UV", ""),
 +            ('ROUGHNESS', "Roughness", ""),
 +            ('EMIT', "Emit", ""),
 +            ('ENVIRONMENT', "Environment", ""),
 +            ('DIFFUSE', "Diffuse", ""),
 +            ('GLOSSY', "Glossy", ""),
 +            ('TRANSMISSION', "Transmission", ""),
 +            ('SUBSURFACE', "Subsurface", ""),
 +        ),
 +    )
  
 -        cls.use_camera_cull = BoolProperty(
 -            name="Use Camera Cull",
 -            description="Allow objects to be culled based on the camera frustum",
 -            default=False,
 -        )
 +    use_camera_cull: BoolProperty(
 +        name="Use Camera Cull",
 +        description="Allow objects to be culled based on the camera frustum",
 +        default=False,
 +    )
  
 -        cls.camera_cull_margin = FloatProperty(
 -            name="Camera Cull Margin",
 -            description="Margin for the camera space culling",
 -            default=0.1,
 -            min=0.0, max=5.0
 -        )
 +    camera_cull_margin: FloatProperty(
 +        name="Camera Cull Margin",
 +        description="Margin for the camera space culling",
 +        default=0.1,
 +        min=0.0, max=5.0,
 +        subtype='FACTOR'
 +    )
  
 -        cls.use_distance_cull = BoolProperty(
 -            name="Use Distance Cull",
 -            description="Allow objects to be culled based on the distance from camera",
 -            default=False,
 -        )
 +    use_distance_cull: BoolProperty(
 +        name="Use Distance Cull",
 +        description="Allow objects to be culled based on the distance from camera",
 +        default=False,
 +    )
  
 -        cls.distance_cull_margin = FloatProperty(
 -            name="Cull Distance",
 -            description="Cull objects which are further away from camera than this distance",
 -            default=50,
 -            min=0.0
 -        )
 +    distance_cull_margin: FloatProperty(
 +        name="Cull Distance",
 +        description="Cull objects which are further away from camera than this distance",
 +        default=50,
 +        min=0.0,
 +        unit='LENGTH'
 +    )
  
 -        cls.motion_blur_position = EnumProperty(
 -            name="Motion Blur Position",
 -            default='CENTER',
 -            description="Offset for the shutter's time interval, allows to change the motion blur trails",
 -            items=(
 -                ('START', "Start on Frame", "The shutter opens at the current frame"),
 -                ('CENTER', "Center on Frame", "The shutter is open during the current frame"),
 -                ('END', "End on Frame", "The shutter closes at the current frame"),
 -            ),
 -        )
 +    motion_blur_position: EnumProperty(
 +        name="Motion Blur Position",
 +        default='CENTER',
 +        description="Offset for the shutter's time interval, allows to change the motion blur trails",
 +        items=(
 +            ('START', "Start on Frame", "The shutter opens at the current frame"),
 +            ('CENTER', "Center on Frame", "The shutter is open during the current frame"),
 +            ('END', "End on Frame", "The shutter closes at the current frame"),
 +        ),
 +    )
  
 -        cls.rolling_shutter_type = EnumProperty(
 -            name="Shutter Type",
 -            default='NONE',
 -            description="Type of rolling shutter effect matching CMOS-based cameras",
 -            items=(
 -                ('NONE', "None", "No rolling shutter effect used"),
 -                ('TOP', "Top-Bottom", "Sensor is being scanned from top to bottom")
 -                # TODO(seergey): Are there real cameras with different scanning direction?
 -            ),
 -        )
 +    rolling_shutter_type: EnumProperty(
 +        name="Shutter Type",
 +        default='NONE',
 +        description="Type of rolling shutter effect matching CMOS-based cameras",
 +        items=(
 +            ('NONE', "None", "No rolling shutter effect used"),
 +            ('TOP', "Top-Bottom", "Sensor is being scanned from top to bottom")
 +            # TODO(seergey): Are there real cameras with different scanning direction?
 +        ),
 +    )
  
 -        cls.rolling_shutter_duration = FloatProperty(
 -            name="Rolling Shutter Duration",
 -            description="Scanline \"exposure\" time for the rolling shutter effect",
 -            default=0.1,
 -            min=0.0, max=1.0,
 -        )
 +    rolling_shutter_duration: FloatProperty(
 +        name="Rolling Shutter Duration",
 +        description="Scanline \"exposure\" time for the rolling shutter effect",
 +        default=0.1,
 +        min=0.0, max=1.0,
 +    )
  
 -        cls.texture_limit = EnumProperty(
 -            name="Viewport Texture Limit",
 -            default='OFF',
 -            description="Limit texture size used by viewport rendering",
 -            items=enum_texture_limit
 -        )
 +    texture_limit: EnumProperty(
 +        name="Viewport Texture Limit",
 +        default='OFF',
 +        description="Limit texture size used by viewport rendering",
 +        items=enum_texture_limit
 +    )
  
 -        cls.texture_limit_render = EnumProperty(
 -            name="Render Texture Limit",
 -            default='OFF',
 -            description="Limit texture size used by final rendering",
 -            items=enum_texture_limit
 -        )
 +    texture_limit_render: EnumProperty(
 +        name="Render Texture Limit",
 +        default='OFF',
 +        description="Limit texture size used by final rendering",
 +        items=enum_texture_limit
 +    )
  
 -        cls.ao_bounces = IntProperty(
 -            name="AO Bounces",
 -            default=0,
 -            description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
 -            min=0, max=1024,
 -        )
 +    ao_bounces: IntProperty(
 +        name="AO Bounces",
 +        default=0,
 +        description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
 +        min=0, max=1024,
 +    )
  
 -        cls.ao_bounces_render = IntProperty(
 -            name="AO Bounces Render",
 -            default=0,
 -            description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
 -            min=0, max=1024,
 -        )
 +    ao_bounces_render: IntProperty(
 +        name="AO Bounces Render",
 +        default=0,
 +        description="Approximate indirect light with background tinted ambient occlusion at the specified bounce, 0 disables this feature",
 +        min=0, max=1024,
 +    )
  
 -        # Various fine-tuning debug flags
 -
 -        def devices_update_callback(self, context):
 -            import _cycles
 -            scene = context.scene.as_pointer()
 -            return _cycles.debug_flags_update(scene)
 -
 -        cls.debug_use_cpu_avx2 = BoolProperty(name="AVX2", default=True)
 -        cls.debug_use_cpu_avx = BoolProperty(name="AVX", default=True)
 -        cls.debug_use_cpu_sse41 = BoolProperty(name="SSE41", default=True)
 -        cls.debug_use_cpu_sse3 = BoolProperty(name="SSE3", default=True)
 -        cls.debug_use_cpu_sse2 = BoolProperty(name="SSE2", default=True)
 -        cls.debug_bvh_layout = EnumProperty(
 -            name="BVH Layout",
 -            items=enum_bvh_layouts,
 -            default='BVH8',
 -        )
 -        cls.debug_use_cpu_split_kernel = BoolProperty(name="Split Kernel", default=False)
 -
 -        cls.debug_use_cuda_adaptive_compile = BoolProperty(name="Adaptive Compile", default=False)
 -        cls.debug_use_cuda_split_kernel = BoolProperty(name="Split Kernel", default=False)
 -
 -        cls.debug_opencl_kernel_type = EnumProperty(
 -            name="OpenCL Kernel Type",
 -            default='DEFAULT',
 -            items=(
 -                ('DEFAULT', "Default", ""),
 -                ('MEGA', "Mega", ""),
 -                ('SPLIT', "Split", ""),
 -            ),
 -            update=devices_update_callback
 -        )
 +    # Various fine-tuning debug flags
  
 -        cls.debug_opencl_device_type = EnumProperty(
 -            name="OpenCL Device Type",
 -            default='ALL',
 -            items=(
 -                ('NONE', "None", ""),
 -                ('ALL', "All", ""),
 -                ('DEFAULT', "Default", ""),
 -                ('CPU', "CPU", ""),
 -                ('GPU', "GPU", ""),
 -                ('ACCELERATOR', "Accelerator", ""),
 -            ),
 -            update=devices_update_callback
 -        )
 +    def _devices_update_callback(self, context):
 +        import _cycles
 +        scene = context.scene.as_pointer()
 +        return _cycles.debug_flags_update(scene)
 +
 +    debug_use_cpu_avx2: BoolProperty(name="AVX2", default=True)
 +    debug_use_cpu_avx: BoolProperty(name="AVX", default=True)
 +    debug_use_cpu_sse41: BoolProperty(name="SSE41", default=True)
 +    debug_use_cpu_sse3: BoolProperty(name="SSE3", default=True)
 +    debug_use_cpu_sse2: BoolProperty(name="SSE2", default=True)
 +    debug_bvh_layout: EnumProperty(
 +        name="BVH Layout",
 +        items=enum_bvh_layouts,
 +        default='BVH8',
 +    )
 +    debug_use_cpu_split_kernel: BoolProperty(name="Split Kernel", default=False)
 +
 +    debug_use_cuda_adaptive_compile: BoolProperty(name="Adaptive Compile", default=False)
 +    debug_use_cuda_split_kernel: BoolProperty(name="Split Kernel", default=False)
 +
 +    debug_opencl_kernel_type: EnumProperty(
 +        name="OpenCL Kernel Type",
 +        default='DEFAULT',
 +        items=(
 +            ('DEFAULT', "Default", ""),
 +            ('MEGA', "Mega", ""),
 +            ('SPLIT', "Split", ""),
 +        ),
 +        update=_devices_update_callback
 +    )
  
 -        cls.debug_opencl_kernel_single_program = BoolProperty(
 -            name="Single Program",
 -            default=True,
 -            update=devices_update_callback,
 -        )
 +    debug_opencl_device_type: EnumProperty(
 +        name="OpenCL Device Type",
 +        default='ALL',
 +        items=(
 +            ('NONE', "None", ""),
 +            ('ALL', "All", ""),
 +            ('DEFAULT', "Default", ""),
 +            ('CPU', "CPU", ""),
 +            ('GPU', "GPU", ""),
 +            ('ACCELERATOR', "Accelerator", ""),
 +        ),
 +        update=_devices_update_callback
 +    )
 +
 +    debug_opencl_kernel_single_program: BoolProperty(
 +        name="Single Program",
 +        default=True,
 +        update=_devices_update_callback,
 +    )
 +    del _devices_update_callback
  
 -        cls.debug_use_opencl_debug = BoolProperty(name="Debug OpenCL", default=False)
 +    debug_use_opencl_debug: BoolProperty(name="Debug OpenCL", default=False)
  
 -        cls.debug_opencl_mem_limit = IntProperty(name="Memory limit", default=0,
 -                                                 description="Artificial limit on OpenCL memory usage in MB (0 to disable limit)")
 +    debug_opencl_mem_limit: IntProperty(
 +        name="Memory limit",
 +        default=0,
 +        description="Artificial limit on OpenCL memory usage in MB (0 to disable limit)"
 +    )
 +
 +    @classmethod
 +    def register(cls):
 +        bpy.types.Scene.cycles = PointerProperty(
 +            name="Cycles Render Settings",
 +            description="Cycles render settings",
 +            type=cls,
 +        )
  
      @classmethod
      def unregister(cls):
  
  
  class CyclesCameraSettings(bpy.types.PropertyGroup):
 +
 +    aperture_type: EnumProperty(
 +        name="Aperture Type",
 +        description="Use f-stop number or aperture radius",
 +        items=enum_aperture_types,
 +        default='RADIUS',
 +    )
 +    aperture_fstop: FloatProperty(
 +        name="Aperture f-stop",
 +        description="F-stop ratio (lower numbers give more defocus, higher numbers give a sharper image)",
 +        min=0.0, soft_min=0.1, soft_max=64.0,
 +        default=5.6,
 +        step=10,
 +        precision=1,
 +    )
 +    aperture_size: FloatProperty(
 +        name="Aperture Size",
 +        description="Radius of the aperture for depth of field (higher values give more defocus)",
 +        min=0.0, soft_max=10.0,
 +        default=0.0,
 +        step=1,
 +        precision=4,
 +        subtype='DISTANCE',
 +    )
 +    aperture_blades: IntProperty(
 +        name="Aperture Blades",
 +        description="Number of blades in aperture for polygonal bokeh (at least 3)",
 +        min=0, max=100,
 +        default=0,
 +    )
 +    aperture_rotation: FloatProperty(
 +        name="Aperture Rotation",
 +        description="Rotation of blades in aperture",
 +        soft_min=-pi, soft_max=pi,
 +        subtype='ANGLE',
 +        default=0,
 +    )
 +    aperture_ratio: FloatProperty(
 +        name="Aperture Ratio",
 +        description="Distortion to simulate anamorphic lens bokeh",
 +        min=0.01, soft_min=1.0, soft_max=2.0,
 +        default=1.0,
 +        precision=4,
 +    )
 +    panorama_type: EnumProperty(
 +        name="Panorama Type",
 +        description="Distortion to use for the calculation",
 +        items=enum_panorama_types,
 +        default='FISHEYE_EQUISOLID',
 +    )
 +    fisheye_fov: FloatProperty(
 +        name="Field of View",
 +        description="Field of view for the fisheye lens",
 +        min=0.1745, soft_max=2.0 * pi, max=10.0 * pi,
 +        subtype='ANGLE',
 +        default=pi,
 +    )
 +    fisheye_lens: FloatProperty(
 +        name="Fisheye Lens",
 +        description="Lens focal length (mm)",
 +        min=0.01, soft_max=15.0, max=100.0,
 +        default=10.5,
 +    )
 +    latitude_min: FloatProperty(
 +        name="Min Latitude",
 +        description="Minimum latitude (vertical angle) for the equirectangular lens",
 +        min=-0.5 * pi, max=0.5 * pi,
 +        subtype='ANGLE',
 +        default=-0.5 * pi,
 +    )
 +    latitude_max: FloatProperty(
 +        name="Max Latitude",
 +        description="Maximum latitude (vertical angle) for the equirectangular lens",
 +        min=-0.5 * pi, max=0.5 * pi,
 +        subtype='ANGLE',
 +        default=0.5 * pi,
 +    )
 +    longitude_min: FloatProperty(
 +        name="Min Longitude",
 +        description="Minimum longitude (horizontal angle) for the equirectangular lens",
 +        min=-pi, max=pi,
 +        subtype='ANGLE',
 +        default=-pi,
 +    )
 +    longitude_max: FloatProperty(
 +        name="Max Longitude",
 +        description="Maximum longitude (horizontal angle) for the equirectangular lens",
 +        min=-pi, max=pi,
 +        subtype='ANGLE',
 +        default=pi,
 +    )
 +
      @classmethod
      def register(cls):
 -        import math
 -
          bpy.types.Camera.cycles = PointerProperty(
              name="Cycles Camera Settings",
              description="Cycles camera settings",
              type=cls,
          )
  
 -        cls.aperture_type = EnumProperty(
 -            name="Aperture Type",
 -            description="Use f-stop number or aperture radius",
 -            items=enum_aperture_types,
 -            default='RADIUS',
 -        )
 -        cls.aperture_fstop = FloatProperty(
 -            name="Aperture f-stop",
 -            description="F-stop ratio (lower numbers give more defocus, higher numbers give a sharper image)",
 -            min=0.0, soft_min=0.1, soft_max=64.0,
 -            default=5.6,
 -            step=10,
 -            precision=1,
 -        )
 -        cls.aperture_size = FloatProperty(
 -            name="Aperture Size",
 -            description="Radius of the aperture for depth of field (higher values give more defocus)",
 -            min=0.0, soft_max=10.0,
 -            default=0.0,
 -            step=1,
 -            precision=4,
 -            subtype='DISTANCE',
 -        )
 -        cls.aperture_blades = IntProperty(
 -            name="Aperture Blades",
 -            description="Number of blades in aperture for polygonal bokeh (at least 3)",
 -            min=0, max=100,
 -            default=0,
 -        )
 -        cls.aperture_rotation = FloatProperty(
 -            name="Aperture Rotation",
 -            description="Rotation of blades in aperture",
 -            soft_min=-math.pi, soft_max=math.pi,
 -            subtype='ANGLE',
 -            default=0,
 -        )
 -        cls.aperture_ratio = FloatProperty(
 -            name="Aperture Ratio",
 -            description="Distortion to simulate anamorphic lens bokeh",
 -            min=0.01, soft_min=1.0, soft_max=2.0,
 -            default=1.0,
 -            precision=4,
 -        )
 -        cls.panorama_type = EnumProperty(
 -            name="Panorama Type",
 -            description="Distortion to use for the calculation",
 -            items=enum_panorama_types,
 -            default='FISHEYE_EQUISOLID',
 -        )
 -        cls.fisheye_fov = FloatProperty(
 -            name="Field of View",
 -            description="Field of view for the fisheye lens",
 -            min=0.1745, soft_max=2.0 * math.pi, max=10.0 * math.pi,
 -            subtype='ANGLE',
 -            default=math.pi,
 -        )
 -        cls.fisheye_lens = FloatProperty(
 -            name="Fisheye Lens",
 -            description="Lens focal length (mm)",
 -            min=0.01, soft_max=15.0, max=100.0,
 -            default=10.5,
 -        )
 -        cls.latitude_min = FloatProperty(
 -            name="Min Latitude",
 -            description="Minimum latitude (vertical angle) for the equirectangular lens",
 -            min=-0.5 * math.pi, max=0.5 * math.pi,
 -            subtype='ANGLE',
 -            default=-0.5 * math.pi,
 -        )
 -        cls.latitude_max = FloatProperty(
 -            name="Max Latitude",
 -            description="Maximum latitude (vertical angle) for the equirectangular lens",
 -            min=-0.5 * math.pi, max=0.5 * math.pi,
 -            subtype='ANGLE',
 -            default=0.5 * math.pi,
 -        )
 -        cls.longitude_min = FloatProperty(
 -            name="Min Longitude",
 -            description="Minimum longitude (horizontal angle) for the equirectangular lens",
 -            min=-math.pi, max=math.pi,
 -            subtype='ANGLE',
 -            default=-math.pi,
 -        )
 -        cls.longitude_max = FloatProperty(
 -            name="Max Longitude",
 -            description="Maximum longitude (horizontal angle) for the equirectangular lens",
 -            min=-math.pi, max=math.pi,
 -            subtype='ANGLE',
 -            default=math.pi,
 -        )
 -
      @classmethod
      def unregister(cls):
          del bpy.types.Camera.cycles
  
  
  class CyclesMaterialSettings(bpy.types.PropertyGroup):
 +
 +    sample_as_light: BoolProperty(
 +        name="Multiple Importance Sample",
 +        description="Use multiple importance sampling for this material, "
 +        "disabling may reduce overall noise for large "
 +        "objects that emit little light compared to other light sources",
 +        default=True,
 +    )
 +    use_transparent_shadow: BoolProperty(
 +        name="Transparent Shadows",
 +        description="Use transparent shadows for this material if it contains a Transparent BSDF, "
 +        "disabling will render faster but not give accurate shadows",
 +        default=True,
 +    )
 +    homogeneous_volume: BoolProperty(
 +        name="Homogeneous Volume",
 +        description="When using volume rendering, assume volume has the same density everywhere "
 +        "(not using any textures), for faster rendering",
 +        default=False,
 +    )
 +    volume_sampling: EnumProperty(
 +        name="Volume Sampling",
 +        description="Sampling method to use for volumes",
 +        items=enum_volume_sampling,
 +        default='MULTIPLE_IMPORTANCE',
 +    )
 +
 +    volume_interpolation: EnumProperty(
 +        name="Volume Interpolation",
 +        description="Interpolation method to use for smoke/fire volumes",
 +        items=enum_volume_interpolation,
 +        default='LINEAR',
 +    )
 +
 +    displacement_method: EnumProperty(
 +        name="Displacement Method",
 +        description="Method to use for the displacement",
 +        items=enum_displacement_methods,
 +        default='BUMP',
 +    )
 +
      @classmethod
      def register(cls):
          bpy.types.Material.cycles = PointerProperty(
              description="Cycles material settings",
              type=cls,
          )
 -        cls.sample_as_light = BoolProperty(
 -            name="Multiple Importance Sample",
 -            description="Use multiple importance sampling for this material, "
 -            "disabling may reduce overall noise for large "
 -            "objects that emit little light compared to other light sources",
 -            default=True,
 -        )
 -        cls.use_transparent_shadow = BoolProperty(
 -            name="Transparent Shadows",
 -            description="Use transparent shadows for this material if it contains a Transparent BSDF, "
 -            "disabling will render faster but not give accurate shadows",
 -            default=True,
 -        )
 -        cls.homogeneous_volume = BoolProperty(
 -            name="Homogeneous Volume",
 -            description="When using volume rendering, assume volume has the same density everywhere "
 -            "(not using any textures), for faster rendering",
 -            default=False,
 -        )
 -        cls.volume_sampling = EnumProperty(
 -            name="Volume Sampling",
 -            description="Sampling method to use for volumes",
 -            items=enum_volume_sampling,
 -            default='MULTIPLE_IMPORTANCE',
 -        )
 -
 -        cls.volume_interpolation = EnumProperty(
 -            name="Volume Interpolation",
 -            description="Interpolation method to use for smoke/fire volumes",
 -            items=enum_volume_interpolation,
 -            default='LINEAR',
 -        )
 -
 -        cls.displacement_method = EnumProperty(
 -            name="Displacement Method",
 -            description="Method to use for the displacement",
 -            items=enum_displacement_methods,
 -            default='BUMP',
 -        )
  
      @classmethod
      def unregister(cls):
          del bpy.types.Material.cycles
  
  
 -class CyclesLampSettings(bpy.types.PropertyGroup):
 +class CyclesLightSettings(bpy.types.PropertyGroup):
 +
 +    cast_shadow: BoolProperty(
 +        name="Cast Shadow",
 +        description="Light casts shadows",
 +        default=True,
 +    )
 +    samples: IntProperty(
 +        name="Samples",
 +        description="Number of light samples to render for each AA sample",
 +        min=1, max=10000,
 +        default=1,
 +    )
 +    max_bounces: IntProperty(
 +        name="Max Bounces",
 +        description="Maximum number of bounces the light will contribute to the render",
 +        min=0, max=1024,
 +        default=1024,
 +    )
 +    use_multiple_importance_sampling: BoolProperty(
 +        name="Multiple Importance Sample",
 +        description="Use multiple importance sampling for the light, "
 +        "reduces noise for area lights and sharp glossy materials",
 +        default=True,
 +    )
 +    is_portal: BoolProperty(
 +        name="Is Portal",
 +        description="Use this area light to guide sampling of the background, "
 +        "note that this will make the light invisible",
 +        default=False,
 +    )
 +
      @classmethod
      def register(cls):
 -        bpy.types.Lamp.cycles = PointerProperty(
 -            name="Cycles Lamp Settings",
 -            description="Cycles lamp settings",
 +        bpy.types.Light.cycles = PointerProperty(
 +            name="Cycles Light Settings",
 +            description="Cycles light settings",
              type=cls,
          )
 -        cls.cast_shadow = BoolProperty(
 -            name="Cast Shadow",
 -            description="Lamp casts shadows",
 -            default=True,
 -        )
 -        cls.samples = IntProperty(
 -            name="Samples",
 -            description="Number of light samples to render for each AA sample",
 -            min=1, max=10000,
 -            default=1,
 -        )
 -        cls.max_bounces = IntProperty(
 -            name="Max Bounces",
 -            description="Maximum number of bounces the light will contribute to the render",
 -            min=0, max=1024,
 -            default=1024,
 -        )
 -        cls.use_multiple_importance_sampling = BoolProperty(
 -            name="Multiple Importance Sample",
 -            description="Use multiple importance sampling for the lamp, "
 -            "reduces noise for area lamps and sharp glossy materials",
 -            default=True,
 -        )
 -        cls.is_portal = BoolProperty(
 -            name="Is Portal",
 -            description="Use this area lamp to guide sampling of the background, "
 -            "note that this will make the lamp invisible",
 -            default=False,
 -        )
  
      @classmethod
      def unregister(cls):
 -        del bpy.types.Lamp.cycles
 +        del bpy.types.Light.cycles
  
  
  class CyclesWorldSettings(bpy.types.PropertyGroup):
 +
 +    sampling_method: EnumProperty(
 +        name="Sampling method",
 +        description="How to sample the background light",
 +        items=enum_world_mis,
 +        default='AUTOMATIC',
 +    )
 +    sample_map_resolution: IntProperty(
 +        name="Map Resolution",
 +        description="Importance map size is resolution x resolution/2; "
 +        "higher values potentially produce less noise, at the cost of memory and speed",
 +        min=4, max=8192,
 +        default=1024,
 +    )
 +    samples: IntProperty(
 +        name="Samples",
 +        description="Number of light samples to render for each AA sample",
 +        min=1, max=10000,
 +        default=1,
 +    )
 +    max_bounces: IntProperty(
 +        name="Max Bounces",
 +        description="Maximum number of bounces the background light will contribute to the render",
 +        min=0, max=1024,
 +        default=1024,
 +    )
 +    homogeneous_volume: BoolProperty(
 +        name="Homogeneous Volume",
 +        description="When using volume rendering, assume volume has the same density everywhere"
 +        "(not using any textures), for faster rendering",
 +        default=False,
 +    )
 +    volume_sampling: EnumProperty(
 +        name="Volume Sampling",
 +        description="Sampling method to use for volumes",
 +        items=enum_volume_sampling,
 +        default='EQUIANGULAR',
 +    )
 +    volume_interpolation: EnumProperty(
 +        name="Volume Interpolation",
 +        description="Interpolation method to use for volumes",
 +        items=enum_volume_interpolation,
 +        default='LINEAR',
 +    )
 +
      @classmethod
      def register(cls):
          bpy.types.World.cycles = PointerProperty(
              description="Cycles world settings",
              type=cls,
          )
 -        cls.sampling_method = EnumProperty(
 -            name="Sampling method",
 -            description="How to sample the background light",
 -            items=enum_world_mis,
 -            default='AUTOMATIC',
 -        )
 -        cls.sample_map_resolution = IntProperty(
 -            name="Map Resolution",
 -            description="Importance map size is resolution x resolution/2; "
 -            "higher values potentially produce less noise, at the cost of memory and speed",
 -            min=4, max=8192,
 -            default=1024,
 -        )
 -        cls.samples = IntProperty(
 -            name="Samples",
 -            description="Number of light samples to render for each AA sample",
 -            min=1, max=10000,
 -            default=1,
 -        )
 -        cls.max_bounces = IntProperty(
 -            name="Max Bounces",
 -            description="Maximum number of bounces the background light will contribute to the render",
 -            min=0, max=1024,
 -            default=1024,
 -        )
 -        cls.homogeneous_volume = BoolProperty(
 -            name="Homogeneous Volume",
 -            description="When using volume rendering, assume volume has the same density everywhere"
 -            "(not using any textures), for faster rendering",
 -            default=False,
 -        )
 -        cls.volume_sampling = EnumProperty(
 -            name="Volume Sampling",
 -            description="Sampling method to use for volumes",
 -            items=enum_volume_sampling,
 -            default='EQUIANGULAR',
 -        )
 -
 -        cls.volume_interpolation = EnumProperty(
 -            name="Volume Interpolation",
 -            description="Interpolation method to use for volumes",
 -            items=enum_volume_interpolation,
 -            default='LINEAR',
 -        )
  
      @classmethod
      def unregister(cls):
  
  
  class CyclesVisibilitySettings(bpy.types.PropertyGroup):
 +
 +    camera: BoolProperty(
 +        name="Camera",
 +        description="Object visibility for camera rays",
 +        default=True,
 +    )
 +    diffuse: BoolProperty(
 +        name="Diffuse",
 +        description="Object visibility for diffuse reflection rays",
 +        default=True,
 +    )
 +    glossy: BoolProperty(
 +        name="Glossy",
 +        description="Object visibility for glossy reflection rays",
 +        default=True,
 +    )
 +    transmission: BoolProperty(
 +        name="Transmission",
 +        description="Object visibility for transmission rays",
 +        default=True,
 +    )
 +    shadow: BoolProperty(
 +        name="Shadow",
 +        description="Object visibility for shadow rays",
 +        default=True,
 +    )
 +    scatter: BoolProperty(
 +        name="Volume Scatter",
 +        description="Object visibility for volume scatter rays",
 +        default=True,
 +    )
 +
      @classmethod
      def register(cls):
          bpy.types.Object.cycles_visibility = PointerProperty(
              type=cls,
          )
  
 -        cls.camera = BoolProperty(
 -            name="Camera",
 -            description="Object visibility for camera rays",
 -            default=True,
 -        )
 -        cls.diffuse = BoolProperty(
 -            name="Diffuse",
 -            description="Object visibility for diffuse reflection rays",
 -            default=True,
 -        )
 -        cls.glossy = BoolProperty(
 -            name="Glossy",
 -            description="Object visibility for glossy reflection rays",
 -            default=True,
 -        )
 -        cls.transmission = BoolProperty(
 -            name="Transmission",
 -            description="Object visibility for transmission rays",
 -            default=True,
 -        )
 -        cls.shadow = BoolProperty(
 -            name="Shadow",
 -            description="Object visibility for shadow rays",
 -            default=True,
 -        )
 -        cls.scatter = BoolProperty(
 -            name="Volume Scatter",
 -            description="Object visibility for volume scatter rays",
 -            default=True,
 -        )
 -
      @classmethod
      def unregister(cls):
          del bpy.types.Object.cycles_visibility
@@@ -1094,71 -1080,70 +1094,71 @@@ class CyclesMeshSettings(bpy.types.Prop
  
  
  class CyclesObjectSettings(bpy.types.PropertyGroup):
 -    @classmethod
 -    def register(cls):
 -        bpy.types.Object.cycles = PointerProperty(
 -            name="Cycles Object Settings",
 -            description="Cycles object settings",
 -            type=cls,
 -        )
  
 -        cls.use_motion_blur = BoolProperty(
 -            name="Use Motion Blur",
 -            description="Use motion blur for this object",
 -            default=True,
 -        )
 +    use_motion_blur: BoolProperty(
 +        name="Use Motion Blur",
 +        description="Use motion blur for this object",
 +        default=True,
 +    )
  
 -        cls.use_deform_motion = BoolProperty(
 -            name="Use Deformation Motion",
 -            description="Use deformation motion blur for this object",
 -            default=True,
 -        )
 +    use_deform_motion: BoolProperty(
 +        name="Use Deformation Motion",
 +        description="Use deformation motion blur for this object",
 +        default=True,
 +    )
  
 -        cls.motion_steps = IntProperty(
 -            name="Motion Steps",
 -            description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
 -            min=1, soft_max=8,
 -            default=1,
 -        )
 +    motion_steps: IntProperty(
 +        name="Motion Steps",
 +        description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
 +        min=1, soft_max=8,
 +        default=1,
 +    )
  
 -        cls.use_camera_cull = BoolProperty(
 -            name="Use Camera Cull",
 -            description="Allow this object and its duplicators to be culled by camera space culling",
 -            default=False,
 -        )
 +    use_camera_cull: BoolProperty(
 +        name="Use Camera Cull",
 +        description="Allow this object and its duplicators to be culled by camera space culling",
 +        default=False,
 +    )
  
 -        cls.use_distance_cull = BoolProperty(
 -            name="Use Distance Cull",
 -            description="Allow this object and its duplicators to be culled by distance from camera",
 -            default=False,
 -        )
 +    use_distance_cull: BoolProperty(
 +        name="Use Distance Cull",
 +        description="Allow this object and its duplicators to be culled by distance from camera",
 +        default=False,
 +    )
  
 -        cls.use_adaptive_subdivision = BoolProperty(
 -            name="Use Adaptive Subdivision",
 -            description="Use adaptive render time subdivision",
 -            default=False,
 -        )
 +    use_adaptive_subdivision: BoolProperty(
 +        name="Use Adaptive Subdivision",
 +        description="Use adaptive render time subdivision",
 +        default=False,
 +    )
  
 -        cls.dicing_rate = FloatProperty(
 -            name="Dicing Scale",
 -            description="Multiplier for scene dicing rate (located in the Geometry Panel)",
 -            min=0.1, max=1000.0, soft_min=0.5,
 -            default=1.0,
 -        )
 +    dicing_rate: FloatProperty(
 +        name="Dicing Scale",
 +        description="Multiplier for scene dicing rate (located in the Subdivision panel)",
 +        min=0.1, max=1000.0, soft_min=0.5,
 +        default=1.0,
 +    )
  
 -        cls.is_shadow_catcher = BoolProperty(
 -            name="Shadow Catcher",
 -            description="Only render shadows on this object, for compositing renders into real footage",
 -            default=False,
 -        )
 +    is_shadow_catcher: BoolProperty(
 +        name="Shadow Catcher",
 +        description="Only render shadows on this object, for compositing renders into real footage",
 +        default=False,
 +    )
 +
 +    is_holdout: BoolProperty(
 +        name="Holdout",
 +        description="Render objects as a holdout or matte, creating a "
 +        "hole in the image with zero alpha, to fill out in "
 +        "compositing with real footage or another render",
 +        default=False,
 +    )
  
 -        cls.is_holdout = BoolProperty(
 -            name="Holdout",
 -            description="Render objects as a holdout or matte, creating a "
 -            "hole in the image with zero alpha, to fill out in "
 -            "compositing with real footange or another render",
 -            default=False,
 +    @classmethod
 +    def register(cls):
 +        bpy.types.Object.cycles = PointerProperty(
 +            name="Cycles Object Settings",
 +            description="Cycles object settings",
 +            type=cls,
          )
  
      @classmethod
  
  
  class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
 +
 +    primitive: EnumProperty(
 +        name="Primitive",
 +        description="Type of primitive used for hair rendering",
 +        items=enum_curve_primitives,
 +        default='LINE_SEGMENTS',
 +    )
 +    shape: EnumProperty(
 +        name="Shape",
 +        description="Form of hair",
 +        items=enum_curve_shape,
 +        default='THICK',
 +    )
 +    cull_backfacing: BoolProperty(
 +        name="Cull Back-faces",
 +        description="Do not test the back-face of each strand",
 +        default=True,
 +    )
 +    use_curves: BoolProperty(
 +        name="Use Cycles Hair Rendering",
 +        description="Activate Cycles hair rendering for particle system",
 +        default=True,
 +    )
 +    resolution: IntProperty(
 +        name="Resolution",
 +        description="Resolution of generated mesh",
 +        min=3, max=64,
 +        default=3,
 +    )
 +    minimum_width: FloatProperty(
 +        name="Minimal width",
 +        description="Minimal pixel width for strands (0 - deactivated)",
 +        min=0.0, max=100.0,
 +        default=0.0,
 +        subtype='PIXEL'
 +    )
 +    maximum_width: FloatProperty(
 +        name="Maximal width",
 +        description="Maximum extension that strand radius can be increased by",
 +        min=0.0, max=100.0,
 +        default=0.1,
 +        subtype='PIXEL'
 +    )
 +    subdivisions: IntProperty(
 +        name="Subdivisions",
 +        description="Number of subdivisions used in Cardinal curve intersection (power of 2)",
 +        min=0, max=24,
 +        default=4,
 +    )
 +
      @classmethod
      def register(cls):
          bpy.types.Scene.cycles_curves = PointerProperty(
              description="Cycles hair rendering settings",
              type=cls,
          )
 -        cls.primitive = EnumProperty(
 -            name="Primitive",
 -            description="Type of primitive used for hair rendering",
 -            items=enum_curve_primitives,
 -            default='LINE_SEGMENTS',
 -        )
 -        cls.shape = EnumProperty(
 -            name="Shape",
 -            description="Form of hair",
 -            items=enum_curve_shape,
 -            default='THICK',
 -        )
 -        cls.cull_backfacing = BoolProperty(
 -            name="Cull back-faces",
 -            description="Do not test the back-face of each strand",
 -            default=True,
 -        )
 -        cls.use_curves = BoolProperty(
 -            name="Use Cycles Hair Rendering",
 -            description="Activate Cycles hair rendering for particle system",
 -            default=True,
 -        )
 -        cls.resolution = IntProperty(
 -            name="Resolution",
 -            description="Resolution of generated mesh",
 -            min=3, max=64,
 -            default=3,
 -        )
 -        cls.minimum_width = FloatProperty(
 -            name="Minimal width",
 -            description="Minimal pixel width for strands (0 - deactivated)",
 -            min=0.0, max=100.0,
 -            default=0.0,
 -        )
 -        cls.maximum_width = FloatProperty(
 -            name="Maximal width",
 -            description="Maximum extension that strand radius can be increased by",
 -            min=0.0, max=100.0,
 -            default=0.1,
 -        )
 -        cls.subdivisions = IntProperty(
 -            name="Subdivisions",
 -            description="Number of subdivisions used in Cardinal curve intersection (power of 2)",
 -            min=0, max=24,
 -            default=4,
 -        )
  
      @classmethod
      def unregister(cls):
  
  
  def update_render_passes(self, context):
 -    scene = context.scene
 -    rd = scene.render
 -    rl = rd.layers.active
 -    rl.update_render_passes()
 +    view_layer = context.view_layer
 +    view_layer.update_render_passes()
  
  
  class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
 -    @classmethod
 -    def register(cls):
 -        bpy.types.SceneRenderLayer.cycles = PointerProperty(
 -            name="Cycles SceneRenderLayer Settings",
 -            description="Cycles SceneRenderLayer Settings",
 -            type=cls,
 -        )
 -        cls.pass_debug_bvh_traversed_nodes = BoolProperty(
 -            name="Debug BVH Traversed Nodes",
 -            description="Store Debug BVH Traversed Nodes pass",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.pass_debug_bvh_traversed_instances = BoolProperty(
 -            name="Debug BVH Traversed Instances",
 -            description="Store Debug BVH Traversed Instances pass",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.pass_debug_bvh_intersections = BoolProperty(
 -            name="Debug BVH Intersections",
 -            description="Store Debug BVH Intersections",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.pass_debug_ray_bounces = BoolProperty(
 -            name="Debug Ray Bounces",
 -            description="Store Debug Ray Bounces pass",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.pass_debug_render_time = BoolProperty(
 -            name="Debug Render Time",
 -            description="Render time in milliseconds per sample and pixel",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.use_pass_volume_direct = BoolProperty(
 -            name="Volume Direct",
 -            description="Deliver direct volumetric scattering pass",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.use_pass_volume_indirect = BoolProperty(
 -            name="Volume Indirect",
 -            description="Deliver indirect volumetric scattering pass",
 -            default=False,
 -            update=update_render_passes,
 -        )
  
 -        cls.use_denoising = BoolProperty(
 -            name="Use Denoising",
 -            description="Denoise the rendered image",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.denoising_diffuse_direct = BoolProperty(
 -            name="Diffuse Direct",
 -            description="Denoise the direct diffuse lighting",
 -            default=True,
 -        )
 -        cls.denoising_diffuse_indirect = BoolProperty(
 -            name="Diffuse Indirect",
 -            description="Denoise the indirect diffuse lighting",
 -            default=True,
 -        )
 -        cls.denoising_glossy_direct = BoolProperty(
 -            name="Glossy Direct",
 -            description="Denoise the direct glossy lighting",
 -            default=True,
 -        )
 -        cls.denoising_glossy_indirect = BoolProperty(
 -            name="Glossy Indirect",
 -            description="Denoise the indirect glossy lighting",
 -            default=True,
 -        )
 -        cls.denoising_transmission_direct = BoolProperty(
 -            name="Transmission Direct",
 -            description="Denoise the direct transmission lighting",
 -            default=True,
 -        )
 -        cls.denoising_transmission_indirect = BoolProperty(
 -            name="Transmission Indirect",
 -            description="Denoise the indirect transmission lighting",
 -            default=True,
 -        )
 -        cls.denoising_subsurface_direct = BoolProperty(
 -            name="Subsurface Direct",
 -            description="Denoise the direct subsurface lighting",
 -            default=True,
 -        )
 -        cls.denoising_subsurface_indirect = BoolProperty(
 -            name="Subsurface Indirect",
 -            description="Denoise the indirect subsurface lighting",
 -            default=True,
 -        )
 -        cls.denoising_strength = FloatProperty(
 -            name="Denoising Strength",
 -            description="Controls neighbor pixel weighting for the denoising filter (lower values preserve more detail, but aren't as smooth)",
 -            min=0.0, max=1.0,
 -            default=0.5,
 -        )
 -        cls.denoising_feature_strength = FloatProperty(
 -            name="Denoising Feature Strength",
 -            description="Controls removal of noisy image feature passes (lower values preserve more detail, but aren't as smooth)",
 -            min=0.0, max=1.0,
 -            default=0.5,
 -        )
 -        cls.denoising_radius = IntProperty(
 -            name="Denoising Radius",
 -            description="Size of the image area that's used to denoise a pixel (higher values are smoother, but might lose detail and are slower)",
 -            min=1, max=25,
 -            default=8,
 -        )
 -        cls.denoising_relative_pca = BoolProperty(
 -            name="Relative filter",
 -            description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)",
 -            default=False,
 -        )
 -        cls.denoising_store_passes = BoolProperty(
 -            name="Store denoising passes",
 -            description="Store the denoising feature passes and the noisy image",
 -            default=False,
 -            update=update_render_passes,
 -        )
 -        cls.use_pass_crypto_object = BoolProperty(
 -                name="Cryptomatte Object",
 -                description="Render cryptomatte object pass, for isolating objects in compositing",
 -                default=False,
 -                update=update_render_passes,
 -                )
 -        cls.use_pass_crypto_material = BoolProperty(
 -                name="Cryptomatte Material",
 -                description="Render cryptomatte material pass, for isolating materials in compositing",
 -                default=False,
 -                update=update_render_passes,
 -                )
 -        cls.use_pass_crypto_asset = BoolProperty(
 -                name="Cryptomatte Asset",
 -                description="Render cryptomatte asset pass, for isolating groups of objects with the same parent",
 -                default=False,
 -                update=update_render_passes,
 -                )
 -        cls.pass_crypto_depth = IntProperty(
 -                name="Cryptomatte Levels",
 -                description="Sets how many unique objects can be distinguished per pixel",
 -                default=6, min=2, max=16, step=2,
 -                update=update_render_passes,
 -                )
 -        cls.pass_crypto_accurate = BoolProperty(
 -                name="Cryptomatte Accurate",
 -                description="Gerenate a more accurate Cryptomatte pass. CPU only, may render slower and use more memory",
 -                default=True,
 -                update=update_render_passes,
 -                )
 -    @classmethod
 -    def unregister(cls):
 -        del bpy.types.SceneRenderLayer.cycles
 +    pass_debug_bvh_traversed_nodes: BoolProperty(
 +        name="Debug BVH Traversed Nodes",
 +        description="Store Debug BVH Traversed Nodes pass",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    pass_debug_bvh_traversed_instances: BoolProperty(
 +        name="Debug BVH Traversed Instances",
 +        description="Store Debug BVH Traversed Instances pass",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    pass_debug_bvh_intersections: BoolProperty(
 +        name="Debug BVH Intersections",
 +        description="Store Debug BVH Intersections",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    pass_debug_ray_bounces: BoolProperty(
 +        name="Debug Ray Bounces",
 +        description="Store Debug Ray Bounces pass",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    pass_debug_render_time: BoolProperty(
 +        name="Debug Render Time",
 +        description="Render time in milliseconds per sample and pixel",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    use_pass_volume_direct: BoolProperty(
 +        name="Volume Direct",
 +        description="Deliver direct volumetric scattering pass",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    use_pass_volume_indirect: BoolProperty(
 +        name="Volume Indirect",
 +        description="Deliver indirect volumetric scattering pass",
 +        default=False,
 +        update=update_render_passes,
 +    )
  
 +    use_denoising: BoolProperty(
 +        name="Use Denoising",
 +        description="Denoise the rendered image",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    denoising_diffuse_direct: BoolProperty(
 +        name="Diffuse Direct",
 +        description="Denoise the direct diffuse lighting",
 +        default=True,
 +    )
 +    denoising_diffuse_indirect: BoolProperty(
 +        name="Diffuse Indirect",
 +        description="Denoise the indirect diffuse lighting",
 +        default=True,
 +    )
 +    denoising_glossy_direct: BoolProperty(
 +        name="Glossy Direct",
 +        description="Denoise the direct glossy lighting",
 +        default=True,
 +    )
 +    denoising_glossy_indirect: BoolProperty(
 +        name="Glossy Indirect",
 +        description="Denoise the indirect glossy lighting",
 +        default=True,
 +    )
 +    denoising_transmission_direct: BoolProperty(
 +        name="Transmission Direct",
 +        description="Denoise the direct transmission lighting",
 +        default=True,
 +    )
 +    denoising_transmission_indirect: BoolProperty(
 +        name="Transmission Indirect",
 +        description="Denoise the indirect transmission lighting",
 +        default=True,
 +    )
 +    denoising_subsurface_direct: BoolProperty(
 +        name="Subsurface Direct",
 +        description="Denoise the direct subsurface lighting",
 +        default=True,
 +    )
 +    denoising_subsurface_indirect: BoolProperty(
 +        name="Subsurface Indirect",
 +        description="Denoise the indirect subsurface lighting",
 +        default=True,
 +    )
 +    denoising_strength: FloatProperty(
 +        name="Denoising Strength",
 +        description="Controls neighbor pixel weighting for the denoising filter (lower values preserve more detail, but aren't as smooth)",
 +        min=0.0, max=1.0,
 +        default=0.5,
 +    )
 +    denoising_feature_strength: FloatProperty(
 +        name="Denoising Feature Strength",
 +        description="Controls removal of noisy image feature passes (lower values preserve more detail, but aren't as smooth)",
 +        min=0.0, max=1.0,
 +        default=0.5,
 +    )
 +    denoising_radius: IntProperty(
 +        name="Denoising Radius",
 +        description="Size of the image area that's used to denoise a pixel (higher values are smoother, but might lose detail and are slower)",
 +        min=1, max=25,
 +        default=8,
 +    )
 +    denoising_relative_pca: BoolProperty(
 +        name="Relative filter",
 +        description="When removing pixels that don't carry information, use a relative threshold instead of an absolute one (can help to reduce artifacts, but might cause detail loss around edges)",
 +        default=False,
 +    )
 +    denoising_store_passes: BoolProperty(
 +        name="Store denoising passes",
 +        description="Store the denoising feature passes and the noisy image",
 +        default=False,
 +        update=update_render_passes,
 +    )
 +    use_pass_crypto_object: BoolProperty(
 +        name="Cryptomatte Object",
 +        description="Render cryptomatte object pass, for isolating objects in compositing",
 +        default=False,
 +        update=update_render_passes,
 +        )
 +    use_pass_crypto_material: BoolProperty(
 +        name="Cryptomatte Material",
 +        description="Render cryptomatte material pass, for isolating materials in compositing",
 +        default=False,
 +        update=update_render_passes,
 +        )
 +    use_pass_crypto_asset: BoolProperty(
 +        name="Cryptomatte Asset",
 +        description="Render cryptomatte asset pass, for isolating groups of objects with the same parent",
 +        default=False,
 +        update=update_render_passes,
 +        )
 +    pass_crypto_depth: IntProperty(
 +        name="Cryptomatte Levels",
 +        description="Sets how many unique objects can be distinguished per pixel",
 +        default=6, min=2, max=16, step=2,
 +        update=update_render_passes,
 +        )
 +    pass_crypto_accurate: BoolProperty(
 +        name="Cryptomatte Accurate",
 +        description="Generate a more accurate Cryptomatte pass. CPU only, may render slower and use more memory",
 +        default=True,
 +        update=update_render_passes,
 +        )
  
 -class CyclesCurveSettings(bpy.types.PropertyGroup):
      @classmethod
      def register(cls):
 -        bpy.types.ParticleSettings.cycles = PointerProperty(
 -            name="Cycles Hair Settings",
 -            description="Cycles hair settings",
 +        bpy.types.ViewLayer.cycles = PointerProperty(
 +            name="Cycles ViewLayer Settings",
 +            description="Cycles ViewLayer Settings",
              type=cls,
          )
 -        cls.radius_scale = FloatProperty(
 -            name="Radius Scaling",
 -            description="Multiplier of width properties",
 -            min=0.0, max=1000.0,
 -            default=0.01,
 -        )
 -        cls.root_width = FloatProperty(
 -            name="Root Size",
 -            description="Strand's width at root",
 -            min=0.0, max=1000.0,
 -            default=1.0,
 -        )
 -        cls.tip_width = FloatProperty(
 -            name="Tip Multiplier",
 -            description="Strand's width at tip",
 -            min=0.0, max=1000.0,
 -            default=0.0,
 -        )
 -        cls.shape = FloatProperty(
 -            name="Strand Shape",
 -            description="Strand shape parameter",
 -            min=-1.0, max=1.0,
 -            default=0.0,
 -        )
 -        cls.use_closetip = BoolProperty(
 -            name="Close tip",
 -            description="Set tip radius to zero",
 -            default=True,
 -        )
  
      @classmethod
      def unregister(cls):
 -        del bpy.types.ParticleSettings.cycles
 +        del bpy.types.ViewLayer.cycles
  
  
  class CyclesDeviceSettings(bpy.types.PropertyGroup):
 -    @classmethod
 -    def register(cls):
 -        cls.id = StringProperty(name="ID")
 -        cls.name = StringProperty(name="Name")
 -        cls.use = BoolProperty(name="Use", default=True)
 -        cls.type = EnumProperty(name="Type", items=enum_device_type, default='CUDA')
 +    id: StringProperty(name="ID")
 +    name: StringProperty(name="Name")
 +    use: BoolProperty(name="Use", default=True)
 +    type: EnumProperty(name="Type", items=enum_device_type, default='CUDA')
  
  
  class CyclesPreferences(bpy.types.AddonPreferences):
              list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2))
          return list
  
 -    compute_device_type = EnumProperty(
 +    compute_device_type: EnumProperty(
          name="Compute Device Type",
          description="Device to use for computation (rendering with Cycles)",
          items=get_device_types,
      )
  
 -    devices = bpy.props.CollectionProperty(type=CyclesDeviceSettings)
 +    devices: bpy.props.CollectionProperty(type=CyclesDeviceSettings)
  
      def find_existing_device_entry(self, device):
          for device_entry in self.devices:
      def get_devices(self):
          import _cycles
          # Layout of the device tuples: (Name, Type, Persistent ID)
-         device_list = _cycles.available_devices()
+         device_list = _cycles.available_devices(self.compute_device_type)
          # Make sure device entries are up to date and not referenced before
          # we know we don't add new devices. This way we guarantee to not
          # hold pointers to a resized array.
  
      def get_num_gpu_devices(self):
          import _cycles
-         device_list = _cycles.available_devices()
+         device_list = _cycles.available_devices(self.compute_device_type)
          num = 0
          for device in device_list:
              if device[1] != self.compute_device_type:
      def has_active_device(self):
          return self.get_num_gpu_devices() > 0
  
-     def draw_impl(self, layout, context):
-         available_device_types = self.get_device_types(context)
-         if len(available_device_types) == 1:
-             layout.label(text="No compatible GPUs found", icon='INFO')
+     def _draw_devices(self, layout, device_type, devices):
+         box = layout.box()
+         found_device = False
+         for device in devices:
+             if device.type == device_type:
+                 found_device = True
+                 break
+         if not found_device:
+             box.label(text="No compatible GPUs found", icon='INFO')
              return
-         layout.row().prop(self, "compute_device_type", expand=True)
  
-         cuda_devices, opencl_devices = self.get_devices()
-         row = layout.row()
+         for device in devices:
+             box.prop(device, "use", text=device.name)
  
-         if self.compute_device_type == 'CUDA' and cuda_devices:
-             box = row.box()
-             for device in cuda_devices:
-                 box.prop(device, "use", text=device.name)
+     def draw_impl(self, layout, context):
+         row = layout.row()
+         row.prop(self, "compute_device_type", expand=True)
  
-         if self.compute_device_type == 'OPENCL' and opencl_devices:
-             box = row.box()
-             for device in opencl_devices:
-                 box.prop(device, "use", text=device.name)
+         cuda_devices, opencl_devices = self.get_devices()
+         row = layout.row()
+         if self.compute_device_type == 'CUDA':
+             self._draw_devices(row, 'CUDA', cuda_devices)
+         elif self.compute_device_type == 'OPENCL':
+             self._draw_devices(row, 'OPENCL', opencl_devices)
  
      def draw(self, context):
          self.draw_impl(self.layout, context)
@@@ -1518,12 -1550,13 +1525,12 @@@ def register()
      bpy.utils.register_class(CyclesRenderSettings)
      bpy.utils.register_class(CyclesCameraSettings)
      bpy.utils.register_class(CyclesMaterialSettings)
 -    bpy.utils.register_class(CyclesLampSettings)
 +    bpy.utils.register_class(CyclesLightSettings)
      bpy.utils.register_class(CyclesWorldSettings)
      bpy.utils.register_class(CyclesVisibilitySettings)
      bpy.utils.register_class(CyclesMeshSettings)
      bpy.utils.register_class(CyclesObjectSettings)
      bpy.utils.register_class(CyclesCurveRenderSettings)
 -    bpy.utils.register_class(CyclesCurveSettings)
      bpy.utils.register_class(CyclesDeviceSettings)
      bpy.utils.register_class(CyclesPreferences)
      bpy.utils.register_class(CyclesRenderLayerSettings)
@@@ -1533,12 -1566,13 +1540,12 @@@ def unregister()
      bpy.utils.unregister_class(CyclesRenderSettings)
      bpy.utils.unregister_class(CyclesCameraSettings)
      bpy.utils.unregister_class(CyclesMaterialSettings)
 -    bpy.utils.unregister_class(CyclesLampSettings)
 +    bpy.utils.unregister_class(CyclesLightSettings)
      bpy.utils.unregister_class(CyclesWorldSettings)
      bpy.utils.unregister_class(CyclesMeshSettings)
      bpy.utils.unregister_class(CyclesObjectSettings)
      bpy.utils.unregister_class(CyclesVisibilitySettings)
      bpy.utils.unregister_class(CyclesCurveRenderSettings)
 -    bpy.utils.unregister_class(CyclesCurveSettings)
      bpy.utils.unregister_class(CyclesDeviceSettings)
      bpy.utils.unregister_class(CyclesPreferences)
      bpy.utils.unregister_class(CyclesRenderLayerSettings)
@@@ -203,10 -203,10 +203,10 @@@ static PyObject *exit_func(PyObject * /
  
  static PyObject *create_func(PyObject * /*self*/, PyObject *args)
  {
 -      PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
 +      PyObject *pyengine, *pyuserpref, *pydata, *pyregion, *pyv3d, *pyrv3d;
        int preview_osl;
  
 -      if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene,
 +      if(!PyArg_ParseTuple(args, "OOOOOOi", &pyengine, &pyuserpref, &pydata,
                             &pyregion, &pyv3d, &pyrv3d, &preview_osl))
        {
                return NULL;
        BL::RenderEngine engine(engineptr);
  
        PointerRNA userprefptr;
 -      RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
 -      BL::UserPreferences userpref(userprefptr);
 +      RNA_pointer_create(NULL, &RNA_Preferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
 +      BL::Preferences userpref(userprefptr);
  
        PointerRNA dataptr;
        RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
        BL::BlendData data(dataptr);
  
 -      PointerRNA sceneptr;
 -      RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
 -      BL::Scene scene(sceneptr);
 -
        PointerRNA regionptr;
        RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
        BL::Region region(regionptr);
                int width = region.width();
                int height = region.height();
  
 -              session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
 +              session = new BlenderSession(engine, userpref, data, v3d, rv3d, width, height);
        }
        else {
 -              /* override some settings for preview */
 -              if(engine.is_preview()) {
 -                      PointerRNA cscene = RNA_pointer_get(&sceneptr, "cycles");
 -
 -                      RNA_boolean_set(&cscene, "shading_system", preview_osl);
 -                      RNA_boolean_set(&cscene, "use_progressive_refine", true);
 -              }
 -
                /* offline session or preview render */
 -              session = new BlenderSession(engine, userpref, data, scene);
 +              session = new BlenderSession(engine, userpref, data, preview_osl);
        }
  
 -      python_thread_state_save(&session->python_thread_state);
 -
 -      session->create();
 -
 -      python_thread_state_restore(&session->python_thread_state);
 -
        return PyLong_FromVoidPtr(session);
  }
  
@@@ -262,22 -280,13 +262,22 @@@ static PyObject *free_func(PyObject * /
        Py_RETURN_NONE;
  }
  
 -static PyObject *render_func(PyObject * /*self*/, PyObject *value)
 +static PyObject *render_func(PyObject * /*self*/, PyObject *args)
  {
 -      BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
 +      PyObject *pysession, *pydepsgraph;
 +
 +      if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
 +              return NULL;
 +
 +      BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
 +
 +      PointerRNA depsgraphptr;
 +      RNA_pointer_create(NULL, &RNA_Depsgraph, (ID*)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
 +      BL::Depsgraph b_depsgraph(depsgraphptr);
  
        python_thread_state_save(&session->python_thread_state);
  
 -      session->render();
 +      session->render(b_depsgraph);
  
        python_thread_state_restore(&session->python_thread_state);
  
  /* pixel_array and result passed as pointers */
  static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
  {
 -      PyObject *pysession, *pyobject;
 +      PyObject *pysession, *pydepsgraph, *pyobject;
        PyObject *pypixel_array, *pyresult;
        const char *pass_type;
        int num_pixels, depth, object_id, pass_filter;
  
 -      if(!PyArg_ParseTuple(args, "OOsiiOiiO", &pysession, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
 +      if(!PyArg_ParseTuple(args, "OOOsiiOiiO", &pysession, &pydepsgraph, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
                return NULL;
  
        BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
  
 +      PointerRNA depsgraphptr;
 +      RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
 +      BL::Depsgraph b_depsgraph(depsgraphptr);
 +
        PointerRNA objectptr;
        RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr);
        BL::Object b_object(objectptr);
  
        python_thread_state_save(&session->python_thread_state);
  
 -      session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
 +      session->bake(b_depsgraph, b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
  
        python_thread_state_restore(&session->python_thread_state);
  
  
  static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
  {
 -      PyObject *pysession, *pyv3d, *pyrv3d;
 +      PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
  
 -      if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
 +      if(!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d))
                return NULL;
  
        BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
  
  static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
  {
 -      PyObject *pysession, *pydata, *pyscene;
 +      PyObject *pysession, *pydata, *pydepsgraph;
  
 -      if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pyscene))
 +      if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph))
                return NULL;
  
        BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
        RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
        BL::BlendData b_data(dataptr);
  
 -      PointerRNA sceneptr;
 -      RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
 -      BL::Scene b_scene(sceneptr);
 +      PointerRNA depsgraphptr;
 +      RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
 +      BL::Depsgraph b_depsgraph(depsgraphptr);
  
        python_thread_state_save(&session->python_thread_state);
  
 -      session->reset_session(b_data, b_scene);
 +      session->reset_session(b_data, b_depsgraph);
  
        python_thread_state_restore(&session->python_thread_state);
  
        Py_RETURN_NONE;
  }
  
 -static PyObject *sync_func(PyObject * /*self*/, PyObject *value)
 +static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
  {
 -      BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
 +      PyObject *pysession, *pydepsgraph;
 +
 +      if(!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
 +              return NULL;
 +
 +      BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
 +
 +      PointerRNA depsgraphptr;
 +      RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
 +      BL::Depsgraph b_depsgraph(depsgraphptr);
  
        python_thread_state_save(&session->python_thread_state);
  
 -      session->synchronize();
 +      session->synchronize(b_depsgraph);
  
        python_thread_state_restore(&session->python_thread_state);
  
        Py_RETURN_NONE;
  }
  
- static PyObject *available_devices_func(PyObject * /*self*/, PyObject * /*args*/)
+ static PyObject *available_devices_func(PyObject * /*self*/, PyObject * args)
  {
-       vector<DeviceInfo>& devices = Device::available_devices();
+       const char *type_name;
+       if(!PyArg_ParseTuple(args, "s", &type_name)) {
+               return NULL;
+       }
+       DeviceType type = Device::type_from_string(type_name);
+       uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type);
+       mask |= DEVICE_MASK_CPU;
+       vector<DeviceInfo> devices = Device::available_devices(mask);
        PyObject *ret = PyTuple_New(devices.size());
  
        for(size_t i = 0; i < devices.size(); i++) {
@@@ -746,11 -751,11 +755,11 @@@ static PyObject *enable_print_stats_fun
  
  static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
  {
-       vector<DeviceInfo>& devices = Device::available_devices();
+       vector<DeviceType> device_types = Device::available_types();
        bool has_cuda = false, has_opencl = false;
-       for(int i = 0; i < devices.size(); i++) {
-               has_cuda   |= (devices[i].type == DEVICE_CUDA);
-               has_opencl |= (devices[i].type == DEVICE_OPENCL);
+       foreach(DeviceType device_type, device_types) {
+               has_cuda   |= (device_type == DEVICE_CUDA);
+               has_opencl |= (device_type == DEVICE_OPENCL);
        }
        PyObject *list = PyTuple_New(2);
        PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
@@@ -763,16 -768,16 +772,16 @@@ static PyMethodDef methods[] = 
        {"exit", exit_func, METH_VARARGS, ""},
        {"create", create_func, METH_VARARGS, ""},
        {"free", free_func, METH_O, ""},
 -      {"render", render_func, METH_O, ""},
 +      {"render", render_func, METH_VARARGS, ""},
        {"bake", bake_func, METH_VARARGS, ""},
        {"draw", draw_func, METH_VARARGS, ""},
 -      {"sync", sync_func, METH_O, ""},
 +      {"sync", sync_func, METH_VARARGS, ""},
        {"reset", reset_func, METH_VARARGS, ""},
  #ifdef WITH_OSL
        {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
        {"osl_compile", osl_compile_func, METH_VARARGS, ""},
  #endif
-       {"available_devices", available_devices_func, METH_NOARGS, ""},
+       {"available_devices", available_devices_func, METH_VARARGS, ""},
        {"system_info", system_info_func, METH_NOARGS, ""},
  #ifdef WITH_OPENCL
        {"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
@@@ -801,7 -806,7 +810,7 @@@ static struct PyModuleDef module = 
        "Blender cycles render integration",
        -1,
        methods,
 -      NULL, NULL, NULL, NULL
 +      NULL, NULL, NULL, NULL,
  };
  
  CCL_NAMESPACE_END
@@@ -78,12 -78,31 +78,12 @@@ BlenderSync::~BlenderSync(
  
  /* Sync */
  
 -bool BlenderSync::sync_recalc()
 +void BlenderSync::sync_recalc(BL::Depsgraph& b_depsgraph)
  {
 -      /* sync recalc flags from blender to cycles. actual update is done separate,
 -       * so we can do it later on if doing it immediate is not suitable */
 -
 -      BL::BlendData::materials_iterator b_mat;
 -      bool has_updated_objects = b_data.objects.is_updated();
 -      for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
 -              if(b_mat->is_updated() || (b_mat->node_tree() && b_mat->node_tree().is_updated())) {
 -                      shader_map.set_recalc(*b_mat);
 -              }
 -              else {
 -                      Shader *shader = shader_map.find(*b_mat);
 -                      if(has_updated_objects && shader != NULL && shader->has_object_dependency) {
 -                              shader_map.set_recalc(*b_mat);
 -                      }
 -              }
 -      }
 -
 -      BL::BlendData::lamps_iterator b_lamp;
 -
 -      for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
 -              if(b_lamp->is_updated() || (b_lamp->node_tree() && b_lamp->node_tree().is_updated()))
 -                      shader_map.set_recalc(*b_lamp);
 +      /* Sync recalc flags from blender to cycles. Actual update is done separate,
 +       * so we can do it later on if doing it immediate is not suitable. */
  
 +      bool has_updated_objects = b_depsgraph.id_type_updated(BL::DriverTarget::id_type_OBJECT);
        bool dicing_prop_changed = false;
  
        if(experimental) {
                }
        }
  
 -      BL::BlendData::objects_iterator b_ob;
 +      /* Iterate over all IDs in this depsgraph. */
 +      BL::Depsgraph::updates_iterator b_update;
 +      for(b_depsgraph.updates.begin(b_update); b_update != b_depsgraph.updates.end(); ++b_update) {
 +              BL::ID b_id(b_update->id());
  
 -      for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
 -              if(b_ob->is_updated()) {
 -                      object_map.set_recalc(*b_ob);
 -                      light_map.set_recalc(*b_ob);
 +              /* Material */
 +              if(b_id.is_a(&RNA_Material)) {
 +                      BL::Material b_mat(b_id);
 +                      shader_map.set_recalc(b_mat);
 +              }
 +              /* Light */
 +              else if(b_id.is_a(&RNA_Light)) {
 +                      BL::Light b_light(b_id);
 +                      shader_map.set_recalc(b_light);
                }
 +              /* Object */
 +              else if(b_id.is_a(&RNA_Object)) {
 +                      BL::Object b_ob(b_id);
 +                      const bool updated_geometry = b_update->is_updated_geometry();
 +
 +                      if(b_update->is_updated_transform()) {
 +                              object_map.set_recalc(b_ob);
 +                              light_map.set_recalc(b_ob);
 +                      }
  
 -              if(object_is_mesh(*b_ob)) {
 -                      if(b_ob->is_updated_data() || b_ob->data().is_updated() ||
 -                         (dicing_prop_changed && object_subdivision_type(*b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE))
 -                      {
 -                              BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data();
 -                              mesh_map.set_recalc(key);
 +                      if(object_is_mesh(b_ob)) {
 +                              if(updated_geometry ||
 +                                 (dicing_prop_changed && object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE))
 +                              {
 +                                      BL::ID key = BKE_object_is_modified(b_ob)? b_ob: b_ob.data();
 +                                      mesh_map.set_recalc(key);
 +                              }
 +                      }
 +                      else if(object_is_light(b_ob)) {
 +                              if(updated_geometry) {
 +                                      light_map.set_recalc(b_ob);
 +                              }
 +                      }
 +
 +                      if(updated_geometry) {
 +                              BL::Object::particle_systems_iterator b_psys;
 +                              for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys)
 +                                      particle_system_map.set_recalc(b_ob);
                        }
                }
 -              else if(object_is_light(*b_ob)) {
 -                      if(b_ob->is_updated_data() || b_ob->data().is_updated())
 -                              light_map.set_recalc(*b_ob);
 +              /* Mesh */
 +              else if(b_id.is_a(&RNA_Mesh)) {
 +                      BL::Mesh b_mesh(b_id);
 +                      mesh_map.set_recalc(b_mesh);
                }
 -
 -              if(b_ob->is_updated_data()) {
 -                      BL::Object::particle_systems_iterator b_psys;
 -                      for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
 -                              particle_system_map.set_recalc(*b_ob);
 +              /* World */
 +              else if(b_id.is_a(&RNA_World)) {
 +                      BL::World b_world(b_id);
 +                      if(world_map == b_world.ptr.data) {
 +                              world_recalc = true;
 +                      }
                }
        }
  
 -      BL::BlendData::meshes_iterator b_mesh;
 -
 -      for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh) {
 -              if(b_mesh->is_updated()) {
 -                      mesh_map.set_recalc(*b_mesh);
 +      /* Updates shader with object dependency if objects changed. */
 +      if(has_updated_objects) {
 +              if(scene->default_background->has_object_dependency) {
 +                      world_recalc = true;
                }
 -      }
  
 -      BL::BlendData::worlds_iterator b_world;
 -
 -      for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world) {
 -              if(world_map == b_world->ptr.data) {
 -                      if(b_world->is_updated() ||
 -                         (b_world->node_tree() && b_world->node_tree().is_updated()))
 -                      {
 -                              world_recalc = true;
 -                      }
 -                      else if(b_world->node_tree() && b_world->use_nodes()) {
 -                              Shader *shader = scene->default_background;
 -                              if(has_updated_objects && shader->has_object_dependency) {
 -                                      world_recalc = true;
 -                              }
 +              foreach(Shader *shader, scene->shaders) {
 +                      if(shader->has_object_dependency) {
 +                              shader->need_sync_object = true;
                        }
                }
        }
 -
 -      bool recalc =
 -              shader_map.has_recalc() ||
 -              object_map.has_recalc() ||
 -              light_map.has_recalc() ||
 -              mesh_map.has_recalc() ||
 -              particle_system_map.has_recalc() ||
 -              BlendDataObjects_is_updated_get(&b_data.ptr) ||
 -              world_recalc;
 -
 -      return recalc;
  }
  
  void BlenderSync::sync_data(BL::RenderSettings& b_render,
 +                            BL::Depsgraph& b_depsgraph,
                              BL::SpaceView3D& b_v3d,
                              BL::Object& b_override,
                              int width, int height,
 -                            void **python_thread_state,
 -                            const char *layer)
 +                            void **python_thread_state)
  {
 -      sync_render_layers(b_v3d, layer);
 +      BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
 +
 +      sync_view_layer(b_v3d, b_view_layer);
        sync_integrator();
        sync_film();
 -      sync_shaders();
 +      sync_shaders(b_depsgraph);
        sync_images();
        sync_curve_settings();
  
           scene->need_motion() == Scene::MOTION_NONE ||
           scene->camera->motion_position == Camera::MOTION_POSITION_CENTER)
        {
 -              sync_objects();
 +              sync_objects(b_depsgraph);
        }
        sync_motion(b_render,
 +                  b_depsgraph,
                    b_override,
                    width, height,
                    python_thread_state);
  
        mesh_synced.clear();
 +
 +      free_data_after_sync(b_depsgraph);
  }
  
  /* Integrator */
@@@ -364,33 -371,75 +364,33 @@@ void BlenderSync::sync_film(
  
  /* Render Layer */
  
 -void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer)
 +void BlenderSync::sync_view_layer(BL::SpaceView3D& /*b_v3d*/, BL::ViewLayer& b_view_layer)
  {
 -      PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
 -      string layername;
 -
 -      /* 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;
 -              }
 -      }
 -
        /* render layer */
 -      BL::RenderSettings r = b_scene.render();
 -      BL::RenderSettings::layers_iterator b_rlay;
 +      view_layer.name = b_view_layer.name();
 +      view_layer.use_background_shader = b_view_layer.use_sky();
 +      view_layer.use_background_ao = b_view_layer.use_ao();
 +      view_layer.use_surfaces = b_view_layer.use_solid();
 +      view_layer.use_hair = b_view_layer.use_strand();
 +
 +      /* Material override. */
 +      view_layer.material_override = b_view_layer.material_override();
 +
 +      /* Sample override. */
 +      PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
        int use_layer_samples = get_enum(cscene, "use_layer_samples");
 -      bool first_layer = true;
 -      uint layer_override = get_layer(b_engine.layer_override());
 -      uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers());
 -
 -      for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
 -              if((!layer && first_layer) || (layer && b_rlay->name() == layer)) {
 -                      render_layer.name = b_rlay->name();
 -
 -                      render_layer.holdout_layer = get_layer(b_rlay->layers_zmask());
 -                      render_layer.exclude_layer = get_layer(b_rlay->layers_exclude());
 -
 -                      render_layer.scene_layer = scene_layers & ~render_layer.exclude_layer;
 -                      render_layer.scene_layer |= render_layer.exclude_layer & render_layer.holdout_layer;
 -
 -                      render_layer.layer = get_layer(b_rlay->layers());
 -                      render_layer.layer |= render_layer.holdout_layer;
 -
 -                      render_layer.material_override = b_rlay->material_override();
 -                      render_layer.use_background_shader = b_rlay->use_sky();
 -                      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) {
 -                              int samples = b_rlay->samples();
 -                              if(get_boolean(cscene, "use_square_samples"))
 -                                      render_layer.samples = samples * samples;
 -                              else
 -                                      render_layer.samples = samples;
 -                      }
 -              }
  
 -              first_layer = false;
 +      view_layer.bound_samples = (use_layer_samples == 1);
 +      view_layer.samples = 0;
 +
 +      if(use_layer_samples != 2) {
 +              int samples = b_view_layer.samples();
 +              if(get_boolean(cscene, "use_square_samples"))
 +                      view_layer.samples = samples * samples;
 +              else
 +                      view_layer.samples = samples;
        }
 +
  }
  
  /* Images */
@@@ -506,7 -555,7 +506,7 @@@ int BlenderSync::get_denoising_pass(BL:
  }
  
  vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay,
 -                                             BL::SceneRenderLayer& b_srlay,
 +                                             BL::ViewLayer& b_view_layer,
                                               const SessionParams &session_params)
  {
        vector<Pass> passes;
                        Pass::add(pass_type, passes);
        }
  
 -      PointerRNA crp = RNA_pointer_get(&b_srlay.ptr, "cycles");
 +      PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
        bool use_denoising = get_boolean(crp, "use_denoising");
        bool store_denoising_passes = get_boolean(crp, "denoising_store_passes");
        scene->film->denoising_flags = 0;
                MAP_OPTION("denoising_subsurface_direct",     DENOISING_CLEAN_SUBSURFACE_DIR);
                MAP_OPTION("denoising_subsurface_indirect",   DENOISING_CLEAN_SUBSURFACE_IND);
  #undef MAP_OPTION
 -              b_engine.add_pass("Noisy Image", 4, "RGBA", b_srlay.name().c_str());
 +              b_engine.add_pass("Noisy Image", 4, "RGBA", b_view_layer.name().c_str());
        }
  
        if(store_denoising_passes) {
 -              b_engine.add_pass("Denoising Normal",          3, "XYZ", b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Normal Variance", 3, "XYZ", b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Albedo",          3, "RGB", b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Albedo Variance", 3, "RGB", b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Depth",           1, "Z",   b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Depth Variance",  1, "Z",   b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Shadow A",        3, "XYV", b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Shadow B",        3, "XYV", b_srlay.name().c_str());
 -              b_engine.add_pass("Denoising Image Variance",  3, "RGB", b_srlay.name().c_str());
 +              b_engine.add_pass("Denoising Normal",          3, "XYZ", b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Normal Variance", 3, "XYZ", b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Albedo",          3, "RGB", b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Albedo Variance", 3, "RGB", b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Depth",           1, "Z",   b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Depth Variance",  1, "Z",   b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Shadow A",        3, "XYV", b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Shadow B",        3, "XYV", b_view_layer.name().c_str());
 +              b_engine.add_pass("Denoising Image Variance",  3, "RGB", b_view_layer.name().c_str());
  
                if(scene->film->denoising_flags & DENOISING_CLEAN_ALL_PASSES) {
 -                      b_engine.add_pass("Denoising Clean",   3, "RGB", b_srlay.name().c_str());
 +                      b_engine.add_pass("Denoising Clean",   3, "RGB", b_view_layer.name().c_str());
                }
        }
  #ifdef __KERNEL_DEBUG__
        if(get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
 -              b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_srlay.name().c_str());
 +              b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
                Pass::add(PASS_BVH_TRAVERSED_NODES, passes);
        }
        if(get_boolean(crp, "pass_debug_bvh_traversed_instances")) {
 -              b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_srlay.name().c_str());
 +              b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str());
                Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes);
        }
        if(get_boolean(crp, "pass_debug_bvh_intersections")) {
 -              b_engine.add_pass("Debug BVH Intersections", 1, "X", b_srlay.name().c_str());
 +              b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str());
                Pass::add(PASS_BVH_INTERSECTIONS, passes);
        }
        if(get_boolean(crp, "pass_debug_ray_bounces")) {
 -              b_engine.add_pass("Debug Ray Bounces", 1, "X", b_srlay.name().c_str());
 +              b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str());
                Pass::add(PASS_RAY_BOUNCES, passes);
        }
  #endif
        if(get_boolean(crp, "pass_debug_render_time")) {
 -              b_engine.add_pass("Debug Render Time", 1, "X", b_srlay.name().c_str());
 +              b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
                Pass::add(PASS_RENDER_TIME, passes);
        }
        if(get_boolean(crp, "use_pass_volume_direct")) {
 -              b_engine.add_pass("VolumeDir", 3, "RGB", b_srlay.name().c_str());
 +              b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
                Pass::add(PASS_VOLUME_DIRECT, passes);
        }
        if(get_boolean(crp, "use_pass_volume_indirect")) {
 -              b_engine.add_pass("VolumeInd", 3, "RGB", b_srlay.name().c_str());
 +              b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
                Pass::add(PASS_VOLUME_INDIRECT, passes);
        }
  
        if(get_boolean(crp, "use_pass_crypto_object")) {
                for(int i = 0; i < crypto_depth; ++i) {
                        string passname = cryptomatte_prefix + string_printf("Object%02d", i);
 -                      b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str());
 +                      b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
                        Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
                }
                scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_OBJECT);
        if(get_boolean(crp, "use_pass_crypto_material")) {
                for(int i = 0; i < crypto_depth; ++i) {
                        string passname = cryptomatte_prefix + string_printf("Material%02d", i);
 -                      b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str());
 +                      b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
                        Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
                }
                scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_MATERIAL);
        if(get_boolean(crp, "use_pass_crypto_asset")) {
                for(int i = 0; i < crypto_depth; ++i) {
                        string passname = cryptomatte_prefix + string_printf("Asset%02d", i);
 -                      b_engine.add_pass(passname.c_str(), 4, "RGBA", b_srlay.name().c_str());
 +                      b_engine.add_pass(passname.c_str(), 4, "RGBA", b_view_layer.name().c_str());
                        Pass::add(PASS_CRYPTOMATTE, passes, passname.c_str());
                }
                scene->film->cryptomatte_passes = (CryptomatteType)(scene->film->cryptomatte_passes | CRYPT_ASSET);
        return passes;
  }
  
 +void BlenderSync::free_data_after_sync(BL::Depsgraph& b_depsgraph)
 +{
 +      /* When viewport display is not needed during render we can force some
 +       * caches to be releases from blender side in order to reduce peak memory
 +       * footprint during synchronization process.
 +       */
 +      const bool is_interface_locked = b_engine.render() &&
 +                                       b_engine.render().use_lock_interface();
 +      const bool can_free_caches = BlenderSession::headless || is_interface_locked;
 +      if(!can_free_caches) {
 +              return;
 +      }
 +      /* TODO(sergey): We can actually remove the whole dependency graph,
 +       * but that will need some API support first.
 +       */
 +      BL::Depsgraph::objects_iterator b_ob;
 +      for(b_depsgraph.objects.begin(b_ob);
 +          b_ob != b_depsgraph.objects.end();
 +          ++b_ob)
 +      {
 +              b_ob->cache_release();
 +      }
 +}
 +
  /* Scene Parameters */
  
  SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene,
@@@ -721,7 -746,7 +721,7 @@@ bool BlenderSync::get_session_pause(BL:
  }
  
  SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
 -                                              BL::UserPreferences& b_userpref,
 +                                              BL::Preferences& b_userpref,
                                                BL::Scene& b_scene,
                                                bool background)
  {
        /* Background */
        params.background = background;
  
-       /* device type */
-       vector<DeviceInfo>& devices = Device::available_devices();
-       /* device default CPU */
-       foreach(DeviceInfo& device, devices) {
-               if(device.type == DEVICE_CPU) {
-                       params.device = device;
-                       break;
-               }
-       }
+       /* Default to CPU device. */
+       params.device = Device::available_devices(DEVICE_MASK_CPU).front();
  
        if(get_enum(cscene, "device") == 2) {
-               /* find network device */
-               foreach(DeviceInfo& info, devices)
-                       if(info.type == DEVICE_NETWORK)
-                               params.device = info;
+               /* Find network device. */
+               vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK);
+               if(!devices.empty()) {
+                       params.device = devices.front();
+               }
        }
        else if(get_enum(cscene, "device") == 1) {
+               /* Find cycles preferences. */
                PointerRNA b_preferences;
  
 -              BL::UserPreferences::addons_iterator b_addon_iter;
 +              BL::Preferences::addons_iterator b_addon_iter;
                for(b_userpref.addons.begin(b_addon_iter); b_addon_iter != b_userpref.addons.end(); ++b_addon_iter) {
                        if(b_addon_iter->module() == "cycles") {
                                b_preferences = b_addon_iter->preferences().ptr;
                        }
                }
  
+               /* Test if we are using GPU devices. */
                enum ComputeDevice {
                        COMPUTE_DEVICE_CPU = 0,
                        COMPUTE_DEVICE_CUDA = 1,
                                                                       COMPUTE_DEVICE_CPU);
  
                if(compute_device != COMPUTE_DEVICE_CPU) {
+                       /* Query GPU devices with matching types. */
+                       uint mask = DEVICE_MASK_CPU;
+                       if(compute_device == COMPUTE_DEVICE_CUDA) {
+                               mask |= DEVICE_MASK_CUDA;
+                       }
+                       else if(compute_device == COMPUTE_DEVICE_OPENCL) {
+                               mask |= DEVICE_MASK_OPENCL;
+                       }
+                       vector<DeviceInfo> devices = Device::available_devices(mask);
+                       /* Match device preferences and available devices. */
                        vector<DeviceInfo> used_devices;
                        RNA_BEGIN(&b_preferences, device, "devices") {
-                               ComputeDevice device_type = (ComputeDevice)get_enum(device,
-                                                                                   "type",
-                                                                                   COMPUTE_DEVICE_NUM,
-                                                                                   COMPUTE_DEVICE_CPU);
-                               if(get_boolean(device, "use") &&
-                                  (device_type == compute_device || device_type == COMPUTE_DEVICE_CPU)) {
+                               if(get_boolean(device, "use")) {
                                        string id = get_string(device, "id");
                                        foreach(DeviceInfo& info, devices) {
                                                if(info.id == id) {
                                }
                        } RNA_END;
  
-                       if(used_devices.size() == 1) {
-                               params.device = used_devices[0];
-                       }
-                       else if(used_devices.size() > 1) {
+                       if(!used_devices.empty()) {
                                params.device = Device::get_multi_device(used_devices,
                                                                         params.threads,
                                                                         params.background);
        params.text_timeout = (double)get_float(cscene, "debug_text_timeout");
  
        /* progressive refine */
 -      params.progressive_refine = get_boolean(cscene, "use_progressive_refine") &&
 +      params.progressive_refine = (b_engine.is_preview() ||
 +                                   get_boolean(cscene, "use_progressive_refine")) &&
                                    !b_r.use_save_buffers();
  
        if(params.progressive_refine) {
 -              BL::RenderSettings::layers_iterator b_rlay;
 -              for(b_r.layers.begin(b_rlay); b_rlay != b_r.layers.end(); ++b_rlay) {
 -                      PointerRNA crl = RNA_pointer_get(&b_rlay->ptr, "cycles");
 +              BL::Scene::view_layers_iterator b_view_layer;
 +              for(b_scene.view_layers.begin(b_view_layer); b_view_layer != b_scene.view_layers.end(); ++b_view_layer) {
 +                      PointerRNA crl = RNA_pointer_get(&b_view_layer->ptr, "cycles");
                        if(get_boolean(crl, "use_denoising")) {
                                params.progressive_refine = false;
                        }
                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 = b_engine.support_display_space_shader(b_scene);
  
        if(b_engine.is_preview()) {
                /* For preview rendering we're using same timeout as
@@@ -36,8 -36,11 +36,11 @@@ CCL_NAMESPACE_BEGI
  bool Device::need_types_update = true;
  bool Device::need_devices_update = true;
  thread_mutex Device::device_mutex;
- vector<DeviceType> Device::types;
- vector<DeviceInfo> Device::devices;
+ vector<DeviceInfo> Device::opencl_devices;
+ vector<DeviceInfo> Device::cuda_devices;
+ vector<DeviceInfo> Device::cpu_devices;
+ vector<DeviceInfo> Device::network_devices;
+ uint Device::devices_initialized_mask = 0;
  
  /* Device Requested Features */
  
@@@ -78,276 -81,132 +81,276 @@@ std::ostream& operator <<(std::ostream 
  
  Device::~Device()
  {
 -      if(!background && vertex_buffer != 0) {
 -              glDeleteBuffers(1, &vertex_buffer);
 +      if(!background) {
 +              if(vertex_buffer != 0) {
 +                      glDeleteBuffers(1, &vertex_buffer);
 +              }
 +              if(fallback_shader_program != 0) {
 +                      glDeleteProgram(fallback_shader_program);
 +              }
        }
  }
  
 -void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
 -      const DeviceDrawParams &draw_params)
 +/* TODO move shaders to standalone .glsl file. */
 +const char *FALLBACK_VERTEX_SHADER =
 +"#version 330\n"
 +"uniform vec2 fullscreen;\n"
 +"in vec2 texCoord;\n"
 +"in vec2 pos;\n"
 +"out vec2 texCoord_interp;\n"
 +"\n"
 +"vec2 normalize_coordinates()\n"
 +"{\n"
 +"     return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n"
 +"}\n"
 +"\n"
 +"void main()\n"
 +"{\n"
 +"     gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n"
 +"     texCoord_interp = texCoord;\n"
 +"}\n\0";
 +
 +const char *FALLBACK_FRAGMENT_SHADER =
 +"#version 330\n"
 +"uniform sampler2D image_texture;\n"
 +"in vec2 texCoord_interp;\n"
 +"out vec4 fragColor;\n"
 +"\n"
 +"void main()\n"
 +"{\n"
 +"     fragColor = texture(image_texture, texCoord_interp);\n"
 +"}\n\0";
 +
 +static void shader_print_errors(const char *task, const char *log, const char *code)
  {
 -      assert(rgba.type == MEM_PIXELS);
 +      LOG(ERROR) << "Shader: " << task << " error:";
 +      LOG(ERROR) << "===== shader string ====";
  
 -      mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1));
 +      stringstream stream(code);
 +      string partial;
  
 -      if(transparent) {
 -              glEnable(GL_BLEND);
 -              glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 +      int line = 1;
 +      while(getline(stream, partial, '\n')) {
 +              if(line < 10) {
 +                      LOG(ERROR) << " " << line << " " << partial;
 +              }
 +              else {
 +                      LOG(ERROR) << line << " " << partial;
 +              }
 +              line++;
        }
 +      LOG(ERROR) << log;
 +}
  
 -      glColor3f(1.0f, 1.0f, 1.0f);
 +static int bind_fallback_shader(void)
 +{
 +      GLint status;
 +      GLchar log[5000];
 +      GLsizei length = 0;
 +      GLuint program = 0;
  
 -      if(rgba.data_type == TYPE_HALF) {
 -              /* for multi devices, this assumes the inefficient method that we allocate
 -               * all pixels on the device even though we only render to a subset */
 -              GLhalf *host_pointer = (GLhalf*)rgba.host_pointer;
 -              float vbuffer[16], *basep;
 -              float *vp = NULL;
 -
 -              host_pointer += 4*y*w;
 -
 -              /* draw half float texture, GLSL shader for display transform assumed to be bound */
 -              GLuint texid;
 -              glGenTextures(1, &texid);
 -              glBindTexture(GL_TEXTURE_2D, texid);
 -              glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, host_pointer);
 -              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 -              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 -
 -              glEnable(GL_TEXTURE_2D);
 -
 -              if(draw_params.bind_display_space_shader_cb) {
 -                      draw_params.bind_display_space_shader_cb();
 +      struct Shader {
 +              const char *source;
 +              GLenum type;
 +      } shaders[2] = {
 +          {FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER},
 +          {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER}
 +    };
 +
 +      program = glCreateProgram();
 +
 +      for(int i = 0; i < 2; i++) {
 +              GLuint shader = glCreateShader(shaders[i].type);
 +
 +              string source_str = shaders[i].source;
 +              const char *c_str = source_str.c_str();
 +
 +              glShaderSource(shader, 1, &c_str, NULL);
 +              glCompileShader(shader);
 +
 +              glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
 +
 +              if(!status) {
 +                      glGetShaderInfoLog(shader, sizeof(log), &length, log);
 +                      shader_print_errors("compile", log, c_str);
 +                      return 0;
                }
  
 -              if(GLEW_VERSION_1_5) {
 -                      if(!vertex_buffer)
 -                              glGenBuffers(1, &vertex_buffer);
 +              glAttachShader(program, shader);
 +      }
 +
 +      /* Link output. */
 +      glBindFragDataLocation(program, 0, "fragColor");
  
 -                      glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
 -                      /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */
 -                      glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
 +      /* Link and error check. */
 +      glLinkProgram(program);
 +
 +      glGetProgramiv(program, GL_LINK_STATUS, &status);
 +      if(!status) {
 +              glGetShaderInfoLog(program, sizeof(log), &length, log);
 +              shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER);
 +              shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER);
 +              return 0;
 +      }
 +
 +      return program;
 +}
 +
 +bool Device::bind_fallback_display_space_shader(const float width, const float height)
 +{
 +      if(fallback_status == FALLBACK_SHADER_STATUS_ERROR) {
 +              return false;
 +      }
  
 -                      vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
 +      if(fallback_status == FALLBACK_SHADER_STATUS_NONE) {
 +              fallback_shader_program = bind_fallback_shader();
 +              fallback_status = FALLBACK_SHADER_STATUS_ERROR;
  
 -                      basep = NULL;
 +              if(fallback_shader_program == 0) {
 +                      return false;
                }
 -              else {
 -                      basep = vbuffer;
 -                      vp = vbuffer;
 +
 +              glUseProgram(fallback_shader_program);
 +              image_texture_location = glGetUniformLocation(fallback_shader_program, "image_texture");
 +              if(image_texture_location < 0) {
 +                      LOG(ERROR) << "Shader doesn't containt the 'image_texture' uniform.";
 +                      return false;
                }
  
 -              if(vp) {
 -                      /* texture coordinate - vertex pair */
 -                      vp[0] = 0.0f;
 -                      vp[1] = 0.0f;
 -                      vp[2] = dx;
 -                      vp[3] = dy;
 -
 -                      vp[4] = 1.0f;
 -                      vp[5] = 0.0f;
 -                      vp[6] = (float)width + dx;
 -                      vp[7] = dy;
 -
 -                      vp[8] = 1.0f;
 -                      vp[9] = 1.0f;
 -                      vp[10] = (float)width + dx;
 -                      vp[11] = (float)height + dy;
 -
 -                      vp[12] = 0.0f;
 -                      vp[13] = 1.0f;
 -                      vp[14] = dx;
 -                      vp[15] = (float)height + dy;
 -
 -                      if(vertex_buffer)
 -                              glUnmapBuffer(GL_ARRAY_BUFFER);
 +              fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen");
 +              if(fullscreen_location < 0) {
 +                      LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform.";
 +                      return false;
                }
  
 -              glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep);
 -              glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float));
 +              fallback_status = FALLBACK_SHADER_STATUS_SUCCESS;
 +      }
  
 -              glEnableClientState(GL_VERTEX_ARRAY);
 -              glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 +      /* Run this every time. */
 +      glUseProgram(fallback_shader_program);
 +      glUniform1i(image_texture_location, 0);
 +      glUniform2f(fullscreen_location, width, height);
 +      return true;
 +}
  
 -              glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 +void Device::draw_pixels(
 +    device_memory& rgba, int y,
 +    int w, int h, int width, int height,
 +    int dx, int dy, int dw, int dh,
 +    bool transparent, const DeviceDrawParams &draw_params)
 +{
 +      const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL);
  
 -              glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 -              glDisableClientState(GL_VERTEX_ARRAY);
 +      assert(rgba.type == MEM_PIXELS);
 +      mem_copy_from(rgba, y, w, h, rgba.memory_elements_size(1));
  
 -              if(vertex_buffer) {
 -                      glBindBuffer(GL_ARRAY_BUFFER, 0);
 -              }
 +      GLuint texid;
 +      glActiveTexture(GL_TEXTURE0);
 +      glGenTextures(1, &texid);
 +      glBindTexture(GL_TEXTURE_2D, texid);
  
 -              if(draw_params.unbind_display_space_shader_cb) {
 -                      draw_params.unbind_display_space_shader_cb();
 -              }
 +      if(rgba.data_type == TYPE_HALF) {
 +              GLhalf *data_pointer = (GLhalf*)rgba.host_pointer;
 +              data_pointer += 4 * y * w;
 +              glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer);
 +      }
 +      else {
 +              uint8_t *data_pointer = (uint8_t*)rgba.host_pointer;
 +              data_pointer += 4 * y * w;
 +              glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_pointer);
 +      }
 +
 +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 +      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 +
 +      if(transparent) {
 +              glEnable(GL_BLEND);
 +              glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 +      }
  
 -              glBindTexture(GL_TEXTURE_2D, 0);
 -              glDisable(GL_TEXTURE_2D);
 -              glDeleteTextures(1, &texid);
 +      GLint shader_program;
 +      if(use_fallback_shader) {
 +              if(!bind_fallback_display_space_shader(dw, dh)) {
 +                      return;
 +              }
 +              shader_program = fallback_shader_program;
        }
        else {
 -              /* fallback for old graphics cards that don't support GLSL, half float,
 -               * and non-power-of-two textures */
 -              glPixelZoom((float)width/(float)w, (float)height/(float)h);
 -              glRasterPos2f(dx, dy);
 +              draw_params.bind_display_space_shader_cb();
 +              glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program);
 +      }
 +
 +      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 */
 +      glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
 +
 +      float *vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
  
 -              uint8_t *pixels = (uint8_t*)rgba.host_pointer;
 +      if(vpointer) {
 +              /* texture coordinate - vertex pair */
 +              vpointer[0] = 0.0f;
 +              vpointer[1] = 0.0f;
 +              vpointer[2] = dx;
 +              vpointer[3] = dy;
  
 -              pixels += 4*y*w;
 +              vpointer[4] = 1.0f;
 +              vpointer[5] = 0.0f;
 +              vpointer[6] = (float)width + dx;
 +              vpointer[7] = dy;
  
 -              glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 +              vpointer[8] = 1.0f;
 +              vpointer[9] = 1.0f;
 +              vpointer[10] = (float)width + dx;
 +              vpointer[11] = (float)height + dy;
  
 -              glRasterPos2f(0.0f, 0.0f);
 -              glPixelZoom(1.0f, 1.0f);
 +              vpointer[12] = 0.0f;
 +              vpointer[13] = 1.0f;
 +              vpointer[14] = dx;
 +              vpointer[15] = (float)height + dy;
 +
 +              if(vertex_buffer) {
 +                      glUnmapBuffer(GL_ARRAY_BUFFER);
 +              }
 +      }
 +
 +      GLuint vertex_array_object;
 +      GLuint position_attribute, texcoord_attribute;
 +
 +      glGenVertexArrays(1, &vertex_array_object);
 +      glBindVertexArray(vertex_array_object);
 +
 +      texcoord_attribute = glGetAttribLocation(shader_program, "texCoord");
 +      position_attribute = glGetAttribLocation(shader_program, "pos");
 +
 +      glEnableVertexAttribArray(texcoord_attribute);
 +      glEnableVertexAttribArray(position_attribute);
 +
 +      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(vertex_buffer) {
 +              glBindBuffer(GL_ARRAY_BUFFER, 0);
        }
  
 -      if(transparent)
 +      if(use_fallback_shader) {
 +              glUseProgram(0);
 +      }
 +      else {
 +              draw_params.unbind_display_space_shader_cb();
 +      }
 +
 +      glBindTexture(GL_TEXTURE_2D, 0);
 +      glDeleteTextures(1, &texid);
 +
 +      if(transparent) {
                glDisable(GL_BLEND);
 +      }
  }
  
  Device *Device::create(DeviceInfo& info, Stats &stats, Profiler &profiler, bool background)
@@@ -423,70 -282,108 +426,108 @@@ string Device::string_from_type(DeviceT
        return "";
  }
  
- vector<DeviceType>& Device::available_types()
+ vector<DeviceType> Device::available_types()
  {
-       thread_scoped_lock lock(device_mutex);
-       if(need_types_update) {
-               types.clear();
-               types.push_back(DEVICE_CPU);
+       vector<DeviceType> types;
+       types.push_back(DEVICE_CPU);
  #ifdef WITH_CUDA
-               if(device_cuda_init()) {
-                       types.push_back(DEVICE_CUDA);
-               }
+       types.push_back(DEVICE_CUDA);
  #endif
  #ifdef WITH_OPENCL
-               if(device_opencl_init()) {
-                       types.push_back(DEVICE_OPENCL);
-               }
+       types.push_back(DEVICE_OPENCL);
  #endif
  #ifdef WITH_NETWORK
-               types.push_back(DEVICE_NETWORK);
+       types.push_back(DEVICE_NETWORK);
  #endif
-               need_types_update = false;
-       }
        return types;
  }
  
- vector<DeviceInfo>& Device::available_devices()
+ vector<DeviceInfo> Device::available_devices(uint mask)
  {
+       /* Lazy initialize devices. On some platforms OpenCL or CUDA drivers can
+        * be broken and cause crashes when only trying to get device info, so
+        * we don't want to do any initialization until the user chooses to. */
        thread_scoped_lock lock(device_mutex);
-       if(need_devices_update) {
-               devices.clear();
+       vector<DeviceInfo> devices;
  #ifdef WITH_OPENCL
-               if(device_opencl_init()) {
-                       device_opencl_info(devices);
+       if(mask & DEVICE_MASK_OPENCL) {
+               if(!(devices_initialized_mask & DEVICE_MASK_OPENCL)) {
+                       if(device_opencl_init()) {
+                               device_opencl_info(opencl_devices);
+                       }
+                       devices_initialized_mask |= DEVICE_MASK_OPENCL;
                }
+               foreach(DeviceInfo& info, opencl_devices) {
+                       devices.push_back(info);
+               }
+       }
  #endif
  #ifdef WITH_CUDA
-               if(device_cuda_init()) {
-                       device_cuda_info(devices);
+       if(mask & DEVICE_MASK_CUDA) {
+               if(!(devices_initialized_mask & DEVICE_MASK_CUDA)) {
+                       if(device_cuda_init()) {
+                               device_cuda_info(cuda_devices);
+                       }
+                       devices_initialized_mask |= DEVICE_MASK_CUDA;
                }
+               foreach(DeviceInfo& info, cuda_devices) {
+                       devices.push_back(info);
+               }
+       }
  #endif
-               device_cpu_info(devices);
+       if(mask & DEVICE_MASK_CPU) {
+               if(!(devices_initialized_mask & DEVICE_MASK_CPU)) {
+                       device_cpu_info(cpu_devices);
+                       devices_initialized_mask |= DEVICE_MASK_CPU;
+               }
+               foreach(DeviceInfo& info, cpu_devices) {
+                       devices.push_back(info);
+               }
+       }
  #ifdef WITH_NETWORK
-               device_network_info(devices);
- #endif
-               need_devices_update = false;
+       if(mask & DEVICE_MASK_NETWORK) {
+               if(!(devices_initialized_mask & DEVICE_MASK_NETWORK)) {
+                       device_network_info(network_devices);
+                       devices_initialized_mask |= DEVICE_MASK_NETWORK;
+               }
+               foreach(DeviceInfo& info, network_devices) {
+                       devices.push_back(info);
+               }
        }
+ #endif
        return devices;
  }
  
- string Device::device_capabilities()
+ string Device::device_capabilities(uint mask)
  {
-       string capabilities = "CPU device capabilities: ";
-       capabilities += device_cpu_capabilities() + "\n";
+       thread_scoped_lock lock(device_mutex);
+       string capabilities = "";
+       if(mask & DEVICE_MASK_CPU) {
+               capabilities += "\nCPU device capabilities: ";
+               capabilities += device_cpu_capabilities() + "\n";
+       }
  
  #ifdef WITH_OPENCL
-       if(device_opencl_init()) {
-               capabilities += "\nOpenCL device capabilities:\n";
-               capabilities += device_opencl_capabilities();
+       if(mask & DEVICE_MASK_OPENCL) {
+               if(device_opencl_init()) {
+                       capabilities += "\nOpenCL device capabilities:\n";
+                       capabilities += device_opencl_capabilities();
+               }
        }
  #endif
  
  #ifdef WITH_CUDA
-       if(device_cuda_init()) {
-               capabilities += "\nCUDA device capabilities:\n";
-               capabilities += device_cuda_capabilities();
+       if(mask & DEVICE_MASK_CUDA) {
+               if(device_cuda_init()) {
+                       capabilities += "\nCUDA device capabilities:\n";
+                       capabilities += device_cuda_capabilities();
+               }
        }
  #endif
  
  
  DeviceInfo Device::get_multi_device(const vector<DeviceInfo>& subdevices, int threads, bool background)
  {
-       assert(subdevices.size() > 1);
+       assert(subdevices.size() > 0);
+       if(subdevices.size() == 1) {
+               /* No multi device needed. */
+               return subdevices.front();
+       }
  
        DeviceInfo info;
        info.type = DEVICE_MULTI;
  
  void Device::tag_update()
  {
-       need_types_update = true;
-       need_devices_update = true;
+       free_memory();
  }
  
  void Device::free_memory()
  {
-       need_types_update = true;
-       need_devices_update = true;
-       types.free_memory();
-       devices.free_memory();
+       devices_initialized_mask = 0;
+       cuda_devices.clear();
+       opencl_devices.clear();
+       cpu_devices.clear();
+       network_devices.clear();
  }
  
  CCL_NAMESPACE_END
@@@ -40,7 -40,7 +40,7 @@@ class RenderTile
  /* Device Types */
  
  enum DeviceType {
-       DEVICE_NONE,
+       DEVICE_NONE = 0,
        DEVICE_CPU,
        DEVICE_OPENCL,
        DEVICE_CUDA,
        DEVICE_MULTI
  };
  
+ enum DeviceTypeMask {
+       DEVICE_MASK_CPU = (1 << DEVICE_CPU),
+       DEVICE_MASK_OPENCL = (1 << DEVICE_OPENCL),
+       DEVICE_MASK_CUDA = (1 << DEVICE_CUDA),
+       DEVICE_MASK_NETWORK = (1 << DEVICE_NETWORK),
+       DEVICE_MASK_ALL = ~0
+ };
+ #define DEVICE_MASK(type) (DeviceTypeMask)(1 << type)
  class DeviceInfo {
  public:
        DeviceType type;
@@@ -249,26 -259,13 +259,26 @@@ struct DeviceDrawParams 
  class Device {
        friend class device_sub_ptr;
  protected:
 -      Device(DeviceInfo& info_, Stats &stats_, Profiler &profiler_, bool background) : background(background), vertex_buffer(0), info(info_), stats(stats_), profiler(profiler_) {}
 +      enum {
 +              FALLBACK_SHADER_STATUS_NONE = 0,
 +              FALLBACK_SHADER_STATUS_ERROR,
 +              FALLBACK_SHADER_STATUS_SUCCESS,
 +      };
 +
 +      Device(DeviceInfo& info_, Stats &stats_, Profiler &profiler_, bool background) : background(background),
 +          vertex_buffer(0),
 +          fallback_status(FALLBACK_SHADER_STATUS_NONE), fallback_shader_program(0),
 +          info(info_), stats(stats_), profiler(profiler_) {}
  
        bool background;
        string error_msg;
  
        /* used for real time display */
        unsigned int vertex_buffer;
 +      int fallback_status, fallback_shader_program;
 +      int image_texture_location, fullscreen_location;
 +
 +      bool bind_fallback_display_space_shader(const float width, const float height);
  
        virtual device_ptr mem_alloc_sub_ptr(device_memory& /*mem*/, int /*offset*/, int /*size*/)
        {
@@@ -321,10 -318,9 +331,10 @@@ public
        virtual void task_cancel() = 0;
  
        /* opengl drawing */
 -      virtual void draw_pixels(device_memory& mem, int y, int w, int h,
 -              int dx, int dy, int width, int height, bool transparent,
 -              const DeviceDrawParams &draw_params);
 +      virtual 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);
  
  #ifdef WITH_NETWORK
        /* networking */
  
        static DeviceType type_from_string(const char *name);
        static string string_from_type(DeviceType type);
-       static vector<DeviceType>& available_types();
-       static vector<DeviceInfo>& available_devices();
-       static string device_capabilities();
+       static vector<DeviceType> available_types();
+       static vector<DeviceInfo> available_devices(uint device_type_mask = DEVICE_MASK_ALL);
+       static string device_capabilities(uint device_type_mask = DEVICE_MASK_ALL);
        static DeviceInfo get_multi_device(const vector<DeviceInfo>& subdevices,
                                           int threads,
                                           bool background);
@@@ -371,8 -367,11 +381,11 @@@ private
        /* Indicted whether device types and devices lists were initialized. */
        static bool need_types_update, need_devices_update;
        static thread_mutex device_mutex;
-       static vector<DeviceType> types;
-       static vector<DeviceInfo> devices;
+       static vector<DeviceInfo> cuda_devices;
+       static vector<DeviceInfo> opencl_devices;
+       static vector<DeviceInfo> cpu_devices;
+       static vector<DeviceInfo> network_devices;
+       static uint devices_initialized_mask;
  };
  
  CCL_NAMESPACE_END