Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
B
blender-addons
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
blender
blender-addons
Commits
4f28fe78
Commit
4f28fe78
authored
9 years ago
by
Bastien Montagne
Browse files
Options
Downloads
Patches
Plain Diff
Fix typo (dimention > dimension), and cleanup the ugly windows EOL (grrrrr).
parent
8c41091b
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
render_auto_tile_size.py
+428
-429
428 additions, 429 deletions
render_auto_tile_size.py
with
428 additions
and
429 deletions
render_auto_tile_size.py
+
428
−
429
View file @
4f28fe78
# BEGIN GPL LICENSE BLOCK #####
# BEGIN GPL LICENSE BLOCK #####
#
#
# This program is free software; you can redistribute it and/or
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# of the License, or (at your option) any later version.
#
#
# This program is distributed in the hope that it will be useful,
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
#
# END GPL LICENSE BLOCK #####
# END GPL LICENSE BLOCK #####
bl_info
=
{
bl_info
=
{
"
name
"
:
"
Auto Tile Size
"
,
"
name
"
:
"
Auto Tile Size
"
,
"
description
"
:
"
Estimate and set the tile size that will render the fastest
"
,
"
description
"
:
"
Estimate and set the tile size that will render the fastest
"
,
"
author
"
:
"
Greg Zaal
"
,
"
author
"
:
"
Greg Zaal
"
,
"
version
"
:
(
3
,
1
),
"
version
"
:
(
3
,
1
,
1
),
"
blender
"
:
(
2
,
74
,
0
),
"
blender
"
:
(
2
,
74
,
0
),
"
location
"
:
"
Render Settings > Performance
"
,
"
location
"
:
"
Render Settings > Performance
"
,
"
warning
"
:
""
,
"
warning
"
:
""
,
"
wiki_url
"
:
"
http://wiki.blender.org/index.php?title=Extensions:2.6/Py/Scripts/Render/Auto_Tile_Size
"
,
"
wiki_url
"
:
"
http://wiki.blender.org/index.php?title=Extensions:2.6/Py/Scripts/Render/Auto_Tile_Size
"
,
"
category
"
:
"
Render
"
,
"
category
"
:
"
Render
"
,
}
}
import
bpy
import
bpy
from
bpy.app.handlers
import
persistent
from
bpy.app.handlers
import
persistent
from
math
import
ceil
,
floor
,
sqrt
from
math
import
ceil
,
floor
,
sqrt
SUPPORTED_RENDER_ENGINES
=
{
'
CYCLES
'
,
'
BLENDER_RENDER
'
}
SUPPORTED_RENDER_ENGINES
=
{
'
CYCLES
'
,
'
BLENDER_RENDER
'
}
TILE_SIZES
=
(
TILE_SIZES
=
(
(
'
16
'
,
"
16
"
,
"
16 x 16
"
),
(
'
16
'
,
"
16
"
,
"
16 x 16
"
),
(
'
32
'
,
"
32
"
,
"
32 x 32
"
),
(
'
32
'
,
"
32
"
,
"
32 x 32
"
),
(
'
64
'
,
"
64
"
,
"
64 x 64
"
),
(
'
64
'
,
"
64
"
,
"
64 x 64
"
),
(
'
128
'
,
"
128
"
,
"
128 x 128
"
),
(
'
128
'
,
"
128
"
,
"
128 x 128
"
),
(
'
256
'
,
"
256
"
,
"
256 x 256
"
),
(
'
256
'
,
"
256
"
,
"
256 x 256
"
),
(
'
512
'
,
"
512
"
,
"
512 x 512
"
),
(
'
512
'
,
"
512
"
,
"
512 x 512
"
),
(
'
1024
'
,
"
1024
"
,
"
1024 x 1024
"
),
(
'
1024
'
,
"
1024
"
,
"
1024 x 1024
"
),
)
)
def
_update_tile_size
(
self
,
context
):
def
_update_tile_size
(
self
,
context
):
do_set_tile_size
(
context
)
do_set_tile_size
(
context
)
class
AutoTileSizeSettings
(
bpy
.
types
.
PropertyGroup
):
class
AutoTileSizeSettings
(
bpy
.
types
.
PropertyGroup
):
gpu_choice
=
bpy
.
props
.
EnumProperty
(
gpu_choice
=
bpy
.
props
.
EnumProperty
(
name
=
"
Target GPU Tile Size
"
,
name
=
"
Target GPU Tile Size
"
,
items
=
TILE_SIZES
,
items
=
TILE_SIZES
,
default
=
'
256
'
,
default
=
'
256
'
,
description
=
"
Square dimentions of tiles for GPU rendering
"
,
description
=
"
Square dimensions of tiles for GPU rendering
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
cpu_choice
=
bpy
.
props
.
EnumProperty
(
cpu_choice
=
bpy
.
props
.
EnumProperty
(
name
=
"
Target CPU Tile Size
"
,
name
=
"
Target CPU Tile Size
"
,
items
=
TILE_SIZES
,
items
=
TILE_SIZES
,
default
=
'
32
'
,
default
=
'
32
'
,
description
=
"
Square dimentions of tiles for CPU rendering
"
,
description
=
"
Square dimensions of tiles for CPU rendering
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
bi_choice
=
bpy
.
props
.
EnumProperty
(
bi_choice
=
bpy
.
props
.
EnumProperty
(
name
=
"
Target CPU Tile Size
"
,
name
=
"
Target CPU Tile Size
"
,
items
=
TILE_SIZES
,
items
=
TILE_SIZES
,
default
=
'
64
'
,
default
=
'
64
'
,
description
=
"
Square dimentions of tiles
"
,
description
=
"
Square dimensions of tiles
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
gpu_custom
=
bpy
.
props
.
IntProperty
(
gpu_custom
=
bpy
.
props
.
IntProperty
(
name
=
"
Target Size
"
,
name
=
"
Target Size
"
,
default
=
256
,
default
=
256
,
min
=
8
,
# same as blender's own limits
min
=
8
,
# same as blender's own limits
max
=
65536
,
max
=
65536
,
description
=
"
Custom target tile size for GPU rendering
"
,
description
=
"
Custom target tile size for GPU rendering
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
cpu_custom
=
bpy
.
props
.
IntProperty
(
cpu_custom
=
bpy
.
props
.
IntProperty
(
name
=
"
Target Size
"
,
name
=
"
Target Size
"
,
default
=
32
,
default
=
32
,
min
=
8
,
# same as blender's own limits
min
=
8
,
# same as blender's own limits
max
=
65536
,
max
=
65536
,
description
=
"
Custom target tile size for CPU rendering
"
,
description
=
"
Custom target tile size for CPU rendering
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
bi_custom
=
bpy
.
props
.
IntProperty
(
bi_custom
=
bpy
.
props
.
IntProperty
(
name
=
"
Target Size
"
,
name
=
"
Target Size
"
,
default
=
64
,
default
=
64
,
min
=
8
,
# same as blender's own limits
min
=
8
,
# same as blender's own limits
max
=
65536
,
max
=
65536
,
description
=
"
Custom target tile size
"
,
description
=
"
Custom target tile size
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
target_type
=
bpy
.
props
.
EnumProperty
(
target_type
=
bpy
.
props
.
EnumProperty
(
name
=
"
Target tile size
"
,
name
=
"
Target tile size
"
,
items
=
(
items
=
(
(
'
po2
'
,
"
Po2
"
,
"
A choice between powers of 2 (16, 32, 64...)
"
),
(
'
po2
'
,
"
Po2
"
,
"
A choice between powers of 2 (16, 32, 64...)
"
),
(
'
custom
'
,
"
Custom
"
,
"
Choose any number as the tile size target
"
)),
(
'
custom
'
,
"
Custom
"
,
"
Choose any number as the tile size target
"
)),
default
=
'
po2
'
,
default
=
'
po2
'
,
description
=
"
Method of choosing the target tile size
"
,
description
=
"
Method of choosing the target tile size
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
use_optimal
=
bpy
.
props
.
BoolProperty
(
use_optimal
=
bpy
.
props
.
BoolProperty
(
name
=
"
Optimal Tiles
"
,
name
=
"
Optimal Tiles
"
,
default
=
True
,
default
=
True
,
description
=
"
Try to find a similar tile size for best performance, instead of using exact selected one
"
,
description
=
"
Try to find a similar tile size for best performance, instead of using exact selected one
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
is_enabled
=
bpy
.
props
.
BoolProperty
(
is_enabled
=
bpy
.
props
.
BoolProperty
(
name
=
"
Auto Tile Size
"
,
name
=
"
Auto Tile Size
"
,
default
=
True
,
default
=
True
,
description
=
"
Calculate the best tile size based on factors of the render size and the chosen target
"
,
description
=
"
Calculate the best tile size based on factors of the render size and the chosen target
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
use_advanced_ui
=
bpy
.
props
.
BoolProperty
(
use_advanced_ui
=
bpy
.
props
.
BoolProperty
(
name
=
"
Advanced Settings
"
,
name
=
"
Advanced Settings
"
,
default
=
False
,
default
=
False
,
description
=
"
Show extra options for more control over the calculated tile size
"
)
description
=
"
Show extra options for more control over the calculated tile size
"
)
thread_error_correct
=
bpy
.
props
.
BoolProperty
(
thread_error_correct
=
bpy
.
props
.
BoolProperty
(
name
=
"
Fix
"
,
name
=
"
Fix
"
,
default
=
True
,
default
=
True
,
description
=
"
Reduce the tile size so that all your available threads are used
"
,
description
=
"
Reduce the tile size so that all your available threads are used
"
,
update
=
_update_tile_size
)
update
=
_update_tile_size
)
# Internally used props (not for GUI)
# Internally used props (not for GUI)
first_run
=
bpy
.
props
.
BoolProperty
(
default
=
True
,
options
=
{
'
HIDDEN
'
})
first_run
=
bpy
.
props
.
BoolProperty
(
default
=
True
,
options
=
{
'
HIDDEN
'
})
threads_error
=
bpy
.
props
.
BoolProperty
(
options
=
{
'
HIDDEN
'
})
threads_error
=
bpy
.
props
.
BoolProperty
(
options
=
{
'
HIDDEN
'
})
num_tiles
=
bpy
.
props
.
IntVectorProperty
(
default
=
(
0
,
0
),
size
=
2
,
options
=
{
'
HIDDEN
'
})
num_tiles
=
bpy
.
props
.
IntVectorProperty
(
default
=
(
0
,
0
),
size
=
2
,
options
=
{
'
HIDDEN
'
})
prev_choice
=
bpy
.
props
.
StringProperty
(
default
=
''
,
options
=
{
'
HIDDEN
'
})
prev_choice
=
bpy
.
props
.
StringProperty
(
default
=
''
,
options
=
{
'
HIDDEN
'
})
prev_engine
=
bpy
.
props
.
StringProperty
(
default
=
''
,
options
=
{
'
HIDDEN
'
})
prev_engine
=
bpy
.
props
.
StringProperty
(
default
=
''
,
options
=
{
'
HIDDEN
'
})
prev_device
=
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_res
=
bpy
.
props
.
IntVectorProperty
(
default
=
(
0
,
0
),
size
=
2
,
options
=
{
'
HIDDEN
'
})
prev_border
=
bpy
.
props
.
BoolProperty
(
default
=
False
,
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_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_actual_tile_size
=
bpy
.
props
.
IntVectorProperty
(
default
=
(
0
,
0
),
size
=
2
,
options
=
{
'
HIDDEN
'
})
prev_threads
=
bpy
.
props
.
IntProperty
(
default
=
0
,
options
=
{
'
HIDDEN
'
})
prev_threads
=
bpy
.
props
.
IntProperty
(
default
=
0
,
options
=
{
'
HIDDEN
'
})
def
ats_poll
(
context
):
def
ats_poll
(
context
):
scene
=
context
.
scene
scene
=
context
.
scene
if
scene
.
render
.
engine
not
in
SUPPORTED_RENDER_ENGINES
or
not
scene
.
ats_settings
.
is_enabled
:
if
scene
.
render
.
engine
not
in
SUPPORTED_RENDER_ENGINES
or
not
scene
.
ats_settings
.
is_enabled
:
return
False
return
False
return
True
return
True
def
engine_is_gpu
(
engine
,
device
,
userpref
):
def
engine_is_gpu
(
engine
,
device
,
userpref
):
return
engine
==
'
CYCLES
'
and
device
==
'
GPU
'
and
userpref
.
system
.
compute_device_type
!=
'
NONE
'
return
engine
==
'
CYCLES
'
and
device
==
'
GPU
'
and
userpref
.
system
.
compute_device_type
!=
'
NONE
'
def
get_tilesize_prop
(
engine
,
device
,
userpref
):
def
get_tilesize_prop
(
engine
,
device
,
userpref
):
target_type
=
"
_choice
"
if
bpy
.
context
.
scene
.
ats_settings
.
target_type
==
'
po2
'
else
"
_custom
"
target_type
=
"
_choice
"
if
bpy
.
context
.
scene
.
ats_settings
.
target_type
==
'
po2
'
else
"
_custom
"
if
engine_is_gpu
(
engine
,
device
,
userpref
):
if
engine_is_gpu
(
engine
,
device
,
userpref
):
return
(
"
gpu
"
+
target_type
)
return
(
"
gpu
"
+
target_type
)
elif
engine
==
'
CYCLES
'
:
elif
engine
==
'
CYCLES
'
:
return
(
"
cpu
"
+
target_type
)
return
(
"
cpu
"
+
target_type
)
return
(
"
bi
"
+
target_type
)
return
(
"
bi
"
+
target_type
)
@persistent
@persistent
def
on_scene_update
(
scene
):
def
on_scene_update
(
scene
):
context
=
bpy
.
context
context
=
bpy
.
context
if
not
ats_poll
(
context
):
if
not
ats_poll
(
context
):
return
return
userpref
=
context
.
user_preferences
userpref
=
context
.
user_preferences
settings
=
scene
.
ats_settings
settings
=
scene
.
ats_settings
render
=
scene
.
render
render
=
scene
.
render
engine
=
render
.
engine
engine
=
render
.
engine
# scene.cycles might not always exist (Cycles is an addon)...
# scene.cycles might not always exist (Cycles is an addon)...
device
=
scene
.
cycles
.
device
if
engine
==
'
CYCLES
'
else
settings
.
prev_device
device
=
scene
.
cycles
.
device
if
engine
==
'
CYCLES
'
else
settings
.
prev_device
border
=
render
.
use_border
border
=
render
.
use_border
threads
=
get_threads
(
context
,
device
)
threads
=
get_threads
(
context
,
device
)
choice
=
getattr
(
settings
,
get_tilesize_prop
(
engine
,
device
,
userpref
))
choice
=
getattr
(
settings
,
get_tilesize_prop
(
engine
,
device
,
userpref
))
res
=
get_actual_res
(
render
)
res
=
get_actual_res
(
render
)
actual_ts
=
(
render
.
tile_x
,
render
.
tile_y
)
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
)
border_res
=
(
render
.
border_min_x
,
render
.
border_min_y
,
render
.
border_max_x
,
render
.
border_max_y
)
# detect relevant changes in scene
# detect relevant changes in scene
do_change
=
(
engine
!=
settings
.
prev_engine
or
do_change
=
(
engine
!=
settings
.
prev_engine
or
device
!=
settings
.
prev_device
or
device
!=
settings
.
prev_device
or
border
!=
settings
.
prev_border
or
border
!=
settings
.
prev_border
or
threads
!=
settings
.
prev_threads
or
threads
!=
settings
.
prev_threads
or
str
(
choice
)
!=
settings
.
prev_choice
or
str
(
choice
)
!=
settings
.
prev_choice
or
res
!=
settings
.
prev_res
[:]
or
res
!=
settings
.
prev_res
[:]
or
border_res
!=
settings
.
prev_border_res
[:]
or
border_res
!=
settings
.
prev_border_res
[:]
or
actual_ts
!=
settings
.
prev_actual_tile_size
[:])
actual_ts
!=
settings
.
prev_actual_tile_size
[:])
if
do_change
:
if
do_change
:
do_set_tile_size
(
context
)
do_set_tile_size
(
context
)
def
get_actual_res
(
render
):
def
get_actual_res
(
render
):
rend_percent
=
render
.
resolution_percentage
*
0.01
rend_percent
=
render
.
resolution_percentage
*
0.01
# floor is implicitly done by int conversion...
# floor is implicitly done by int conversion...
return
(
int
(
render
.
resolution_x
*
rend_percent
),
int
(
render
.
resolution_y
*
rend_percent
))
return
(
int
(
render
.
resolution_x
*
rend_percent
),
int
(
render
.
resolution_y
*
rend_percent
))
def
get_threads
(
context
,
device
):
def
get_threads
(
context
,
device
):
render
=
context
.
scene
.
render
render
=
context
.
scene
.
render
engine
=
render
.
engine
engine
=
render
.
engine
userpref
=
context
.
user_preferences
userpref
=
context
.
user_preferences
if
engine_is_gpu
(
engine
,
device
,
userpref
):
if
engine_is_gpu
(
engine
,
device
,
userpref
):
gpu_device_str
=
userpref
.
system
.
compute_device
gpu_device_str
=
userpref
.
system
.
compute_device
if
'
MULTI
'
in
gpu_device_str
:
if
'
MULTI
'
in
gpu_device_str
:
threads
=
int
(
gpu_device_str
.
split
(
'
_
'
)[
-
1
])
threads
=
int
(
gpu_device_str
.
split
(
'
_
'
)[
-
1
])
else
:
else
:
threads
=
1
threads
=
1
else
:
else
:
threads
=
render
.
threads
threads
=
render
.
threads
return
threads
return
threads
def
max_tile_size
(
threads
,
xres
,
yres
):
def
max_tile_size
(
threads
,
xres
,
yres
):
'''
Give the largest tile size that will still use all threads
'''
'''
Give the largest tile size that will still use all threads
'''
render_area
=
xres
*
yres
render_area
=
xres
*
yres
tile_area
=
render_area
/
threads
tile_area
=
render_area
/
threads
tile_length
=
sqrt
(
tile_area
)
tile_length
=
sqrt
(
tile_area
)
# lists: num x tiles, num y tiles, squareness, total tiles
# lists: num x tiles, num y tiles, squareness, total tiles
perfect_attempts
=
[]
# attempts with correct number of tiles
perfect_attempts
=
[]
# attempts with correct number of tiles
attempts
=
[]
# all attempts, even if incorrect number of tiles
attempts
=
[]
# all attempts, even if incorrect number of tiles
axes
=
[
xres
,
yres
]
axes
=
[
xres
,
yres
]
funcs
=
[
floor
,
ceil
]
funcs
=
[
floor
,
ceil
]
for
axis
in
axes
:
for
axis
in
axes
:
sec_axis
=
yres
if
axis
==
xres
else
xres
sec_axis
=
yres
if
axis
==
xres
else
xres
for
func
in
funcs
:
for
func
in
funcs
:
primary
=
func
(
axis
/
tile_length
)
primary
=
func
(
axis
/
tile_length
)
if
primary
>
0
:
if
primary
>
0
:
secondary
=
threads
/
primary
secondary
=
threads
/
primary
ts_p
=
axis
/
primary
ts_p
=
axis
/
primary
ts_s
=
sec_axis
/
secondary
ts_s
=
sec_axis
/
secondary
squareness
=
max
(
ts_p
,
ts_s
)
-
min
(
ts_p
,
ts_s
)
squareness
=
max
(
ts_p
,
ts_s
)
-
min
(
ts_p
,
ts_s
)
attempt
=
[
primary
if
axis
==
xres
else
secondary
,
primary
if
axis
!=
xres
else
secondary
,
squareness
,
primary
*
secondary
]
attempt
=
[
primary
if
axis
==
xres
else
secondary
,
primary
if
axis
!=
xres
else
secondary
,
squareness
,
primary
*
secondary
]
if
attempt
not
in
attempts
:
if
attempt
not
in
attempts
:
attempts
.
append
(
attempt
)
attempts
.
append
(
attempt
)
if
secondary
.
is_integer
():
# will only be an integer if there are the right number of tiles
if
secondary
.
is_integer
():
# will only be an integer if there are the right number of tiles
perfect_attempts
.
append
(
attempt
)
perfect_attempts
.
append
(
attempt
)
if
perfect_attempts
:
# prefer to use attempt that has exactly the right number of tiles
if
perfect_attempts
:
# prefer to use attempt that has exactly the right number of tiles
attempts
=
perfect_attempts
attempts
=
perfect_attempts
attempt
=
sorted
(
attempts
,
key
=
lambda
k
:
k
[
2
])[
0
]
# pick set with most square tiles
attempt
=
sorted
(
attempts
,
key
=
lambda
k
:
k
[
2
])[
0
]
# pick set with most square tiles
numtiles_x
=
round
(
attempt
[
0
])
numtiles_x
=
round
(
attempt
[
0
])
numtiles_y
=
round
(
attempt
[
1
])
numtiles_y
=
round
(
attempt
[
1
])
tile_x
=
ceil
(
xres
/
numtiles_x
)
tile_x
=
ceil
(
xres
/
numtiles_x
)
tile_y
=
ceil
(
yres
/
numtiles_y
)
tile_y
=
ceil
(
yres
/
numtiles_y
)
return
(
tile_x
,
tile_y
)
return
(
tile_x
,
tile_y
)
def
do_set_tile_size
(
context
):
def
do_set_tile_size
(
context
):
if
not
ats_poll
(
context
):
if
not
ats_poll
(
context
):
return
False
return
False
scene
=
context
.
scene
scene
=
context
.
scene
userpref
=
context
.
user_preferences
userpref
=
context
.
user_preferences
settings
=
scene
.
ats_settings
settings
=
scene
.
ats_settings
render
=
scene
.
render
render
=
scene
.
render
engine
=
render
.
engine
engine
=
render
.
engine
device
=
scene
.
cycles
.
device
if
engine
==
'
CYCLES
'
else
settings
.
prev_device
device
=
scene
.
cycles
.
device
if
engine
==
'
CYCLES
'
else
settings
.
prev_device
border
=
render
.
use_border
border
=
render
.
use_border
realxres
,
realyres
=
xres
,
yres
=
res
=
get_actual_res
(
scene
.
render
)
realxres
,
realyres
=
xres
,
yres
=
res
=
get_actual_res
(
scene
.
render
)
if
border
:
if
border
:
xres
=
round
(
xres
*
(
render
.
border_max_x
-
render
.
border_min_x
))
xres
=
round
(
xres
*
(
render
.
border_max_x
-
render
.
border_min_x
))
yres
=
round
(
yres
*
(
render
.
border_max_y
-
render
.
border_min_y
))
yres
=
round
(
yres
*
(
render
.
border_max_y
-
render
.
border_min_y
))
choice
=
getattr
(
settings
,
get_tilesize_prop
(
engine
,
device
,
userpref
))
choice
=
getattr
(
settings
,
get_tilesize_prop
(
engine
,
device
,
userpref
))
target
=
int
(
choice
)
target
=
int
(
choice
)
numtiles_x
=
ceil
(
xres
/
target
)
numtiles_x
=
ceil
(
xres
/
target
)
numtiles_y
=
ceil
(
yres
/
target
)
numtiles_y
=
ceil
(
yres
/
target
)
settings
.
num_tiles
=
(
numtiles_x
,
numtiles_y
)
settings
.
num_tiles
=
(
numtiles_x
,
numtiles_y
)
if
settings
.
use_optimal
:
if
settings
.
use_optimal
:
tile_x
=
ceil
(
xres
/
numtiles_x
)
tile_x
=
ceil
(
xres
/
numtiles_x
)
tile_y
=
ceil
(
yres
/
numtiles_y
)
tile_y
=
ceil
(
yres
/
numtiles_y
)
else
:
else
:
tile_x
=
target
tile_x
=
target
tile_y
=
target
tile_y
=
target
# Print tile size (for debug purposes)
# Print tile size (for debug purposes)
# print("Tile size: %dx%d (%dx%d tiles)" % (tile_x, tile_y, ceil(xres / tile_x), ceil(yres / tile_y)))
# print("Tile size: %dx%d (%dx%d tiles)" % (tile_x, tile_y, ceil(xres / tile_x), ceil(yres / tile_y)))
# Detect if there are fewer tiles than available threads
# Detect if there are fewer tiles than available threads
threads
=
get_threads
(
context
,
device
)
threads
=
get_threads
(
context
,
device
)
if
((
numtiles_x
*
numtiles_y
)
<
threads
):
if
((
numtiles_x
*
numtiles_y
)
<
threads
):
settings
.
threads_error
=
True
settings
.
threads_error
=
True
if
settings
.
thread_error_correct
:
if
settings
.
thread_error_correct
:
tile_x
,
tile_y
=
max_tile_size
(
threads
,
xres
,
yres
)
tile_x
,
tile_y
=
max_tile_size
(
threads
,
xres
,
yres
)
settings
.
num_tiles
=
(
ceil
(
xres
/
tile_x
),
ceil
(
yres
/
tile_y
))
settings
.
num_tiles
=
(
ceil
(
xres
/
tile_x
),
ceil
(
yres
/
tile_y
))
else
:
else
:
settings
.
threads_error
=
False
settings
.
threads_error
=
False
# Make sure tile sizes are within the internal limit
# Make sure tile sizes are within the internal limit
tile_x
=
max
(
8
,
tile_x
)
tile_x
=
max
(
8
,
tile_x
)
tile_y
=
max
(
8
,
tile_y
)
tile_y
=
max
(
8
,
tile_y
)
tile_x
=
min
(
65536
,
tile_x
)
tile_x
=
min
(
65536
,
tile_x
)
tile_y
=
min
(
65536
,
tile_y
)
tile_y
=
min
(
65536
,
tile_y
)
render
.
tile_x
=
tile_x
render
.
tile_x
=
tile_x
render
.
tile_y
=
tile_y
render
.
tile_y
=
tile_y
settings
.
prev_engine
=
engine
settings
.
prev_engine
=
engine
settings
.
prev_device
=
device
settings
.
prev_device
=
device
settings
.
prev_border
=
border
settings
.
prev_border
=
border
settings
.
prev_threads
=
threads
settings
.
prev_threads
=
threads
settings
.
prev_choice
=
str
(
choice
)
settings
.
prev_choice
=
str
(
choice
)
settings
.
prev_res
=
res
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_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
.
prev_actual_tile_size
=
(
tile_x
,
tile_y
)
settings
.
first_run
=
False
settings
.
first_run
=
False
return
True
return
True
class
SetTileSize
(
bpy
.
types
.
Operator
):
class
SetTileSize
(
bpy
.
types
.
Operator
):
"""
The first render may not obey the tile-size set here
"""
"""
The first render may not obey the tile-size set here
"""
bl_idname
=
"
render.autotilesize_set
"
bl_idname
=
"
render.autotilesize_set
"
bl_label
=
"
Set
"
bl_label
=
"
Set
"
@classmethod
@classmethod
def
poll
(
clss
,
context
):
def
poll
(
clss
,
context
):
return
ats_poll
(
context
)
return
ats_poll
(
context
)
def
execute
(
self
,
context
):
def
execute
(
self
,
context
):
if
do_set_tile_size
(
context
):
if
do_set_tile_size
(
context
):
return
{
'
FINISHED
'
}
return
{
'
FINISHED
'
}
return
{
'
CANCELLED
'
}
return
{
'
CANCELLED
'
}
# ##### INTERFACE #####
# ##### INTERFACE #####
def
ui_layout
(
engine
,
layout
,
context
):
def
ui_layout
(
engine
,
layout
,
context
):
scene
=
context
.
scene
scene
=
context
.
scene
userpref
=
context
.
user_preferences
userpref
=
context
.
user_preferences
settings
=
scene
.
ats_settings
settings
=
scene
.
ats_settings
render
=
scene
.
render
render
=
scene
.
render
engine
=
render
.
engine
engine
=
render
.
engine
device
=
scene
.
cycles
.
device
if
engine
==
'
CYCLES
'
else
settings
.
prev_device
device
=
scene
.
cycles
.
device
if
engine
==
'
CYCLES
'
else
settings
.
prev_device
col
=
layout
.
column
(
align
=
True
)
col
=
layout
.
column
(
align
=
True
)
sub
=
col
.
column
(
align
=
True
)
sub
=
col
.
column
(
align
=
True
)
row
=
sub
.
row
(
align
=
True
)
row
=
sub
.
row
(
align
=
True
)
row
.
prop
(
settings
,
"
is_enabled
"
,
toggle
=
True
)
row
.
prop
(
settings
,
"
is_enabled
"
,
toggle
=
True
)
row
.
prop
(
settings
,
"
use_advanced_ui
"
,
toggle
=
True
,
text
=
""
,
icon
=
'
PREFERENCES
'
)
row
.
prop
(
settings
,
"
use_advanced_ui
"
,
toggle
=
True
,
text
=
""
,
icon
=
'
PREFERENCES
'
)
sub
=
col
.
column
(
align
=
False
)
sub
=
col
.
column
(
align
=
False
)
sub
.
enabled
=
settings
.
is_enabled
sub
.
enabled
=
settings
.
is_enabled
if
settings
.
use_advanced_ui
:
if
settings
.
use_advanced_ui
:
row
=
sub
.
row
(
align
=
True
)
row
=
sub
.
row
(
align
=
True
)
row
.
label
(
"
Target tile size:
"
)
row
.
label
(
"
Target tile size:
"
)
row
.
separator
()
row
.
separator
()
row
.
prop
(
settings
,
"
target_type
"
,
expand
=
True
)
row
.
prop
(
settings
,
"
target_type
"
,
expand
=
True
)
row
=
sub
.
row
(
align
=
True
)
row
=
sub
.
row
(
align
=
True
)
row
.
prop
(
settings
,
get_tilesize_prop
(
engine
,
device
,
userpref
),
expand
=
True
)
row
.
prop
(
settings
,
get_tilesize_prop
(
engine
,
device
,
userpref
),
expand
=
True
)
sub
.
prop
(
settings
,
"
use_optimal
"
,
text
=
"
Calculate Optimal Size
"
)
sub
.
prop
(
settings
,
"
use_optimal
"
,
text
=
"
Calculate Optimal Size
"
)
sub
.
label
(
"
Number of tiles: %s x %s (Total: %s)
"
%
(
settings
.
num_tiles
[
0
],
settings
.
num_tiles
[
1
],
settings
.
num_tiles
[
0
]
*
settings
.
num_tiles
[
1
]))
sub
.
label
(
"
Number of tiles: %s x %s (Total: %s)
"
%
(
settings
.
num_tiles
[
0
],
settings
.
num_tiles
[
1
],
settings
.
num_tiles
[
0
]
*
settings
.
num_tiles
[
1
]))
if
settings
.
first_run
:
if
settings
.
first_run
:
sub
=
layout
.
column
(
align
=
True
)
sub
=
layout
.
column
(
align
=
True
)
sub
.
operator
(
"
render.autotilesize_set
"
,
text
=
"
First-render fix
"
,
icon
=
'
ERROR
'
)
sub
.
operator
(
"
render.autotilesize_set
"
,
text
=
"
First-render fix
"
,
icon
=
'
ERROR
'
)
elif
settings
.
prev_device
!=
device
:
elif
settings
.
prev_device
!=
device
:
sub
=
layout
.
column
(
align
=
True
)
sub
=
layout
.
column
(
align
=
True
)
sub
.
operator
(
"
render.autotilesize_set
"
,
text
=
"
Device changed - fix
"
,
icon
=
'
ERROR
'
)
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
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
=
"
Warning: Tile size is not very square
"
,
icon
=
'
ERROR
'
)
sub
.
label
(
text
=
"
Try a slightly different resolution
"
)
sub
.
label
(
text
=
"
Try a slightly different resolution
"
)
if
settings
.
threads_error
:
if
settings
.
threads_error
:
row
=
sub
.
row
(
align
=
True
)
row
=
sub
.
row
(
align
=
True
)
row
.
alignment
=
'
CENTER
'
row
.
alignment
=
'
CENTER
'
row
.
label
(
text
=
"
Warning: Fewer tiles than threads
"
,
icon
=
'
ERROR
'
)
row
.
label
(
text
=
"
Warning: Fewer tiles than threads
"
,
icon
=
'
ERROR
'
)
row
.
prop
(
settings
,
'
thread_error_correct
'
)
row
.
prop
(
settings
,
'
thread_error_correct
'
)
def
menu_func_cycles
(
self
,
context
):
def
menu_func_cycles
(
self
,
context
):
ui_layout
(
'
CYCLES
'
,
self
.
layout
,
context
)
ui_layout
(
'
CYCLES
'
,
self
.
layout
,
context
)
def
menu_func_bi
(
self
,
context
):
def
menu_func_bi
(
self
,
context
):
ui_layout
(
'
BLENDER_RENDER
'
,
self
.
layout
,
context
)
ui_layout
(
'
BLENDER_RENDER
'
,
self
.
layout
,
context
)
# ##### REGISTRATION #####
# ##### REGISTRATION #####
def
register
():
def
register
():
bpy
.
utils
.
register_module
(
__name__
)
bpy
.
utils
.
register_module
(
__name__
)
bpy
.
types
.
Scene
.
ats_settings
=
bpy
.
props
.
PointerProperty
(
type
=
AutoTileSizeSettings
)
bpy
.
types
.
Scene
.
ats_settings
=
bpy
.
props
.
PointerProperty
(
type
=
AutoTileSizeSettings
)
# Note, the Cycles addon must be registered first, otherwise this panel doesn't exist - better be safe here!
# Note, the Cycles addon must be registered first, otherwise this panel doesn't exist - better be safe here!
cycles_panel
=
getattr
(
bpy
.
types
,
"
CyclesRender_PT_performance
"
,
None
)
cycles_panel
=
getattr
(
bpy
.
types
,
"
CyclesRender_PT_performance
"
,
None
)
if
cycles_panel
is
not
None
:
if
cycles_panel
is
not
None
:
cycles_panel
.
append
(
menu_func_cycles
)
cycles_panel
.
append
(
menu_func_cycles
)
bpy
.
types
.
RENDER_PT_performance
.
append
(
menu_func_bi
)
bpy
.
types
.
RENDER_PT_performance
.
append
(
menu_func_bi
)
bpy
.
app
.
handlers
.
scene_update_post
.
append
(
on_scene_update
)
bpy
.
app
.
handlers
.
scene_update_post
.
append
(
on_scene_update
)
def
unregister
():
def
unregister
():
bpy
.
app
.
handlers
.
scene_update_post
.
remove
(
on_scene_update
)
bpy
.
app
.
handlers
.
scene_update_post
.
remove
(
on_scene_update
)
bpy
.
types
.
RENDER_PT_performance
.
remove
(
menu_func_bi
)
bpy
.
types
.
RENDER_PT_performance
.
remove
(
menu_func_bi
)
cycles_panel
=
getattr
(
bpy
.
types
,
"
CyclesRender_PT_performance
"
,
None
)
cycles_panel
=
getattr
(
bpy
.
types
,
"
CyclesRender_PT_performance
"
,
None
)
if
cycles_panel
is
not
None
:
if
cycles_panel
is
not
None
:
cycles_panel
.
remove
(
menu_func_cycles
)
cycles_panel
.
remove
(
menu_func_cycles
)
del
bpy
.
types
.
Scene
.
ats_settings
del
bpy
.
types
.
Scene
.
ats_settings
bpy
.
utils
.
unregister_module
(
__name__
)
bpy
.
utils
.
unregister_module
(
__name__
)
if
__name__
==
"
__main__
"
:
if
__name__
==
"
__main__
"
:
register
()
register
()
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment