[Bf-extensions-cvs] [a259323] master: Add Auto Tile Size to Contrib

Greg Zaal noreply at git.blender.org
Sat Nov 1 15:17:06 CET 2014


Commit: a2593232c7a886531434db5335b6de4afbc93ea3
Author: Greg Zaal
Date:   Sat Nov 1 16:14:15 2014 +0200
Branches: master
https://developer.blender.org/rBACa2593232c7a886531434db5335b6de4afbc93ea3

Add Auto Tile Size to Contrib

This add-on estimates the render tile size which provides the best performance based on the render resolution (including border and percentage), render engine and render device.

More info about the add-on: http://adaptivesamples.com/2013/11/05/auto-tile-size-addon-updated-again/

===================================================================

A	render_auto_tile_size.py

===================================================================

diff --git a/render_auto_tile_size.py b/render_auto_tile_size.py
new file mode 100644
index 0000000..576e86c
--- /dev/null
+++ b/render_auto_tile_size.py
@@ -0,0 +1,319 @@
+# BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# END GPL LICENSE BLOCK #####
+
+bl_info = {
+    "name": "Auto Tile Size",
+    "description": "Estimate and set the tile size that will render the fastest",
+    "author": "Greg Zaal",
+    "version": (2, 7),
+    "blender": (2, 72, 0),
+    "location": "Render Settings > Performance",
+    "warning": "",
+    "wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.6/Py/Scripts/Render/Auto_Tile_Size",
+    "category": "Render",
+}
+
+
+import bpy
+from bpy.app.handlers import persistent
+from math import ceil, floor
+
+
+SUPPORTED_RENDER_ENGINES = {'CYCLES', 'BLENDER_RENDER'}
+TILE_SIZES = (
+    ('16', "16", "16 x 16"),
+    ('32', "32", "32 x 32"),
+    ('64', "64", "64 x 64"),
+    ('128', "128", "128 x 128"),
+    ('256', "256", "256 x 256"),
+    ('512', "512", "512 x 512"),
+    ('1024', "1024", "1024 x 1024"),
+)
+
+
+def _update_tile_size(self, context):
+    do_set_tile_size(context)
+
+
+class AutoTileSizeSettings(bpy.types.PropertyGroup):
+    gpu_choice = bpy.props.EnumProperty(
+        name="Target GPU Tile Size",
+        items=TILE_SIZES,
+        default='256',
+        description="Square dimentions of tiles",
+        update=_update_tile_size)
+
+    cpu_choice = bpy.props.EnumProperty(
+        name="Target CPU Tile Size",
+        items=TILE_SIZES,
+        default='32',
+        description="Square dimentions of tiles",
+        update=_update_tile_size)
+
+    bi_choice = bpy.props.EnumProperty(
+        name="Target CPU Tile Size",
+        items=TILE_SIZES,
+        default='64',
+        description="Square dimentions of tiles",
+        update=_update_tile_size)
+
+    # XXX There is no need for this to be an enum, a mere bool should be enough?
+    use_optimal = bpy.props.BoolProperty(
+        name="Optimal Tiles",
+        default=True,
+        description="Try to find a similar tile size for best performance, instead of using exact selected one",
+        update=_update_tile_size)
+
+    is_enabled = bpy.props.BoolProperty(
+        name="Auto Tile Size",
+        default=True,
+        description="Calculate the best tile size based on factors of the render size and the chosen target",
+        update=_update_tile_size)
+
+    use_advanced_ui = bpy.props.BoolProperty(
+        name="Advanced Settings",
+        default=False,
+        description="Show extra options for more control over the calculated tile size")
+
+    # Internally used props (not for GUI)
+    first_run = bpy.props.BoolProperty(default=True, options={'HIDDEN'})
+    threads_error = bpy.props.BoolProperty(options={'HIDDEN'})
+    prev_choice = bpy.props.StringProperty(default='', options={'HIDDEN'})
+    prev_engine = bpy.props.StringProperty(default='', options={'HIDDEN'})
+    prev_device = bpy.props.StringProperty(default='', options={'HIDDEN'})
+    prev_res = bpy.props.IntVectorProperty(default=(0, 0), size=2, options={'HIDDEN'})
+    prev_border = bpy.props.BoolProperty(default=False, options={'HIDDEN'})
+    prev_border_res = bpy.props.FloatVectorProperty(default=(0, 0, 0, 0), size=4, options={'HIDDEN'})
+    prev_actual_tile_size = bpy.props.IntVectorProperty(default=(0, 0), size=2, options={'HIDDEN'})
+    prev_threads = bpy.props.IntProperty(default=0, options={'HIDDEN'})
+
+
+def ats_poll(context):
+    scene = context.scene
+    if scene.render.engine not in SUPPORTED_RENDER_ENGINES or not scene.ats_settings.is_enabled:
+        return False
+    return True
+
+
+def ats_get_engine_is_gpu(engine, device, userpref):
+    return engine == 'CYCLES' and device == 'GPU' and userpref.system.compute_device_type != 'NONE'
+
+
+def ats_get_tilesize_prop(engine, device, userpref):
+    if ats_get_engine_is_gpu(engine, device, userpref):
+        return "gpu_choice"
+    elif engine == 'CYCLES':
+        return "cpu_choice"
+    return "bi_choice"
+
+
+ at persistent
+def on_scene_update(scene):
+    context = bpy.context
+
+    if not ats_poll(context):
+        return
+
+    userpref = context.user_preferences
+
+    settings = scene.ats_settings
+    render = scene.render
+    engine = render.engine
+
+    # scene.cycles might not always exist (Cycles is an addon)...
+    device = scene.cycles.device if engine == 'CYCLES' else settings.prev_device
+    border = render.use_border
+    threads = render.threads
+
+    choice = getattr(settings, ats_get_tilesize_prop(engine, device, userpref))
+
+    res = get_actual_res(render)
+    actual_ts = (render.tile_x, render.tile_y)
+    border_res = (render.border_min_x, render.border_min_y, render.border_max_x, render.border_max_y)
+
+    # detect relevant changes in scene
+    do_change = (engine != settings.prev_engine or
+                 device != settings.prev_device or
+                 border != settings.prev_border or
+                 threads != settings.prev_threads or
+                 choice != settings.prev_choice or
+                 res != settings.prev_res[:] or
+                 border_res != settings.prev_border_res[:] or
+                 actual_ts != settings.prev_actual_tile_size[:])
+    if do_change:
+        do_set_tile_size(context)
+
+
+def get_actual_res(render):
+    rend_percent = render.resolution_percentage * 0.01
+    # floor is implicitly done by int conversion...
+    return (int(render.resolution_x * rend_percent), int(render.resolution_y * rend_percent))
+
+
+def do_set_tile_size(context):
+    if not ats_poll(context):
+        return False
+
+    scene = context.scene
+    userpref = context.user_preferences
+
+    settings = scene.ats_settings
+    render = scene.render
+    engine = render.engine
+    device = scene.cycles.device if engine == 'CYCLES' else settings.prev_device
+    border = render.use_border
+    threads = render.threads
+
+    realxres, realyres = xres, yres = res = get_actual_res(scene.render)
+
+    if border:
+        xres = round(xres * (render.border_max_x - render.border_min_x))
+        yres = round(yres * (render.border_max_y - render.border_min_y))
+
+    choice = getattr(settings, ats_get_tilesize_prop(engine, device, userpref))
+    target = int(choice)
+
+    numtiles_x = ceil(xres / target)
+    numtiles_y = ceil(yres / target)
+    if settings.use_optimal:
+        tile_x = ceil(xres / numtiles_x)
+        tile_y = ceil(yres / numtiles_y)
+    else:
+        tile_x = target
+        tile_y = target
+
+    print("Tile size: %dx%d (%dx%d tiles)" % (tile_x, tile_y, ceil(xres / tile_x), ceil(yres / tile_y)))
+
+    render.tile_x = tile_x
+    render.tile_y = tile_y
+
+    # Detect if there are fewer tiles than available threads
+    if ((numtiles_x * numtiles_y) < threads) and not ats_get_engine_is_gpu(engine, device, userpref):
+        settings.threads_error = True
+    else:
+        settings.threads_error = False
+
+    settings.prev_engine = engine
+    settings.prev_device = device
+    settings.prev_border = border
+    settings.prev_threads = threads
+    settings.prev_choice = choice
+    settings.prev_res = res
+    settings.prev_border_res = (render.border_min_x, render.border_min_y, render.border_max_x, render.border_max_y)
+    settings.prev_actual_tile_size = (tile_x, tile_y)
+    settings.first_run = False
+
+    return True
+
+
+class SetTileSize(bpy.types.Operator):
+    """The first render may not obey the tile-size set here"""
+    bl_idname = "render.autotilesize_set"
+    bl_label = "Set"
+
+    @classmethod
+    def poll(clss, context):
+        return ats_poll(context)
+
+    def execute(self, context):
+        if do_set_tile_size(context):
+            return {'FINISHED'}
+        return {'CANCELLED'}
+
+
+# ##### INTERFACE #####
+
+def ui_layout(engine, layout, context):
+    scene = context.scene
+    userpref = context.user_preferences
+
+    settings = scene.ats_settings
+    render = scene.render
+    engine = render.engine
+    device = scene.cycles.device if engine == 'CYCLES' else settings.prev_device
+
+    col = layout.column(align=True)
+    sub = col.column(align=True)
+    row = sub.row(align=True)
+    row.prop(settings, "is_enabled", toggle=True)
+    row.prop(settings, "use_advanced_ui", toggle=True, text="", icon='PREFERENCES')
+
+    sub = col.column(align=True)
+    sub.enabled = settings.is_enabled
+
+    if settings.use_advanced_ui:
+        sub.label("Target tile size:")
+
+        row = sub.row(align=True)
+        row.prop(settings, ats_get_tilesize_prop(engine, device, userpref), expand=True)
+        sub.prop(settings, "use_optimal", text="Calculate Optimal Size")
+
+    if settings.first_run:
+        sub = layout.column(align=True)
+        sub.operator("render.autotilesize_set", text="First-render fix", icon='ERROR')
+    elif settings.prev_device != device:
+        sub = layout.column(align=True)
+        sub.operator("render.autotilesize_set", text="Device changed - fix", icon='ERROR')
+
+    if (render.tile_x / render.tile_y > 2) or (render.tile_x / render.tile_y < 0.5):  # if not very square tile
+        sub.label(text="Warning: Tile size is not very square", icon='ERROR')
+        sub.label(text="    Try a slightly different resolution")
+        sub.label(text="    or choose \"Exact\" above")
+    if settings.threads_error:
+        sub.label(text="Warning: Fewer tiles than render threads", icon='ERROR')
+
+
+def menu_func_cycles(self, con

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list