Faster build times

This commit is contained in:
Lubos Lenco 2017-01-18 14:52:51 +01:00
parent 14d4ad1b96
commit ccf195cdbd
6 changed files with 115 additions and 51 deletions

View file

@ -1,22 +1,29 @@
import armutils
import shutil
import os
import bpy
assets = []
khafile_defs = []
khafile_defs_last = []
embedded_data = []
shaders = []
shaders_last = []
shader_datas = []
def reset():
global assets
global khafile_defs
global khafile_defs_last
global embedded_data
global shaders
global shaders_last
global shader_datas
assets = []
khafile_defs_last = khafile_defs
khafile_defs = []
embedded_data = []
shaders_last = shaders
shaders = []
shader_datas = []
@ -27,9 +34,14 @@ def add(file):
def add_khafile_def(d):
global khafile_defs
global khafile_defs_last
if d not in khafile_defs:
khafile_defs.append(d)
wrd = bpy.data.worlds['Arm']
if not wrd.arm_recompile_trigger and d not in khafile_defs_last:
wrd.arm_recompile_trigger = True
def add_embedded_data(file):
global embedded_data
if file not in embedded_data:
@ -37,9 +49,14 @@ def add_embedded_data(file):
def add_shader(file):
global shaders
global shaders_last
if file not in shaders:
shaders.append(file)
wrd = bpy.data.worlds['Arm']
if not wrd.arm_recompile_trigger and file not in shaders_last:
wrd.arm_recompile_trigger = True
def add_shader_data(file):
global shader_datas
if file not in shader_datas:

View file

@ -57,14 +57,14 @@ def on_scene_update_post(context):
break
# Auto patch on every operator change
wrd = bpy.data.worlds['Arm']
if state.krom_running and \
bpy.data.worlds['Arm'].arm_play_live_patch and \
bpy.data.worlds['Arm'].arm_play_auto_build and \
wrd.arm_play_live_patch and \
wrd.arm_play_auto_build and \
operators_changed:
# Otherwise rebuild scene
if bridge.send_operator(last_operator) == False:
make.patch_project()
make.compile_project(target_name="krom", patch=True)
make.play_project(in_viewport=True)
# Use frame rate for update frequency for now
if time.time() - last_time >= (1 / bpy.context.scene.render.fps):
@ -131,7 +131,10 @@ def on_scene_update_post(context):
obj.data.mesh_cached = False
if obj.active_material != None and obj.active_material.is_updated:
obj.active_material.is_cached = False
if obj.active_material.lock_cache == True: # is_cached was set to true
obj.active_material.lock_cache = False
else:
obj.active_material.is_cached = False
@persistent
def on_load_post(context):

View file

@ -1,4 +1,6 @@
import os
import glob
import time
import shutil
import bpy
import json
@ -22,6 +24,7 @@ import lib.make_variants
import lib.server
exporter = ArmoryExporter()
scripts_mtime = 0 # Monitor source changes
def compile_shader(raw_shaders_path, shader_name, defs):
os.chdir(raw_shaders_path + './' + shader_name)
@ -161,7 +164,7 @@ def compile_project(target_name=None, is_publish=False, watch=False, patch=False
cmd.append('opengl2')
if kha_target_name == 'krom':
if state.in_viewport or patch:
if state.in_viewport:
if armutils.glsl_version() >= 330:
cmd.append('--shaderversion')
cmd.append('330')
@ -178,7 +181,7 @@ def compile_project(target_name=None, is_publish=False, watch=False, patch=False
for s in bpy.data.texts[cmd_text].as_string().split(' '):
cmd.append(s)
if state.krom_running:
if patch:
if state.compileproc == None: # Already compiling
# Patch running game, stay silent, disable krafix and haxe
# cmd.append('--silent')
@ -189,22 +192,22 @@ def compile_project(target_name=None, is_publish=False, watch=False, patch=False
cmd.append('""')
# Khamake throws error when krafix is not found, hide for now
state.compileproc = subprocess.Popen(cmd, stderr=subprocess.PIPE)
threading.Timer(0.1, watch_patch).start()
if state.playproc == None:
if state.in_viewport:
mode = 'play_viewport'
else:
mode = 'play'
else:
mode = 'build'
threading.Timer(0.1, watch_patch, [mode]).start()
return state.compileproc
elif watch == True:
elif watch:
state.compileproc = subprocess.Popen(cmd)
threading.Timer(0.1, watch_compile, ['build']).start()
return state.compileproc
else:
return subprocess.Popen(cmd)
# For live patching
def patch_project():
sdk_path = armutils.get_sdk_path()
fp = armutils.get_fp()
os.chdir(fp)
export_data(fp, sdk_path, is_play=True)
def build_project(is_play=False, is_publish=False, in_viewport=False, target=None):
wrd = bpy.data.worlds['Arm']
@ -303,17 +306,20 @@ def watch_compile(mode):
state.compileproc = None
state.compileproc_finished = True
if result == 0:
bpy.data.worlds['Arm'].arm_recompile = False
state.compileproc_success = True
on_compiled(mode)
else:
state.compileproc_success = False
log.print_info('Build failed, check console')
def watch_patch():
def watch_patch(mode):
state.compileproc.wait()
log.print_progress(100)
# result = state.compileproc.poll()
state.compileproc = None
state.compileproc_finished = True
on_compiled(mode)
def runtime_to_target(in_viewport):
wrd = bpy.data.worlds['Arm']
@ -324,11 +330,20 @@ def runtime_to_target(in_viewport):
else:
return 'html5'
def play_project(self, in_viewport):
def get_khajs_path(in_viewport, target):
if in_viewport:
return 'build/krom/krom.js'
elif target == 'krom':
return 'build/window/krom/krom.js'
else: # browser, electron
return 'build/html5/kha.js'
def play_project(in_viewport):
global scripts_mtime
wrd = bpy.data.worlds['Arm']
# Store area
if armutils.with_krom() and in_viewport and bpy.context.area.type == 'VIEW_3D':
if armutils.with_krom() and in_viewport and bpy.context.area != None and bpy.context.area.type == 'VIEW_3D':
state.play_area = bpy.context.area
state.target = runtime_to_target(in_viewport)
@ -337,21 +352,51 @@ def play_project(self, in_viewport):
build_project(is_play=True, in_viewport=in_viewport, target=state.target)
state.in_viewport = in_viewport
# Compile
mode = 'play'
if state.target == 'native':
state.compileproc = compile_project(target_name='--run')
elif state.target == 'krom':
if in_viewport:
mode = 'play_viewport'
state.compileproc = compile_project(target_name='krom')
else: # Electron, Browser
w, h = armutils.get_render_resolution()
write_data.write_electronjs(w, h)
write_data.write_indexhtml(w, h)
state.compileproc = compile_project(target_name='html5')
khajs_path = get_khajs_path(in_viewport, state.target)
if wrd.arm_recompile or \
wrd.arm_recompile_trigger or \
not wrd.arm_cache_compiler or \
not wrd.arm_cache_shaders or \
not os.path.isfile(khajs_path) or \
state.last_target != state.target:
wrd.arm_recompile = True
threading.Timer(0.1, watch_compile, [mode]).start()
wrd.arm_recompile_trigger = False
state.last_target = state.target
# Trait sources modified
script_path = armutils.get_fp() + '/Sources/' + wrd.arm_project_package
if os.path.isdir(script_path):
for fn in glob.iglob(os.path.join(script_path, '**', '*.hx'), recursive=True):
mtime = os.path.getmtime(fn)
if scripts_mtime < mtime:
scripts_mtime = mtime
wrd.arm_recompile = True
# New compile requred - traits or materials changed
if wrd.arm_recompile:
# Unable to live-patch, stop player
if state.krom_running:
bpy.ops.arm.space_stop()
# play_project(in_viewport=True) # Restart
return
mode = 'play'
if state.target == 'native':
state.compileproc = compile_project(target_name='--run')
elif state.target == 'krom':
if in_viewport:
mode = 'play_viewport'
state.compileproc = compile_project(target_name='krom')
else: # Electron, Browser
w, h = armutils.get_render_resolution()
write_data.write_electronjs(w, h)
write_data.write_indexhtml(w, h)
state.compileproc = compile_project(target_name='html5')
threading.Timer(0.1, watch_compile, [mode]).start()
else: # kha.js up to date
compile_project(target_name=state.target, patch=True)
def on_compiled(mode): # build, play, play_viewport, publish
log.clear()
@ -433,21 +478,10 @@ def clean_project():
os.chdir(armutils.get_fp())
wrd = bpy.data.worlds['Arm']
# Preserve envmaps
# if wrd.arm_cache_envmaps:
# envmaps_path = 'build/compiled/Assets/envmaps'
# if os.path.isdir(envmaps_path):
# shutil.move(envmaps_path, '.')
# Remove build and compiled data
if os.path.isdir('build'):
shutil.rmtree('build')
# Move envmaps back
# if wrd.arm_cache_envmaps and os.path.isdir('envmaps'):
# os.makedirs('build/compiled/Assets')
# shutil.move('envmaps', 'build/compiled/Assets')
# Remove compiled nodes
nodes_path = 'Sources/' + wrd.arm_project_package.replace('.', '/') + '/node/'
if os.path.isdir(nodes_path):

View file

@ -1,5 +1,6 @@
target = 'krom'
last_target = 'krom'
in_viewport = False
playproc = None
compileproc = None

View file

@ -32,9 +32,17 @@ def invalidate_mesh_cache(self, context):
return
context.object.data.mesh_cached = False
def update_mat_cache(self, context):
if self.is_cached == True:
self.lock_cache = True
else:
bpy.data.worlds['Arm'].arm_recompile_trigger = True
arm_ver = '17.01.1'
def init_properties():
global arm_ver
bpy.types.World.arm_recompile = bpy.props.BoolProperty(name="Recompile", description="Recompile sources on next play", default=True)
bpy.types.World.arm_recompile_trigger = bpy.props.BoolProperty(name="Recompile Trigger", description="Force upcoming recomilation", default=False)
bpy.types.World.arm_progress = bpy.props.FloatProperty(name="Progress", description="Current build progress", default=100.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, subtype='PERCENTAGE', get=log.get_progress)
bpy.types.World.arm_version = StringProperty(name="Version", description="Armory SDK version", default=arm_ver)
target_prop = EnumProperty(
@ -85,6 +93,7 @@ def init_properties():
bpy.types.World.arm_lod_gen_levels = IntProperty(name="Levels", description="Number of levels to generate", default=3, min=1)
bpy.types.World.arm_lod_gen_ratio = FloatProperty(name="Decimate Ratio", description="Decimate ratio", default=0.8)
bpy.types.World.arm_cache_shaders = BoolProperty(name="Cache Shaders", description="Do not rebuild existing shaders", default=True, update=assets.invalidate_shader_cache)
bpy.types.World.arm_cache_compiler = BoolProperty(name="Cache Compiler", description="Only recompile sources when required", default=True)
bpy.types.World.arm_gpu_processing = BoolProperty(name="GPU Processing", description="Utilize GPU for asset pre-processing at build time", default=True)
bpy.types.World.arm_play_live_patch = BoolProperty(name="Live Patching", description="Sync running player data to Blender", default=True)
bpy.types.World.arm_play_auto_build = BoolProperty(name="Auto Build", description="Rebuild scene on operator changes", default=True)
@ -336,7 +345,8 @@ def init_properties():
bpy.types.World.voxelgi = bpy.props.BoolProperty(name="VGI", description="Voxel-based Global Illumination", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.voxelgi_dimensions = bpy.props.FloatVectorProperty(name="Dimensions", description="3D texture size", size=3, default=[128, 128, 128], update=assets.invalidate_shader_cache)
# For material
bpy.types.Material.is_cached = bpy.props.BoolProperty(name="Material Cached", description="No need to reexport material data", default=False)
bpy.types.Material.is_cached = bpy.props.BoolProperty(name="Material Cached", description="No need to reexport material data", default=False, update=update_mat_cache)
bpy.types.Material.lock_cache = bpy.props.BoolProperty(name="Lock Material Cache", description="Prevent is_cached from updating", default=False)
bpy.types.Material.cast_shadow = bpy.props.BoolProperty(name="Cast Shadow", default=True)
bpy.types.Material.receive_shadow = bpy.props.BoolProperty(name="Receive Shadow", default=True)
bpy.types.Material.override_shader = bpy.props.BoolProperty(name="Override Shader", default=False)

View file

@ -382,6 +382,7 @@ class ArmoryPlayerPanel(bpy.types.Panel):
layout.operator("arm.render", icon="RENDER_STILL")
layout.prop(wrd, 'arm_cache_shaders')
layout.prop(wrd, 'arm_cache_compiler')
layout.prop(wrd, 'arm_gpu_processing')
layout.prop(wrd, 'arm_minimize')
layout.prop(wrd, 'arm_optimize_mesh')
@ -444,7 +445,7 @@ class ArmoryPlayButton(bpy.types.Operator):
nodes_renderpath.check_default()
assets.invalidate_enabled = False
make.play_project(self, False)
make.play_project(False)
assets.invalidate_enabled = True
return{'FINISHED'}
@ -482,10 +483,9 @@ class ArmoryPlayInViewportButton(bpy.types.Operator):
if space.viewport_shade == 'RENDERED':
space.viewport_shade = 'SOLID'
break
make.play_project(self, True)
make.play_project(True)
else:
make.patch_project()
make.compile_project()
make.play_project(True)
assets.invalidate_enabled = True
return{'FINISHED'}
@ -527,8 +527,7 @@ class ArmoryPatchButton(bpy.types.Operator):
def execute(self, context):
assets.invalidate_enabled = False
make.patch_project()
make.compile_project()
make.play_project(True)
assets.invalidate_enabled = True
return{'FINISHED'}