diff options
Diffstat (limited to 'release/scripts/io/netrender')
-rw-r--r-- | release/scripts/io/netrender/__init__.py | 42 | ||||
-rw-r--r-- | release/scripts/io/netrender/client.py | 29 | ||||
-rw-r--r-- | release/scripts/io/netrender/master.py | 21 | ||||
-rw-r--r-- | release/scripts/io/netrender/master_html.py | 7 | ||||
-rw-r--r-- | release/scripts/io/netrender/operators.py | 93 | ||||
-rw-r--r--[-rwxr-xr-x] | release/scripts/io/netrender/repath.py | 25 | ||||
-rw-r--r-- | release/scripts/io/netrender/slave.py | 43 | ||||
-rw-r--r-- | release/scripts/io/netrender/ui.py | 344 | ||||
-rw-r--r-- | release/scripts/io/netrender/utils.py | 17 |
9 files changed, 330 insertions, 291 deletions
diff --git a/release/scripts/io/netrender/__init__.py b/release/scripts/io/netrender/__init__.py index f5f104d6d92..5a705e95aa8 100644 --- a/release/scripts/io/netrender/__init__.py +++ b/release/scripts/io/netrender/__init__.py @@ -18,16 +18,31 @@ # This directory is a Python package. -from netrender import model -from netrender import operators -from netrender import client -from netrender import slave -from netrender import master -from netrender import master_html -from netrender import utils -from netrender import balancing -from netrender import ui -from netrender import repath +# To support reload properly, try to access a package var, if it's there, reload everything +try: + init_data + + reload(model) + reload(operators) + reload(client) + reload(slave) + reload(master) + reload(master_html) + reload(utils) + reload(balancing) + reload(ui) + reload(repath) +except: + from netrender import model + from netrender import operators + from netrender import client + from netrender import slave + from netrender import master + from netrender import master_html + from netrender import utils + from netrender import balancing + from netrender import ui + from netrender import repath jobs = [] slaves = [] @@ -38,11 +53,10 @@ init_data = True init_address = True def register(): - pass # TODO + ui.addProperties() + def unregister(): import bpy - bpy.types.unregister(ui.NetRenderJob) - bpy.types.unregister(ui.NetRenderSettings) - bpy.types.unregister(ui.NetRenderSlave) + bpy.types.Scene.RemoveProperty("network_render") diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py index 9f6d1a7639e..6f0f6460ae1 100644 --- a/release/scripts/io/netrender/client.py +++ b/release/scripts/io/netrender/client.py @@ -41,7 +41,7 @@ def addFluidFiles(job, path): job.addFile(path + fluid_file, current_frame, current_frame) def addPointCache(job, ob, point_cache, default_path): - if not point_cache.disk_cache: + if not point_cache.use_disk_cache: return @@ -49,7 +49,7 @@ def addPointCache(job, ob, point_cache, default_path): if name == "": name = "".join(["%02X" % ord(c) for c in ob.name]) - cache_path = bpy.utils.expandpath(point_cache.filepath) if point_cache.external else default_path + cache_path = bpy.path.abspath(point_cache.filepath) if point_cache.use_external else default_path index = "%02i" % point_cache.index @@ -113,7 +113,7 @@ def clientSendJob(conn, scene, anim = False): # LIBRARIES ########################### for lib in bpy.data.libraries: - file_path = bpy.utils.expandpath(lib.filepath) + file_path = bpy.path.abspath(lib.filepath) if os.path.exists(file_path): job.addFile(file_path) @@ -122,7 +122,7 @@ def clientSendJob(conn, scene, anim = False): ########################### for image in bpy.data.images: if image.source == "FILE" and not image.packed_file: - file_path = bpy.utils.expandpath(image.filepath) + file_path = bpy.path.abspath(image.filepath) if os.path.exists(file_path): job.addFile(file_path) @@ -139,17 +139,17 @@ def clientSendJob(conn, scene, anim = False): for object in bpy.data.objects: for modifier in object.modifiers: if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN": - addFluidFiles(job, bpy.utils.expandpath(modifier.settings.path)) + addFluidFiles(job, bpy.path.abspath(modifier.settings.path)) elif modifier.type == "CLOTH": addPointCache(job, object, modifier.point_cache, default_path) elif modifier.type == "SOFT_BODY": addPointCache(job, object, modifier.point_cache, default_path) elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN": addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path) - if modifier.domain_settings.highres: + if modifier.domain_settings.use_high_resolution: addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path) - elif modifier.type == "MULTIRES" and modifier.external: - file_path = bpy.utils.expandpath(modifier.filepath) + elif modifier.type == "MULTIRES" and modifier.is_external: + file_path = bpy.path.abspath(modifier.filepath) job.addFile(file_path) # particles modifier are stupid and don't contain data @@ -171,6 +171,7 @@ def clientSendJob(conn, scene, anim = False): # try to send path first conn.request("POST", "/job", repr(job.serialize())) response = conn.getresponse() + response.read() job_id = response.getheader("job-id") @@ -181,6 +182,7 @@ def clientSendJob(conn, scene, anim = False): conn.request("PUT", fileURL(job_id, rfile.index), f) f.close() response = conn.getresponse() + response.read() # server will reply with ACCEPTED until all files are found @@ -189,7 +191,6 @@ def clientSendJob(conn, scene, anim = False): def requestResult(conn, job_id, frame): conn.request("GET", renderURL(job_id, frame)) -@rnaType class NetworkRenderEngine(bpy.types.RenderEngine): bl_idname = 'NET_RENDER' bl_label = "Network Render" @@ -209,7 +210,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): address = "" if netsettings.server_address == "[default]" else netsettings.server_address - master.runMaster((address, netsettings.server_port), netsettings.master_broadcast, netsettings.master_clear, netsettings.path, self.update_stats, self.test_break) + master.runMaster((address, netsettings.server_port), netsettings.master_broadcast, netsettings.use_master_clear, netsettings.path, self.update_stats, self.test_break) def render_slave(self, scene): @@ -237,6 +238,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): requestResult(conn, job_id, scene.frame_current) response = conn.getresponse() + response.read() if response.status == http.client.NO_CONTENT: new_job = True @@ -245,16 +247,19 @@ class NetworkRenderEngine(bpy.types.RenderEngine): requestResult(conn, job_id, scene.frame_current) response = conn.getresponse() + response.read() while response.status == http.client.ACCEPTED and not self.test_break(): time.sleep(1) requestResult(conn, job_id, scene.frame_current) response = conn.getresponse() + response.read() # cancel new jobs (animate on network) on break if self.test_break() and new_job: conn.request("POST", cancelURL(job_id)) response = conn.getresponse() + response.read() print( response.status, response.reason ) netsettings.job_id = 0 @@ -266,7 +271,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): x= int(r.resolution_x*r.resolution_percentage*0.01) y= int(r.resolution_y*r.resolution_percentage*0.01) - f = open(netsettings.path + "output.exr", "wb") + f = open(os.path.join(netsettings.path, "output.exr"), "wb") buf = response.read(1024) while buf: @@ -276,7 +281,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): f.close() result = self.begin_result(0, 0, x, y) - result.load_from_file(netsettings.path + "output.exr") + result.load_from_file(os.path.join(netsettings.path, "output.exr")) self.end_result(result) conn.close() diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py index f227f61a536..6deb925420b 100644 --- a/release/scripts/io/netrender/master.py +++ b/release/scripts/io/netrender/master.py @@ -89,7 +89,7 @@ class MRenderJob(netrender.model.RenderJob): def save(self): if self.save_path: - f = open(self.save_path + "job.txt", "w") + f = open(os.path.join(self.save_path, "job.txt"), "w") f.write(repr(self.serialize())) f.close() @@ -134,8 +134,8 @@ class MRenderJob(netrender.model.RenderJob): self.status = JOB_QUEUED def addLog(self, frames): - log_name = "_".join(("%04d" % f for f in frames)) + ".log" - log_path = self.save_path + log_name + log_name = "_".join(("%06d" % f for f in frames)) + ".log" + log_path = os.path.join(self.save_path, log_name) for number in frames: frame = self[number] @@ -260,7 +260,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): elif frame.status == DONE: self.server.stats("", "Sending result to client") - filename = job.save_path + "%04d" % frame_number + ".exr" + filename = os.path.join(job.save_path, "%06d.exr" % frame_number) f = open(filename, 'rb') self.send_head(content = "image/x-exr") @@ -294,7 +294,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if frame.status in (QUEUED, DISPATCHED): self.send_head(http.client.ACCEPTED) elif frame.status == DONE: - filename = job.save_path + "%04d" % frame_number + ".exr" + filename = os.path.join(job.save_path, "%06d.exr" % frame_number) thumbname = thumbnail(filename) @@ -716,7 +716,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if file_index > 0: file_path = prefixPath(job.save_path, render_file.filepath, main_path) else: - file_path = job.save_path + main_name + file_path = os.path.join(job.save_path, main_name) buf = self.rfile.read(length) @@ -772,7 +772,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if job_result == DONE: length = int(self.headers['content-length']) buf = self.rfile.read(length) - f = open(job.save_path + "%04d" % job_frame + ".exr", 'wb') + f = open(os.path.join(job.save_path, "%06d.exr" % job_frame), 'wb') f.write(buf) f.close() @@ -822,13 +822,12 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if job.type == netrender.model.JOB_BLENDER: length = int(self.headers['content-length']) buf = self.rfile.read(length) - f = open(job.save_path + "%04d" % job_frame + ".jpg", 'wb') + f = open(os.path.join(job.save_path, "%06d.jpg" % job_frame), 'wb') f.write(buf) f.close() del buf - self.send_head() else: # frame not found self.send_head(http.client.NO_CONTENT) else: # job not found @@ -880,7 +879,7 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer): self.job_id = 0 if subdir: - self.path = path + "master_" + str(os.getpid()) + os.sep + self.path = os.path.join(path, "master_" + str(os.getpid())) else: self.path = path @@ -1007,7 +1006,7 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer): self.jobs_map[job.id] = job # create job directory - job.save_path = self.path + "job_" + job.id + os.sep + job.save_path = os.path.join(self.path, "job_" + job.id) if not os.path.exists(job.save_path): os.mkdir(job.save_path) diff --git a/release/scripts/io/netrender/master_html.py b/release/scripts/io/netrender/master_html.py index c3695cd4f0f..74155f6bd66 100644 --- a/release/scripts/io/netrender/master_html.py +++ b/release/scripts/io/netrender/master_html.py @@ -27,9 +27,10 @@ def get(handler): def output(text): handler.wfile.write(bytes(text, encoding='utf8')) - def head(title): + def head(title, refresh = False): output("<html><head>") - output("<meta http-equiv='refresh' content=5>") + if refresh: + output("<meta http-equiv='refresh' content=5>") output("<script src='/html/netrender.js' type='text/javascript'></script>") # output("<script src='/html/json2.js' type='text/javascript'></script>") output("<title>") @@ -104,7 +105,7 @@ def get(handler): f.close() elif handler.path == "/html" or handler.path == "/": handler.send_head(content = "text/html") - head("NetRender") + head("NetRender", refresh = True) output("<h2>Jobs</h2>") diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py index 858ec800dbc..252b1146b67 100644 --- a/release/scripts/io/netrender/operators.py +++ b/release/scripts/io/netrender/operators.py @@ -26,13 +26,13 @@ from netrender.utils import * import netrender.client as client import netrender.model -@rnaType class RENDER_OT_netslave_bake(bpy.types.Operator): '''NEED DESCRIPTION''' bl_idname = "render.netslavebake" bl_label = "Bake all in file" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -52,27 +52,27 @@ class RENDER_OT_netslave_bake(bpy.types.Operator): modifier.settings.path = relative_path bpy.ops.fluid.bake({"active_object": object, "scene": scene}) elif modifier.type == "CLOTH": - modifier.point_cache.step = 1 - modifier.point_cache.disk_cache = True - modifier.point_cache.external = False + modifier.point_cache.frame_step = 1 + modifier.point_cache.use_disk_cache = True + modifier.point_cache.use_external = False elif modifier.type == "SOFT_BODY": - modifier.point_cache.step = 1 - modifier.point_cache.disk_cache = True - modifier.point_cache.external = False + modifier.point_cache.frame_step = 1 + modifier.point_cache.use_disk_cache = True + modifier.point_cache.use_external = False elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN": - modifier.domain_settings.point_cache_low.step = 1 - modifier.domain_settings.point_cache_low.disk_cache = True - modifier.domain_settings.point_cache_low.external = False - modifier.domain_settings.point_cache_high.step = 1 - modifier.domain_settings.point_cache_high.disk_cache = True - modifier.domain_settings.point_cache_high.external = False + modifier.domain_settings.point_cache_low.use_step = 1 + modifier.domain_settings.point_cache_low.use_disk_cache = True + modifier.domain_settings.point_cache_low.use_external = False + modifier.domain_settings.point_cache_high.use_step = 1 + modifier.domain_settings.point_cache_high.use_disk_cache = True + modifier.domain_settings.point_cache_high.use_external = False # particles modifier are stupid and don't contain data # we have to go through the object property for psys in object.particle_systems: - psys.point_cache.step = 1 - psys.point_cache.disk_cache = True - psys.point_cache.external = False + psys.point_cache.use_step = 1 + psys.point_cache.use_disk_cache = True + psys.point_cache.use_external = False psys.point_cache.filepath = relative_path bpy.ops.ptcache.bake_all() @@ -84,13 +84,13 @@ class RENDER_OT_netslave_bake(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientanim(bpy.types.Operator): '''Start rendering an animation on network''' bl_idname = "render.netclientanim" bl_label = "Animation on network" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -111,13 +111,13 @@ class RENDER_OT_netclientanim(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientrun(bpy.types.Operator): '''Start network rendering service''' bl_idname = "render.netclientstart" bl_label = "Start Service" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -128,13 +128,13 @@ class RENDER_OT_netclientrun(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientsend(bpy.types.Operator): '''Send Render Job to the Network''' bl_idname = "render.netclientsend" bl_label = "Send job" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -158,13 +158,13 @@ class RENDER_OT_netclientsend(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientsendframe(bpy.types.Operator): '''Send Render Job with current frame to the Network''' bl_idname = "render.netclientsendframe" bl_label = "Send current frame job" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -188,13 +188,13 @@ class RENDER_OT_netclientsendframe(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientstatus(bpy.types.Operator): '''Refresh the status of the current jobs''' bl_idname = "render.netclientstatus" bl_label = "Client Status" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -205,6 +205,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): conn.request("GET", "/status") response = conn.getresponse() + response.read() print( response.status, response.reason ) jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8'))) @@ -228,13 +229,13 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientblacklistslave(bpy.types.Operator): '''Operator documentation text, will be used for the operator tooltip and python docs.''' bl_idname = "render.netclientblacklistslave" bl_label = "Client Blacklist Slave" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -258,13 +259,13 @@ class RENDER_OT_netclientblacklistslave(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): '''Operator documentation text, will be used for the operator tooltip and python docs.''' bl_idname = "render.netclientwhitelistslave" bl_label = "Client Whitelist Slave" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -289,13 +290,13 @@ class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): return self.execute(context) -@rnaType class RENDER_OT_netclientslaves(bpy.types.Operator): '''Refresh status about available Render slaves''' bl_idname = "render.netclientslaves" bl_label = "Client Slaves" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -306,6 +307,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): conn.request("GET", "/slaves") response = conn.getresponse() + response.read() print( response.status, response.reason ) slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8'))) @@ -334,13 +336,13 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientcancel(bpy.types.Operator): '''Cancel the selected network rendering job.''' bl_idname = "render.netclientcancel" bl_label = "Client Cancel" - def poll(self, context): + @classmethod + def poll(cls, context): netsettings = context.scene.network_render return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 @@ -354,6 +356,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): conn.request("POST", cancelURL(job.id)) response = conn.getresponse() + response.read() print( response.status, response.reason ) netsettings.jobs.remove(netsettings.active_job_index) @@ -363,13 +366,13 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class RENDER_OT_netclientcancelall(bpy.types.Operator): '''Cancel all running network rendering jobs.''' bl_idname = "render.netclientcancelall" bl_label = "Client Cancel All" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -380,6 +383,7 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator): conn.request("POST", "/clear") response = conn.getresponse() + response.read() print( response.status, response.reason ) while(len(netsettings.jobs) > 0): @@ -390,13 +394,13 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class netclientdownload(bpy.types.Operator): '''Download render results from the network''' bl_idname = "render.netclientdownload" bl_label = "Client Download" - def poll(self, context): + @classmethod + def poll(cls, context): netsettings = context.scene.network_render return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 @@ -412,6 +416,7 @@ class netclientdownload(bpy.types.Operator): for frame in job.frames: client.requestResult(conn, job.id, frame.number) response = conn.getresponse() + response.read() if response.status != http.client.OK: print("missing", frame.number) @@ -419,7 +424,7 @@ class netclientdownload(bpy.types.Operator): print("got back", frame.number) - f = open(netsettings.path + "%06d" % frame.number + ".exr", "wb") + f = open(os.path.join(netsettings.path, "%06d.exr" % frame.number), "wb") buf = response.read(1024) while buf: @@ -435,13 +440,13 @@ class netclientdownload(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class netclientscan(bpy.types.Operator): '''Listen on network for master server broadcasting its address and port.''' bl_idname = "render.netclientscan" bl_label = "Client Scan" - def poll(self, context): + @classmethod + def poll(cls, context): return True def execute(self, context): @@ -458,13 +463,13 @@ class netclientscan(bpy.types.Operator): def invoke(self, context, event): return self.execute(context) -@rnaType class netclientweb(bpy.types.Operator): '''Open new window with information about running rendering jobs''' bl_idname = "render.netclientweb" bl_label = "Open Master Monitor" - def poll(self, context): + @classmethod + def poll(cls, context): netsettings = context.scene.network_render return netsettings.server_address != "[default]" diff --git a/release/scripts/io/netrender/repath.py b/release/scripts/io/netrender/repath.py index 7f9befd34fb..3ac9636b628 100755..100644 --- a/release/scripts/io/netrender/repath.py +++ b/release/scripts/io/netrender/repath.py @@ -66,10 +66,10 @@ def update(job): def process(paths): def processPointCache(point_cache): - point_cache.external = False + point_cache.use_external = False def processFluid(fluid): - new_path = path_map.get(fluid.path, None) + new_path = path_map.get(fluid.filepath, None) if new_path: fluid.path = new_path @@ -83,14 +83,17 @@ def process(paths): elif paths[i].endswith(".bobj.gz"): path_map[os.path.split(paths[i])[0]] = os.path.split(paths[i+1])[0] else: - path_map[paths[i]] = paths[i+1] + path_map[os.path.split(paths[i])[1]] = paths[i+1] + + # TODO original paths aren't really the orignal path (they are the normalized path + # so we repath using the filenames only. ########################### # LIBRARIES ########################### for lib in bpy.data.libraries: - file_path = bpy.utils.expandpath(lib.filepath) - new_path = path_map.get(file_path, None) + file_path = bpy.path.abspath(lib.filepath) + new_path = path_map.get(os.path.split(file_path)[1], None) if new_path: lib.filepath = new_path @@ -99,8 +102,8 @@ def process(paths): ########################### for image in bpy.data.images: if image.source == "FILE" and not image.packed_file: - file_path = bpy.utils.expandpath(image.filepath) - new_path = path_map.get(file_path, None) + file_path = bpy.path.abspath(image.filepath) + new_path = path_map.get(os.path.split(file_path)[1], None) if new_path: image.filepath = new_path @@ -118,10 +121,10 @@ def process(paths): processPointCache(modifier.point_cache) elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN": processPointCache(modifier.domain_settings.point_cache_low) - if modifier.domain_settings.highres: + if modifier.domain_settings.use_high_resolution: processPointCache(modifier.domain_settings.point_cache_high) - elif modifier.type == "MULTIRES" and modifier.external: - file_path = bpy.utils.expandpath(modifier.filepath) + elif modifier.type == "MULTIRES" and modifier.is_external: + file_path = bpy.path.abspath(modifier.filepath) new_path = path_map.get(file_path, None) if new_path: modifier.filepath = new_path @@ -144,4 +147,4 @@ if __name__ == "__main__": process(args) - bpy.ops.wm.save_as_mainfile(path=new_path, check_existing=False) + bpy.ops.wm.save_as_mainfile(filepath=new_path, check_existing=False) diff --git a/release/scripts/io/netrender/slave.py b/release/scripts/io/netrender/slave.py index 9fd00152dc1..b383481824b 100644 --- a/release/scripts/io/netrender/slave.py +++ b/release/scripts/io/netrender/slave.py @@ -59,8 +59,8 @@ def slave_Info(): def testCancel(conn, job_id, frame_number): conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) - # cancelled if job isn't found anymore - if conn.getresponse().status == http.client.NO_CONTENT: + # canceled if job isn't found anymore + if responseStatus(conn) == http.client.NO_CONTENT: return True else: return False @@ -79,7 +79,9 @@ def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None): job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True) if not found: - temp_path = JOB_PREFIX + "slave.temp" + # Force prefix path if not found + job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True) + temp_path = os.path.join(JOB_PREFIX, "slave.temp") conn.request("GET", fileURL(job_id, rfile.index), headers={"slave-id":slave_id}) response = conn.getresponse() @@ -111,10 +113,11 @@ def render_slave(engine, netsettings, threads): if conn: conn.request("POST", "/slave", repr(slave_Info().serialize())) response = conn.getresponse() + response.read() slave_id = response.getheader("slave-id") - NODE_PREFIX = netsettings.path + "slave_" + slave_id + os.sep + NODE_PREFIX = os.path.join(netsettings.path, "slave_" + slave_id) if not os.path.exists(NODE_PREFIX): os.mkdir(NODE_PREFIX) @@ -130,7 +133,7 @@ def render_slave(engine, netsettings, threads): job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8'))) engine.update_stats("", "Network render processing job from master") - JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep + JOB_PREFIX = os.path.join(NODE_PREFIX, "job_" + job.id) if not os.path.exists(JOB_PREFIX): os.mkdir(JOB_PREFIX) @@ -155,6 +158,7 @@ def render_slave(engine, netsettings, threads): logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames]) conn.request("POST", "/log", bytes(repr(logfile.serialize()), encoding='utf8')) response = conn.getresponse() + response.read() first_frame = job.frames[0].number @@ -170,7 +174,7 @@ def render_slave(engine, netsettings, threads): frame_args += ["-f", str(frame.number)] val = SetErrorMode() - process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-t", str(threads), "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-t", str(threads), "-o", os.path.join(JOB_PREFIX, "######"), "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) RestoreErrorMode(val) elif job.type == netrender.model.JOB_PROCESS: command = job.frames[0].command @@ -194,9 +198,10 @@ def render_slave(engine, netsettings, threads): # (only need to update on one frame, they are linked conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers) response = conn.getresponse() + response.read() # Also output on console - if netsettings.slave_thumb: + if netsettings.use_slave_output_log: print(str(stdout, encoding='utf8'), end="") stdout = bytes() @@ -214,18 +219,21 @@ def render_slave(engine, netsettings, threads): if cancelled: # kill process if needed if process.poll() == None: - process.terminate() + try: + process.terminate() + except OSError: + pass continue # to next frame # flush the rest of the logs if stdout: # Also output on console - if netsettings.slave_thumb: + if netsettings.use_slave_thumb: print(str(stdout, encoding='utf8'), end="") # (only need to update on one frame, they are linked conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers) - if conn.getresponse().status == http.client.NO_CONTENT: + if responseStatus(conn) == http.client.NO_CONTENT: continue total_t = time.time() - start_t @@ -246,26 +254,27 @@ def render_slave(engine, netsettings, threads): if job.type == netrender.model.JOB_BLENDER: # send image back to server - filename = JOB_PREFIX + "%06d" % frame.number + ".exr" + filename = os.path.join(JOB_PREFIX, "%06d.exr" % frame.number) # thumbnail first - if netsettings.slave_thumb: + if netsettings.use_slave_thumb: thumbname = thumbnail(filename) f = open(thumbname, 'rb') conn.request("PUT", "/thumb", f, headers=headers) f.close() - conn.getresponse() + responseStatus(conn) + f = open(filename, 'rb') conn.request("PUT", "/render", f, headers=headers) f.close() - if conn.getresponse().status == http.client.NO_CONTENT: + if responseStatus(conn) == http.client.NO_CONTENT: continue elif job.type == netrender.model.JOB_PROCESS: conn.request("PUT", "/render", headers=headers) - if conn.getresponse().status == http.client.NO_CONTENT: + if responseStatus(conn) == http.client.NO_CONTENT: continue else: headers["job-result"] = str(ERROR) @@ -273,7 +282,7 @@ def render_slave(engine, netsettings, threads): headers["job-frame"] = str(frame.number) # send error result back to server conn.request("PUT", "/render", headers=headers) - if conn.getresponse().status == http.client.NO_CONTENT: + if responseStatus(conn) == http.client.NO_CONTENT: continue engine.update_stats("", "Network render connected to master, waiting for jobs") @@ -288,7 +297,7 @@ def render_slave(engine, netsettings, threads): conn.close() - if netsettings.slave_clear: + if netsettings.use_slave_clear: clearSlave(NODE_PREFIX) if __name__ == "__main__": diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py index c60b10c484a..c2d943f63f8 100644 --- a/release/scripts/io/netrender/ui.py +++ b/release/scripts/io/netrender/ui.py @@ -36,6 +36,11 @@ DISPATCHED = 1 DONE = 2 ERROR = 3 +def base_poll(cls, context): + rd = context.scene.render + return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) + + def init_file(): if netrender.init_file != bpy.data.filepath: netrender.init_file = bpy.data.filepath @@ -81,17 +86,21 @@ class RenderButtonsPanel(): bl_region_type = "WINDOW" bl_context = "render" # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here - - def poll(self, context): + + @classmethod + def poll(cls, context): rd = context.scene.render - return (rd.use_game_engine==False) and (rd.engine in self.COMPAT_ENGINES) + return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES) # Setting panel, use in the scene for now. -@rnaType class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel): bl_label = "Network Settings" COMPAT_ENGINES = {'NET_RENDER'} + @classmethod + def poll(cls, context): + return super(RENDER_PT_network_settings, cls).poll(context) + def draw(self, context): layout = self.layout @@ -122,15 +131,14 @@ class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel): layout.operator("render.netclientweb", icon='QUESTION') -@rnaType class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel): bl_label = "Slave Settings" COMPAT_ENGINES = {'NET_RENDER'} - def poll(self, context): + @classmethod + def poll(cls, context): scene = context.scene - return (super().poll(context) - and scene.network_render.mode == "RENDER_SLAVE") + return super(RENDER_PT_network_slave_settings, cls).poll(context) and scene.network_render.mode == "RENDER_SLAVE" def draw(self, context): layout = self.layout @@ -139,23 +147,23 @@ class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel): rd = scene.render netsettings = scene.network_render - layout.prop(netsettings, "slave_clear") - layout.prop(netsettings, "slave_thumb") - layout.prop(netsettings, "slave_outputlog") + layout.prop(netsettings, "use_slave_clear") + layout.prop(netsettings, "use_slave_thumb") + layout.prop(netsettings, "use_slave_output_log") layout.label(text="Threads:") layout.prop(rd, "threads_mode", expand=True) sub = layout.column() sub.enabled = rd.threads_mode == 'FIXED' sub.prop(rd, "threads") -@rnaType + class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel): bl_label = "Master Settings" COMPAT_ENGINES = {'NET_RENDER'} - def poll(self, context): + @classmethod + def poll(cls, context): scene = context.scene - return (super().poll(context) - and scene.network_render.mode == "RENDER_MASTER") + return super(RENDER_PT_network_master_settings, cls).poll(context) and scene.network_render.mode == "RENDER_MASTER" def draw(self, context): layout = self.layout @@ -163,18 +171,17 @@ class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel): scene = context.scene netsettings = scene.network_render - layout.prop(netsettings, "master_broadcast") - layout.prop(netsettings, "master_clear") + layout.prop(netsettings, "use_master_broadcast") + layout.prop(netsettings, "use_master_clear") -@rnaType class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel): bl_label = "Job Settings" COMPAT_ENGINES = {'NET_RENDER'} - def poll(self, context): + @classmethod + def poll(cls, context): scene = context.scene - return (super().poll(context) - and scene.network_render.mode == "RENDER_CLIENT") + return super(RENDER_PT_network_job, cls).poll(context) and scene.network_render.mode == "RENDER_CLIENT" def draw(self, context): layout = self.layout @@ -207,19 +214,18 @@ class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel): row.prop(netsettings, "priority") row.prop(netsettings, "chunks") -@rnaType class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel): bl_label = "Slaves Status" COMPAT_ENGINES = {'NET_RENDER'} - def poll(self, context): + @classmethod + def poll(cls, context): scene = context.scene netsettings = scene.network_render if netsettings.mode != "RENDER_CLIENT": return False verify_address(netsettings) - return (super().poll(context) - and netsettings.server_address != "[default]") + return super(RENDER_PT_network_slaves, cls).poll(context) and netsettings.server_address != "[default]" def draw(self, context): layout = self.layout @@ -246,19 +252,18 @@ class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel): layout.label(text="Seen: " + time.ctime(slave.last_seen)) layout.label(text="Stats: " + slave.stats) -@rnaType class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel): bl_label = "Slaves Blacklist" COMPAT_ENGINES = {'NET_RENDER'} - def poll(self, context): + @classmethod + def poll(cls, context): scene = context.scene netsettings = scene.network_render if netsettings.mode != "RENDER_CLIENT": return False verify_address(netsettings) - return (super().poll(context) - and netsettings.server_address != "[default]") + return super(RENDER_PT_network_slaves_blacklist, cls).poll(context) and netsettings.server_address != "[default]" def draw(self, context): layout = self.layout @@ -284,19 +289,18 @@ class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel): layout.label(text="Seen: " + time.ctime(slave.last_seen)) layout.label(text="Stats: " + slave.stats) -@rnaType class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel): bl_label = "Jobs" COMPAT_ENGINES = {'NET_RENDER'} - def poll(self, context): + @classmethod + def poll(cls, context): scene = context.scene netsettings = scene.network_render if netsettings.mode != "RENDER_CLIENT": return False verify_address(netsettings) - return (super().poll(context) - and netsettings.server_address != "[default]") + return super(RENDER_PT_network_jobs, cls).poll(context) and netsettings.server_address != "[default]" def draw(self, context): layout = self.layout @@ -325,150 +329,148 @@ class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel): layout.label(text="Done: %04i" % job.results[DONE]) layout.label(text="Error: %04i" % job.results[ERROR]) -@rnaType class NetRenderSettings(bpy.types.IDPropertyGroup): pass -@rnaType class NetRenderSlave(bpy.types.IDPropertyGroup): pass -@rnaType class NetRenderJob(bpy.types.IDPropertyGroup): pass -bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings") - -NetRenderSettings.StringProperty( attr="server_address", - name="Server address", - description="IP or name of the master render server", - maxlen = 128, - default = "[default]") - -NetRenderSettings.IntProperty( attr="server_port", - name="Server port", - description="port of the master render server", - default = 8000, - min=1, - max=65535) - -NetRenderSettings.BoolProperty( attr="master_broadcast", - name="Broadcast", - description="broadcast master server address on local network", - default = True) - -NetRenderSettings.BoolProperty( attr="slave_clear", - name="Clear on exit", - description="delete downloaded files on exit", - default = True) - -NetRenderSettings.BoolProperty( attr="slave_thumb", - name="Generate thumbnails", - description="Generate thumbnails on slaves instead of master", - default = False) - -NetRenderSettings.BoolProperty( attr="slave_outputlog", - name="Output render log on console", - description="Output render text log to console as well as sending it to the master", - default = True) - -NetRenderSettings.BoolProperty( attr="master_clear", - name="Clear on exit", - description="delete saved files on exit", - default = False) - -default_path = os.environ.get("TEMP") - -if not default_path: - if os.name == 'nt': - default_path = "c:/tmp/" - else: - default_path = "/tmp/" -elif not default_path.endswith(os.sep): - default_path += os.sep - -NetRenderSettings.StringProperty( attr="path", - name="Path", - description="Path for temporary files", - maxlen = 128, - default = default_path, - subtype='FILE_PATH') - -NetRenderSettings.StringProperty( attr="job_name", - name="Job name", - description="Name of the job", - maxlen = 128, - default = "[default]") - -NetRenderSettings.StringProperty( attr="job_category", - name="Job category", - description="Category of the job", - maxlen = 128, - default = "") - -NetRenderSettings.IntProperty( attr="chunks", - name="Chunks", - description="Number of frame to dispatch to each slave in one chunk", - default = 5, - min=1, - max=65535) - -NetRenderSettings.IntProperty( attr="priority", - name="Priority", - description="Priority of the job", - default = 1, - min=1, - max=10) - -NetRenderSettings.StringProperty( attr="job_id", - name="Network job id", - description="id of the last sent render job", - maxlen = 64, - default = "") - -NetRenderSettings.IntProperty( attr="active_slave_index", - name="Index of the active slave", - description="", - default = -1, - min= -1, - max=65535) - -NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index", - name="Index of the active slave", - description="", - default = -1, - min= -1, - max=65535) - -NetRenderSettings.IntProperty( attr="active_job_index", - name="Index of the active job", - description="", - default = -1, - min= -1, - max=65535) - -NetRenderSettings.EnumProperty(attr="mode", - items=( - ("RENDER_CLIENT", "Client", "Act as render client"), - ("RENDER_MASTER", "Master", "Act as render master"), - ("RENDER_SLAVE", "Slave", "Act as render slave"), - ), - name="Network mode", - description="Mode of operation of this instance", - default="RENDER_CLIENT") - -NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="") -NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="") -NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="") - -NetRenderSlave.StringProperty( attr="name", - name="Name of the slave", - description="", - maxlen = 64, - default = "") - -NetRenderJob.StringProperty( attr="name", - name="Name of the job", - description="", - maxlen = 128, - default = "") +def addProperties(): + bpy.types.Scene.PointerProperty(attr="network_render", type=NetRenderSettings, name="Network Render", description="Network Render Settings") + + NetRenderSettings.StringProperty( attr="server_address", + name="Server address", + description="IP or name of the master render server", + maxlen = 128, + default = "[default]") + + NetRenderSettings.IntProperty( attr="server_port", + name="Server port", + description="port of the master render server", + default = 8000, + min=1, + max=65535) + + NetRenderSettings.BoolProperty( attr="use_master_broadcast", + name="Broadcast", + description="broadcast master server address on local network", + default = True) + + NetRenderSettings.BoolProperty( attr="use_slave_clear", + name="Clear on exit", + description="delete downloaded files on exit", + default = True) + + NetRenderSettings.BoolProperty( attr="use_slave_thumb", + name="Generate thumbnails", + description="Generate thumbnails on slaves instead of master", + default = False) + + NetRenderSettings.BoolProperty( attr="use_slave_output_log", + name="Output render log on console", + description="Output render text log to console as well as sending it to the master", + default = True) + + NetRenderSettings.BoolProperty( attr="use_master_clear", + name="Clear on exit", + description="delete saved files on exit", + default = False) + + default_path = os.environ.get("TEMP") + + if not default_path: + if os.name == 'nt': + default_path = "c:/tmp/" + else: + default_path = "/tmp/" + elif not default_path.endswith(os.sep): + default_path += os.sep + + NetRenderSettings.StringProperty( attr="path", + name="Path", + description="Path for temporary files", + maxlen = 128, + default = default_path, + subtype='FILE_PATH') + + NetRenderSettings.StringProperty( attr="job_name", + name="Job name", + description="Name of the job", + maxlen = 128, + default = "[default]") + + NetRenderSettings.StringProperty( attr="job_category", + name="Job category", + description="Category of the job", + maxlen = 128, + default = "") + + NetRenderSettings.IntProperty( attr="chunks", + name="Chunks", + description="Number of frame to dispatch to each slave in one chunk", + default = 5, + min=1, + max=65535) + + NetRenderSettings.IntProperty( attr="priority", + name="Priority", + description="Priority of the job", + default = 1, + min=1, + max=10) + + NetRenderSettings.StringProperty( attr="job_id", + name="Network job id", + description="id of the last sent render job", + maxlen = 64, + default = "") + + NetRenderSettings.IntProperty( attr="active_slave_index", + name="Index of the active slave", + description="", + default = -1, + min= -1, + max=65535) + + NetRenderSettings.IntProperty( attr="active_blacklisted_slave_index", + name="Index of the active slave", + description="", + default = -1, + min= -1, + max=65535) + + NetRenderSettings.IntProperty( attr="active_job_index", + name="Index of the active job", + description="", + default = -1, + min= -1, + max=65535) + + NetRenderSettings.EnumProperty(attr="mode", + items=( + ("RENDER_CLIENT", "Client", "Act as render client"), + ("RENDER_MASTER", "Master", "Act as render master"), + ("RENDER_SLAVE", "Slave", "Act as render slave"), + ), + name="Network mode", + description="Mode of operation of this instance", + default="RENDER_CLIENT") + + NetRenderSettings.CollectionProperty(attr="slaves", type=NetRenderSlave, name="Slaves", description="") + NetRenderSettings.CollectionProperty(attr="slaves_blacklist", type=NetRenderSlave, name="Slaves Blacklist", description="") + NetRenderSettings.CollectionProperty(attr="jobs", type=NetRenderJob, name="Job List", description="") + + NetRenderSlave.StringProperty( attr="name", + name="Name of the slave", + description="", + maxlen = 64, + default = "") + + NetRenderJob.StringProperty( attr="name", + name="Name of the job", + description="", + maxlen = 128, + default = "") diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py index 6288b9747c0..81617ac0d30 100644 --- a/release/scripts/io/netrender/utils.py +++ b/release/scripts/io/netrender/utils.py @@ -57,9 +57,10 @@ FRAME_STATUS_TEXT = { ERROR: "Error" } -def rnaType(rna_type): - if bpy: bpy.types.register(rna_type) - return rna_type +def responseStatus(conn): + response = conn.getresponse() + response.read() + return response.status def reporting(report, message, errorType = None): if errorType: @@ -171,20 +172,20 @@ def prefixPath(prefix_directory, file_path, prefix_path, force = False): # if an absolute path, make sure path exists, if it doesn't, use relative local path full_path = file_path if force or not os.path.exists(full_path): - p, n = os.path.split(full_path) + p, n = os.path.split(os.path.normpath(full_path)) if prefix_path and p.startswith(prefix_path): if len(prefix_path) < len(p): - directory = prefix_directory + p[len(prefix_path)+1:] + os.sep # +1 to remove separator + directory = os.path.join(prefix_directory, p[len(prefix_path)+1:]) # +1 to remove separator if not os.path.exists(directory): os.mkdir(directory) else: directory = prefix_directory - full_path = directory + n + full_path = os.path.join(directory, n) else: - full_path = prefix_directory + n + full_path = os.path.join(prefix_directory, n) else: - full_path = prefix_directory + file_path + full_path = (prefix_directory, file_path) return full_path |