Page Menu
Home
Search
Configure Global Search
Log In
Files
F115758
auto_tile_size_release_04.py
Greg Zaal (gregzaal)
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
Greg Zaal (gregzaal)
Oct 10 2014, 7:42 PM
Size
13 KB
Subscribers
None
auto_tile_size_release_04.py
View Options
# 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 Render Tile Size"
,
"description"
:
"Estimate the tile size that will render the fastest"
,
"author"
:
"Greg Zaal"
,
"version"
:
(
2
,
4
),
"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"
,
"tracker_url"
:
"https://projects.blender.org/tracker/index.php?func=detail&aid=36785&group_id=153&atid=467"
,
"category"
:
"Render"
}
import
bpy
from
bpy.app.handlers
import
persistent
from
math
import
ceil
@persistent
def
on_scene_update
(
context
):
scene
=
bpy
.
context
.
scene
if
scene
.
render
.
engine
not
in
[
'CYCLES'
,
'BLENDER_RENDER'
]:
return
False
renderer
=
scene
.
render
.
engine
prevrenderer
=
scene
.
TileSizePrevRenderer
device
=
scene
.
cycles
.
device
prevdevice
=
scene
.
TileSizePrevDevice
border
=
scene
.
render
.
use_border
prev_border
=
scene
.
TileSizePrevBorder
threads
=
scene
.
render
.
threads
prev_threads
=
scene
.
TileSizePrevThreads
choice
=
0
if
(
device
==
'GPU'
and
bpy
.
context
.
user_preferences
.
system
.
compute_device_type
!=
'NONE'
)
and
scene
.
render
.
engine
==
'CYCLES'
:
choice
=
scene
.
TileSizeGPUChoice
elif
(
device
==
'CPU'
or
bpy
.
context
.
user_preferences
.
system
.
compute_device_type
==
'NONE'
)
and
scene
.
render
.
engine
==
'CYCLES'
:
choice
=
scene
.
TileSizeCPUChoice
elif
scene
.
render
.
engine
==
'BLENDER_RENDER'
:
choice
=
scene
.
TileSizeBIChoice
prevchoice
=
int
(
scene
.
TileSizePrevChoice
)
res
=
str
(
int
(
getActualRes
(
'x'
)))
+
'x'
+
str
(
int
(
getActualRes
(
'y'
)))
prevres
=
scene
.
TileSizePrevRes
actual_ts
=
str
(
scene
.
render
.
tile_x
)
+
'x'
+
str
(
scene
.
render
.
tile_y
)
prevactual_ts
=
scene
.
TileSizePrevActualTileSize
border_res
=
(
str
(
scene
.
render
.
border_min_x
)
+
"x"
+
str
(
scene
.
render
.
border_min_y
))
+
'-'
+
(
str
(
scene
.
render
.
border_max_x
)
+
"x"
+
str
(
scene
.
render
.
border_max_y
))
prev_border_res
=
scene
.
TileSizePrevBorderRes
# detect relevant changes in scene
change_triggers
=
[
renderer
!=
prevrenderer
,
device
!=
prevdevice
,
border
!=
prev_border
,
threads
!=
prev_threads
,
int
(
choice
)
!=
prevchoice
,
res
!=
prevres
,
border_res
!=
prev_border_res
,
actual_ts
!=
prevactual_ts
]
if
any
(
change_triggers
)
and
scene
.
TileSizeEnable
:
scene
.
TileSizePrevRenderer
=
renderer
scene
.
TileSizePrevDevice
=
device
scene
.
TileSizePrevBorder
=
border
scene
.
TileSizePrevThreads
=
threads
scene
.
TileSizePrevChoice
=
choice
scene
.
TileSizePrevBorderRes
=
border_res
do_set_tile_size
(
context
)
else
:
pass
return
True
def
do_set_tile_size
(
context
):
context
=
bpy
.
context
scene
=
context
.
scene
if
scene
.
render
.
engine
not
in
[
'CYCLES'
,
'BLENDER_RENDER'
]:
print
(
"Auto Tile Size is not supported for this renderer"
)
return
False
scene
.
TileSizeFirstRun
=
False
device
=
scene
.
cycles
.
device
target
=
0
xres
=
int
(
getActualRes
(
'x'
))
yres
=
int
(
getActualRes
(
'y'
))
realxres
=
xres
realyres
=
yres
if
context
.
scene
.
render
.
use_border
:
xres
=
int
(
xres
*
(
context
.
scene
.
render
.
border_max_x
-
context
.
scene
.
render
.
border_min_x
))
yres
=
int
(
yres
*
(
context
.
scene
.
render
.
border_max_y
-
context
.
scene
.
render
.
border_min_y
))
if
(
device
==
'GPU'
and
context
.
user_preferences
.
system
.
compute_device_type
!=
'NONE'
)
and
scene
.
render
.
engine
==
'CYCLES'
:
target
=
int
(
scene
.
TileSizeGPUChoice
)
elif
(
device
==
'CPU'
or
context
.
user_preferences
.
system
.
compute_device_type
==
'NONE'
)
and
scene
.
render
.
engine
==
'CYCLES'
:
target
=
int
(
scene
.
TileSizeCPUChoice
)
elif
scene
.
render
.
engine
==
'BLENDER_RENDER'
:
target
=
int
(
scene
.
TileSizeBIChoice
)
else
:
print
(
"Failed to get compute device"
)
return
False
scene
.
TileSizePrevChoice
=
str
(
target
)
scene
.
TileSizePrevDevice
=
device
numtiles_x
=
ceil
(
xres
/
target
)
numtiles_y
=
ceil
(
yres
/
target
)
if
scene
.
TileSizeOptimal
==
"optimal"
:
tile_x
=
ceil
(
xres
/
numtiles_x
)
tile_y
=
ceil
(
yres
/
numtiles_y
)
print
(
str
(
tile_x
)
+
"x"
+
str
(
tile_y
)
+
" ("
+
str
(
int
(
xres
/
tile_x
))
+
"x"
+
str
(
int
(
yres
/
tile_y
))
+
" tiles)"
)
else
:
tile_x
=
target
tile_y
=
target
print
(
str
(
tile_x
)
+
"x"
+
str
(
tile_y
)
+
" ("
+
str
(
xres
/
tile_x
)
+
" x "
+
str
(
yres
/
tile_y
)
+
" tiles)"
)
# Detect if there are fewer tiles than available threads
if
((
ceil
(
numtiles_x
)
*
ceil
(
numtiles_y
))
<
scene
.
render
.
threads
)
and
not
((
device
==
'GPU'
and
context
.
user_preferences
.
system
.
compute_device_type
!=
'NONE'
)
and
scene
.
render
.
engine
==
'CYCLES'
):
scene
.
TileSizeThreadsError
=
True
else
:
scene
.
TileSizeThreadsError
=
False
scene
.
render
.
tile_x
=
tile_x
scene
.
render
.
tile_y
=
tile_y
scene
.
TileSizePrevRes
=
str
(
realxres
)
+
'x'
+
str
(
realyres
)
scene
.
TileSizePrevActualTileSize
=
str
(
scene
.
render
.
tile_x
)
+
'x'
+
str
(
scene
.
render
.
tile_y
)
return
True
def
isprime
(
num
):
for
x
in
range
(
2
,
int
(
num
**
0.5
)
+
1
):
if
num
%
x
==
0
:
return
False
return
True
def
getActualRes
(
xy
):
rend
=
bpy
.
context
.
scene
.
render
rend_percent
=
rend
.
resolution_percentage
*
0.01
x
=
(
str
(
rend
.
resolution_x
*
rend_percent
)
.
split
(
'.'
))[
0
]
y
=
(
str
(
rend
.
resolution_y
*
rend_percent
)
.
split
(
'.'
))[
0
]
returnvar
=
x
if
xy
==
"y"
:
returnvar
=
y
return
(
returnvar
)
class
SetTileSize
(
bpy
.
types
.
Operator
):
'The first render may not obey the tile-size set here'
bl_idname
=
'autotile.set'
bl_label
=
'Set'
def
execute
(
self
,
context
):
context
.
scene
.
TileSizeFirstRun
=
False
if
do_set_tile_size
(
context
):
return
{
'FINISHED'
}
else
:
return
{
'CANCELLED'
}
def
ui_layout
(
renderer
,
layout
,
context
):
scene
=
context
.
scene
col
=
layout
.
column
(
align
=
True
)
row
=
col
.
row
(
align
=
True
)
row
.
prop
(
scene
,
'TileSizeEnable'
,
toggle
=
True
)
row
.
prop
(
scene
,
'TileSizeAdvancedUI'
,
toggle
=
True
,
text
=
''
,
icon
=
'PREFERENCES'
)
if
scene
.
TileSizeAdvancedUI
:
col
.
label
(
"Target tile size:"
)
row
=
col
.
row
(
align
=
True
)
if
renderer
==
'CYCLES'
:
if
scene
.
cycles
.
device
==
'GPU'
and
context
.
user_preferences
.
system
.
compute_device_type
!=
'NONE'
and
scene
.
render
.
engine
==
'CYCLES'
:
row
.
prop
(
scene
,
'TileSizeGPUChoice'
,
expand
=
True
)
elif
scene
.
cycles
.
device
==
'CPU'
or
context
.
user_preferences
.
system
.
compute_device_type
==
'NONE'
and
scene
.
render
.
engine
==
'CYCLES'
:
row
.
prop
(
scene
,
'TileSizeCPUChoice'
,
expand
=
True
)
elif
renderer
==
'BLENDER_RENDER'
:
row
.
prop
(
scene
,
'TileSizeBIChoice'
,
expand
=
True
)
row
=
col
.
row
(
align
=
True
)
row
.
prop
(
scene
,
'TileSizeOptimal'
,
text
=
'Consistent Tiles'
,
expand
=
True
)
if
scene
.
TileSizeFirstRun
:
col
=
layout
.
column
(
align
=
True
)
col
.
operator
(
'autotile.set'
,
text
=
"First-render fix"
,
icon
=
'ERROR'
)
elif
scene
.
TileSizePrevDevice
!=
scene
.
cycles
.
device
:
col
=
layout
.
column
(
align
=
True
)
col
.
operator
(
'autotile.set'
,
text
=
"Device changed - fix"
,
icon
=
'ERROR'
)
if
(
scene
.
render
.
tile_x
/
scene
.
render
.
tile_y
>
2
)
or
(
scene
.
render
.
tile_x
/
scene
.
render
.
tile_y
<
0.5
):
# if not very square tile
col
.
label
(
text
=
"Warning: Tile size is not very square"
,
icon
=
'ERROR'
)
col
.
label
(
text
=
" Try a slightly different resolution"
)
col
.
label
(
text
=
" or choose
\"
Exact
\"
above"
)
if
scene
.
TileSizeThreadsError
:
col
.
label
(
text
=
"Warning: There are fewer tiles than render threads"
,
icon
=
'ERROR'
)
def
menu_func_cycles
(
self
,
context
):
layout
=
self
.
layout
ui_layout
(
'CYCLES'
,
layout
,
context
)
def
menu_func_bi
(
self
,
context
):
layout
=
self
.
layout
ui_layout
(
'BLENDER_RENDER'
,
layout
,
context
)
def
_update_tile_size
(
self
,
context
):
do_set_tile_size
(
context
)
def
register
():
bpy
.
types
.
Scene
.
TileSizeGPUChoice
=
bpy
.
props
.
EnumProperty
(
name
=
"Target GPU Tile Size"
,
items
=
((
"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"
)),
default
=
'256'
,
description
=
"Square dimensions of tiles"
,
update
=
_update_tile_size
)
bpy
.
types
.
Scene
.
TileSizeCPUChoice
=
bpy
.
props
.
EnumProperty
(
name
=
"Target CPU Tile Size"
,
items
=
((
"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"
)),
default
=
'32'
,
description
=
"Square dimensions of tiles"
,
update
=
_update_tile_size
)
bpy
.
types
.
Scene
.
TileSizeBIChoice
=
bpy
.
props
.
EnumProperty
(
name
=
"Target CPU Tile Size"
,
items
=
((
"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"
)),
default
=
'64'
,
description
=
"Square dimensions of tiles"
,
update
=
_update_tile_size
)
bpy
.
types
.
Scene
.
TileSizeOptimal
=
bpy
.
props
.
EnumProperty
(
name
=
"Optimal Tiles"
,
default
=
"optimal"
,
description
=
"Match the target size exactly, or try to find a similar tile size for best performance"
,
items
=
((
"optimal"
,
"Optimal"
,
"All tiles will be the same size and roughly match the target (usually renders faster)"
),
(
"exact"
,
"Exact"
,
"Most tiles will match the target, but tiles around the edges may be rectangular (renders slower)"
)),
update
=
_update_tile_size
)
bpy
.
types
.
Scene
.
TileSizeEnable
=
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
)
bpy
.
types
.
Scene
.
TileSizeAdvancedUI
=
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)
bpy
.
types
.
Scene
.
TileSizeFirstRun
=
bpy
.
props
.
BoolProperty
(
default
=
True
)
bpy
.
types
.
Scene
.
TileSizeThreadsError
=
bpy
.
props
.
BoolProperty
()
bpy
.
types
.
Scene
.
TileSizePrevChoice
=
bpy
.
props
.
StringProperty
(
default
=
'0'
)
bpy
.
types
.
Scene
.
TileSizePrevRenderer
=
bpy
.
props
.
StringProperty
(
default
=
'prevrenderer'
)
bpy
.
types
.
Scene
.
TileSizePrevDevice
=
bpy
.
props
.
StringProperty
(
default
=
'prevdevice'
)
bpy
.
types
.
Scene
.
TileSizePrevRes
=
bpy
.
props
.
StringProperty
(
default
=
'prevres'
)
bpy
.
types
.
Scene
.
TileSizePrevBorder
=
bpy
.
props
.
BoolProperty
(
default
=
False
)
bpy
.
types
.
Scene
.
TileSizePrevBorderRes
=
bpy
.
props
.
StringProperty
(
default
=
"prevborderres"
)
bpy
.
types
.
Scene
.
TileSizePrevActualTileSize
=
bpy
.
props
.
StringProperty
(
default
=
'prevactual'
)
bpy
.
types
.
Scene
.
TileSizePrevThreads
=
bpy
.
props
.
IntProperty
(
default
=
0
)
bpy
.
types
.
CyclesRender_PT_performance
.
append
(
menu_func_cycles
)
# Note, the Cycles addon must be registered first, otherwise this panel doesn't exist
bpy
.
types
.
RENDER_PT_performance
.
append
(
menu_func_bi
)
bpy
.
app
.
handlers
.
scene_update_post
.
append
(
on_scene_update
)
bpy
.
utils
.
register_module
(
__name__
)
def
unregister
():
del
bpy
.
types
.
Scene
.
TileSizeGPUChoice
del
bpy
.
types
.
Scene
.
TileSizeCPUChoice
del
bpy
.
types
.
Scene
.
TileSizeBIChoice
del
bpy
.
types
.
Scene
.
TileSizeOptimal
del
bpy
.
types
.
Scene
.
TileSizeEnable
del
bpy
.
types
.
Scene
.
TileSizeAdvancedUI
del
bpy
.
types
.
Scene
.
TileSizeFirstRun
del
bpy
.
types
.
Scene
.
TileSizeThreadsError
del
bpy
.
types
.
Scene
.
TileSizePrevChoice
del
bpy
.
types
.
Scene
.
TileSizePrevRenderer
del
bpy
.
types
.
Scene
.
TileSizePrevDevice
del
bpy
.
types
.
Scene
.
TileSizePrevRes
del
bpy
.
types
.
Scene
.
TileSizePrevBorder
del
bpy
.
types
.
Scene
.
TileSizePrevBorderRes
del
bpy
.
types
.
Scene
.
TileSizePrevActualTileSize
del
bpy
.
types
.
Scene
.
TileSizePrevThreads
bpy
.
types
.
CyclesRender_PT_performance
.
remove
(
menu_func_cycles
)
bpy
.
types
.
RENDER_PT_performance
.
remove
(
menu_func_bi
)
bpy
.
app
.
handlers
.
scene_update_post
.
remove
(
on_scene_update
)
bpy
.
utils
.
unregister_module
(
__name__
)
if
__name__
==
"__main__"
:
register
()
File Metadata
Details
Attached
Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
6c/27/e042f67a935331aabe7cc476f120
Attached To
T36785: Automatically calculate the best tile size for the fastest render
Event Timeline
Log In to Comment