diff --git a/release/io/netrender/client.py b/release/io/netrender/client.py index 90039a3273a..bc4d363c996 100644 --- a/release/io/netrender/client.py +++ b/release/io/netrender/client.py @@ -22,7 +22,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): def render_master(self, scene): server_address = (scene.network_render.server_address, scene.network_render.server_port) - httpd = master.RenderMasterServer(server_address, master.RenderHandler) + httpd = master.RenderMasterServer(server_address, master.RenderHandler, scene.network_render.path) httpd.timeout = 1 httpd.stats = self.update_stats while not self.test_break(): @@ -32,6 +32,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): slave.render_slave(self, scene) def render_client(self, scene): + netsettings = scene.network_render self.update_stats("", "Network render client initiation") conn = clientConnection(scene) @@ -41,7 +42,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): self.update_stats("", "Network render exporting") - job_id = scene.network_render.job_id + job_id = netsettings.job_id # reading back result @@ -51,10 +52,10 @@ class NetworkRenderEngine(bpy.types.RenderEngine): response = conn.getresponse() if response.status == http.client.NO_CONTENT: - scene.network_render.job_id = clientSendJob(conn, scene) + netsettings.job_id = clientSendJob(conn, scene) clientRequestResult(conn, scene, job_id) - while response.status == http.client.PROCESSING and not self.test_break(): + while response.status == http.client.ACCEPTED and not self.test_break(): print("waiting") time.sleep(1) clientRequestResult(conn, scene, job_id) @@ -68,7 +69,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(PATH_PREFIX + "output.exr", "wb") + f = open(netsetting.path + "output.exr", "wb") buf = response.read(1024) while buf: @@ -78,7 +79,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine): f.close() result = self.begin_result(0, 0, x, y) - result.load_from_file(PATH_PREFIX + "output.exr", 0, 0) + result.load_from_file(netsettings.path + "output.exr", 0, 0) self.end_result(result) conn.close() diff --git a/release/io/netrender/master.py b/release/io/netrender/master.py index daca3bcf653..6f97685935d 100644 --- a/release/io/netrender/master.py +++ b/release/io/netrender/master.py @@ -9,12 +9,22 @@ JOB_WAITING = 0 # before all data has been entered JOB_PAUSED = 1 # paused by user JOB_QUEUED = 2 # ready to be dispatched +class MRenderFile: + def __init__(self, filepath): + self.filepath = filepath + self.found = False + + def test(self): + self.found = os.path.exists(self.filepath) + return self.found + + class MRenderSlave(netrender.model.RenderSlave): - def __init__(self, name, adress, stats): + def __init__(self, name, address, stats): super().__init__() - self.id = hashlib.md5(bytes(repr(name) + repr(adress), encoding='utf8')).hexdigest() + self.id = hashlib.md5(bytes(repr(name) + repr(address), encoding='utf8')).hexdigest() self.name = name - self.adress = adress + self.address = address self.stats = stats self.last_seen = time.time() @@ -31,11 +41,12 @@ def groupKey(job): return (job.status, job.framesLeft() > 0, job.priority, job.credits) class MRenderJob(netrender.model.RenderJob): - def __init__(self, job_id, name, path, chunks = 1, priority = 1, credits = 100.0, blacklist = []): + def __init__(self, job_id, name, files, chunks = 1, priority = 1, credits = 100.0, blacklist = []): super().__init__() self.id = job_id self.name = name - self.path = path + self.files = files + self.render_files = [MRenderFile(path) for path in files] self.status = JOB_WAITING self.frames = [] self.chunks = chunks @@ -44,6 +55,14 @@ class MRenderJob(netrender.model.RenderJob): self.blacklist = blacklist self.last_dispatched = time.time() + def testStart(self): + for f in self.render_files: + if not f.test(): + return False + + self.start() + return True + def start(self): self.status = JOB_QUEUED @@ -75,7 +94,7 @@ class MRenderJob(netrender.model.RenderJob): if f.status == QUEUED: self.update() frames.append(f) - if len(frames) == self.chunks: + if len(frames) >= self.chunks: break return frames @@ -162,10 +181,10 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if frame: if frame.status in (QUEUED, DISPATCHED): - self.send_head(http.client.PROCESSING) + self.send_head(http.client.ACCEPTED) elif frame.status == DONE: self.server.stats("", "Sending result back to client") - f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".exr", 'rb') + f = open(self.server.path + job_id + "%04d" % job_frame + ".exr", 'rb') self.send_head() @@ -173,13 +192,13 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): f.close() elif frame.status == ERROR: - self.send_head(http.client.NO_CONTENT) + self.send_head(http.client.PARTIAL_CONTENT) else: # no such frame - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) else: # no such job id - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "log": job_id = self.headers['job-id'] @@ -194,23 +213,21 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if frame: if frame.status in (QUEUED, DISPATCHED): self.send_head(http.client.PROCESSING) - elif frame.status == DONE: + else: self.server.stats("", "Sending log back to client") - f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".log", 'rb') + f = open(self.server.path + job_id + "%04d" % job_frame + ".log", 'rb') self.send_head() shutil.copyfileobj(f, self.wfile) f.close() - elif frame.status == ERROR: - self.send_head(http.client.NO_CONTENT) else: # no such frame - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) else: # no such job id - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "status": job_id = self.headers.get('job-id', "") @@ -228,13 +245,13 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): message = frame.serialize() else: # no such frame - self.send_heat(http.client.NOT_FOUND) + self.send_heat(http.client.NO_CONTENT) return else: message = job.serialize() else: # no such job id - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) return else: # status of all jobs message = [] @@ -262,6 +279,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if job and frames: for f in frames: + print("dispatch", f.number) f.status = DISPATCHED f.slave = slave @@ -274,9 +292,9 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.server.stats("", "Sending job frame to render node") else: # no job available, return error code - self.send_head(http.client.NO_CONTENT) + self.send_head(http.client.ACCEPTED) else: # invalid slave id - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "file": job_id = self.headers['job-id'] @@ -288,14 +306,14 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head(headers={"job-id": job.id}) self.server.stats("", "Sending file to render node") - f = open(PATH_PREFIX + job.id + ".blend", 'rb') + f = open(self.server.path + job.id + ".blend", 'rb') shutil.copyfileobj(f, self.wfile) f.close() else: # no such job id - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "slave": message = [] @@ -322,33 +340,25 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.server.stats("", "Receiving job") length = int(self.headers['content-length']) - job_frame_string = self.headers['job-frame'] - job_name = self.headers.get('job-name', "") - job_chunks = int(self.headers.get('job-chunks', "1")) - blacklist = self.headers.get('slave-blacklist', '').split() - job_path = str(self.rfile.read(length), encoding='utf8') + job_info = netrender.model.RenderJob.materialize(eval(str(self.rfile.read(length), encoding='utf8'))) - if os.path.exists(job_path): - job_id = self.server.nextJobID() + job_id = self.server.nextJobID() + + print("chunks", job_info.chunks) + + job = MRenderJob(job_id, job_info.name, job_info.files, chunks = job_info.chunks, priority = job_info.priority, blacklist = job_info.blacklist) + self.server.addJob(job) + + for frame in job_info.frames: + frame = job.addFrame(frame.number) - job = MRenderJob(job_id, job_name, job_path, chunks = job_chunks, blacklist = blacklist) - self.server.addJob(job) - - if ":" in job_frame_string: - frame_start, frame_end = [int(x) for x in job_frame_string.split(":")] - - for job_frame in range(frame_start, frame_end + 1): - frame = job.addFrame(job_frame) - else: - job_frame = int(job_frame_string) - frame = job.addFrame(job_frame) - - job.start() - - self.send_head(headers={"job-id": job_id}) + headers={"job-id": job_id} + + if job.testStart(): + self.send_head(headers=headers) else: - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.ACCEPTED, headers=headers) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "cancel": job_id = self.headers.get('job-id', "") @@ -375,7 +385,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): self.send_head() else: # job not found - self.send_head(http.client.NOT_FOUND) + self.send_head(http.client.NO_CONTENT) # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- elif self.path == "slave": length = int(self.headers['content-length']) @@ -412,7 +422,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): job_path = job_id + ".blend" - f = open(PATH_PREFIX + job_path, "wb") + f = open(self.server.path + job_path, "wb") f.write(buf) f.close() del buf @@ -445,7 +455,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): if job_result == DONE: length = int(self.headers['content-length']) buf = self.rfile.read(length) - f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".exr", 'wb') + f = open(self.server.path + job_id + "%04d" % job_frame + ".exr", 'wb') f.write(buf) f.close() @@ -471,7 +481,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): print("log length:", length) buf = self.rfile.read(length) - f = open(PATH_PREFIX + job_id + "%04d" % job_frame + ".log", 'wb') + f = open(self.server.path + job_id + "%04d" % job_frame + ".log", 'wb') f.write(buf) f.close() @@ -483,20 +493,21 @@ class RenderHandler(http.server.BaseHTTPRequestHandler): class RenderMasterServer(http.server.HTTPServer): - def __init__(self, address, handler_class): + def __init__(self, address, handler_class, path): super().__init__(address, handler_class) self.jobs = [] self.jobs_map = {} self.slaves = [] self.slaves_map = {} self.job_id = 0 + self.path = path def nextJobID(self): self.job_id += 1 return str(self.job_id) - def addSlave(self, name, adress, stats): - slave = MRenderSlave(name, adress, stats) + def addSlave(self, name, address, stats): + slave = MRenderSlave(name, address, stats) self.slaves.append(slave) self.slaves_map[slave.id] = slave diff --git a/release/io/netrender/model.py b/release/io/netrender/model.py index 98866ff1dfc..8b919b1fa36 100644 --- a/release/io/netrender/model.py +++ b/release/io/netrender/model.py @@ -10,7 +10,7 @@ class RenderSlave: def __init__(self): self.id = "" self.name = "" - self.adress = (0,0) + self.address = (0,0) self.stats = "" self.total_done = 0 self.total_error = 0 @@ -20,7 +20,7 @@ class RenderSlave: return { "id": self.id, "name": self.name, - "adress": self.adress, + "address": self.address, "stats": self.stats, "total_done": self.total_done, "total_error": self.total_error, @@ -40,7 +40,7 @@ class RenderSlave: slave = RenderSlave() slave.id = slave_id slave.name = data["name"] - slave.adress = data["adress"] + slave.address = data["address"] slave.stats = data["stats"] slave.total_done = data["total_done"] slave.total_error = data["total_error"] @@ -54,7 +54,7 @@ class RenderJob: def __init__(self): self.id = "" self.name = "" - self.path = "" + self.files = [] self.frames = [] self.chunks = 0 self.priority = 0 @@ -62,6 +62,11 @@ class RenderJob: self.blacklist = [] self.last_dispatched = 0.0 + def addFrame(self, frame_number): + frame = RenderFrame(frame_number) + self.frames.append(frame) + return frame + def __len__(self): return len(self.frames) @@ -96,8 +101,9 @@ class RenderJob: return { "id": self.id, "name": self.name, - "path": self.path, + "files": self.files, "frames": [f.serialize() for f in self.frames if not frames or f in frames], + "chunks": self.chunks, "priority": self.priority, "credits": self.credits, "blacklist": self.blacklist, @@ -112,8 +118,9 @@ class RenderJob: job = RenderJob() job.id = data["id"] job.name = data["name"] - job.path = data["path"] + job.files = data["files"] job.frames = [RenderFrame.materialize(f) for f in data["frames"]] + job.chunks = data["chunks"] job.priority = data["priority"] job.credits = data["credits"] job.blacklist = data["blacklist"] @@ -122,8 +129,8 @@ class RenderJob: return job class RenderFrame: - def __init__(self): - self.number = 0 + def __init__(self, number = 0): + self.number = number self.time = 0 self.status = QUEUED self.slave = None diff --git a/release/io/netrender/operators.py b/release/io/netrender/operators.py index 8df662b6b52..a1208aa1b46 100644 --- a/release/io/netrender/operators.py +++ b/release/io/netrender/operators.py @@ -48,7 +48,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): return True def execute(self, context): - netprops = context.scene.network_render + netsettings = context.scene.network_render conn = clientConnection(context.scene) if conn: @@ -59,12 +59,12 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): jobs = (netrender.model.RenderJob.materialize(j) for j in eval(str(response.read(), encoding='utf8'))) - while(len(netprops.jobs) > 0): - netprops.jobs.remove(0) + while(len(netsettings.jobs) > 0): + netsettings.jobs.remove(0) for j in jobs: - netprops.jobs.add() - job = netprops.jobs[-1] + netsettings.jobs.add() + job = netsettings.jobs[-1] job_results = j.framesStatus() @@ -93,22 +93,22 @@ class RENDER_OT_netclientblacklistslave(bpy.types.Operator): return True def execute(self, context): - netprops = context.scene.network_render + netsettings = context.scene.network_render - if netprops.active_slave_index >= 0: + if netsettings.active_slave_index >= 0: - slave = netrender.slaves[netprops.active_slave_index] + slave = netrender.slaves[netsettings.active_slave_index] - netprops.slaves_blacklist.add() + netsettings.slaves_blacklist.add() - netprops.slaves_blacklist[-1].id = slave.id - netprops.slaves_blacklist[-1].name = slave.name - netprops.slaves_blacklist[-1].adress = slave.adress - netprops.slaves_blacklist[-1].last_seen = slave.last_seen - netprops.slaves_blacklist[-1].stats = slave.stats + netsettings.slaves_blacklist[-1].id = slave.id + netsettings.slaves_blacklist[-1].name = slave.name + netsettings.slaves_blacklist[-1].address = slave.address + netsettings.slaves_blacklist[-1].last_seen = slave.last_seen + netsettings.slaves_blacklist[-1].stats = slave.stats - netprops.slaves.remove(netprops.active_slave_index) - netprops.active_slave_index = -1 + netsettings.slaves.remove(netsettings.active_slave_index) + netsettings.active_slave_index = -1 return ('FINISHED',) @@ -129,22 +129,22 @@ class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): return True def execute(self, context): - netprops = context.scene.network_render + netsettings = context.scene.network_render - if netprops.active_blacklisted_slave_index >= 0: + if netsettings.active_blacklisted_slave_index >= 0: - slave = netprops.slaves_blacklist[netprops.active_blacklisted_slave_index] + slave = netsettings.slaves_blacklist[netsettings.active_blacklisted_slave_index] - netprops.slaves.add() + netsettings.slaves.add() - netprops.slaves[-1].id = slave.id - netprops.slaves[-1].name = slave.name - netprops.slaves[-1].adress = slave.adress - netprops.slaves[-1].last_seen = slave.last_seen - netprops.slaves[-1].stats = slave.stats + netsettings.slaves[-1].id = slave.id + netsettings.slaves[-1].name = slave.name + netsettings.slaves[-1].address = slave.address + netsettings.slaves[-1].last_seen = slave.last_seen + netsettings.slaves[-1].stats = slave.stats - netprops.slaves_blacklist.remove(netprops.active_blacklisted_slave_index) - netprops.active_blacklisted_slave_index = -1 + netsettings.slaves_blacklist.remove(netsettings.active_blacklisted_slave_index) + netsettings.active_blacklisted_slave_index = -1 return ('FINISHED',) @@ -166,7 +166,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): return True def execute(self, context): - netprops = context.scene.network_render + netsettings = context.scene.network_render conn = clientConnection(context.scene) if conn: @@ -177,21 +177,21 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): slaves = (netrender.model.RenderSlave.materialize(s) for s in eval(str(response.read(), encoding='utf8'))) - while(len(netprops.slaves) > 0): - netprops.slaves.remove(0) + while(len(netsettings.slaves) > 0): + netsettings.slaves.remove(0) for s in slaves: - for slave in netprops.slaves_blacklist: + for slave in netsettings.slaves_blacklist: if slave.id == s.id: break - netprops.slaves.add() - slave = netprops.slaves[-1] + netsettings.slaves.add() + slave = netsettings.slaves[-1] slave.id = s.id slave.name = s.name slave.stats = s.stats - slave.adress = s.adress[0] + slave.address = s.address[0] slave.last_seen = time.ctime(s.last_seen) return ('FINISHED',) @@ -210,15 +210,15 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): __props__ = [] def poll(self, context): - netprops = context.scene.network_render - return netprops.active_job_index >= 0 and len(netprops.jobs) > 0 + netsettings = context.scene.network_render + return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0 def execute(self, context): - netprops = context.scene.network_render + netsettings = context.scene.network_render conn = clientConnection(context.scene) if conn: - job = netprops.jobs[netprops.active_job_index] + job = netsettings.jobs[netsettings.active_job_index] conn.request("POST", "cancel", headers={"job-id":job.id}) diff --git a/release/io/netrender/slave.py b/release/io/netrender/slave.py index 59c474293b3..64801743d70 100644 --- a/release/io/netrender/slave.py +++ b/release/io/netrender/slave.py @@ -21,17 +21,50 @@ def testCancel(conn, job_id): response = conn.getresponse() # cancelled if job isn't found anymore - if response.status == http.client.NOT_FOUND: + if response.status == http.client.NO_CONTENT: return True else: return False -def render_slave(engine, scene): - NODE_PREFIX = PATH_PREFIX + "node" + os.sep - timeout = 1 +def testFile(conn, JOB_PREFIX, file_path, main_path = None): + if os.path.isabs(file_path): + # if an absolute path, make sure path exists, if it doesn't, use relative local path + job_full_path = file_path + if not os.path.exists(job_full_path): + p, n = os.path.split(job_full_path) + + if main_path and p.startswith(main_path): + directory = JOB_PREFIX + p[len(main_path):] + job_full_path = directory + n + if not os.path.exists(directory): + os.mkdir(directory) + else: + job_full_path = JOB_PREFIX + n + else: + job_full_path = JOB_PREFIX + file_path - if not os.path.exists(NODE_PREFIX): - os.mkdir(NODE_PREFIX) + if not os.path.exists(job_full_path): + conn.request("GET", "file", headers={"job-id": job.id, "slave-id":slave_id}) + response = conn.getresponse() + + if response.status != http.client.OK: + return None # file for job not returned by server, need to return an error code to server + + f = open(job_full_path, "wb") + buf = response.read(1024) + + while buf: + f.write(buf) + buf = response.read(1024) + + f.close() + + return job_full_path + + +def render_slave(engine, scene): + netsettings = scene.network_render + timeout = 1 engine.update_stats("", "Network render node initiation") @@ -43,6 +76,10 @@ def render_slave(engine, scene): slave_id = response.getheader("slave-id") + NODE_PREFIX = netsettings.path + "node_" + slave_id + os.sep + if not os.path.exists(NODE_PREFIX): + os.mkdir(NODE_PREFIX) + while not engine.test_break(): conn.request("GET", "job", headers={"slave-id":slave_id}) @@ -53,41 +90,30 @@ def render_slave(engine, scene): job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8'))) - print("File:", job.path) - engine.update_stats("", "Render File", job.path, "for job", job.id) + JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep + if not os.path.exists(JOB_PREFIX): + os.mkdir(JOB_PREFIX) - if os.path.isabs(job.path): - # if an absolute path, make sure path exists, if it doesn't, use relative local path - job_full_path = job.path - if not os.path.exists(job_full_path): - job_full_path = NODE_PREFIX + job.id + ".blend" - else: - job_full_path = NODE_PREFIX + job.path + job_path = job.files[0] + main_path, main_file = os.path.split(job_path) - if not os.path.exists(job_full_path): - conn.request("GET", "file", headers={"job-id": job.id, "slave-id":slave_id}) - response = conn.getresponse() - - if response.status != http.client.OK: - break # file for job not returned by server, need to return an error code to server - - f = open(job_full_path, "wb") - buf = response.read(1024) - - while buf: - f.write(buf) - buf = response.read(1024) - - f.close() + job_full_path = testFile(conn, JOB_PREFIX, job_path) + print("Fullpath", job_full_path) + print("File:", main_file, "and %i other files" % (len(job.files) - 1,)) + engine.update_stats("", "Render File", main_file, "for job", job.id) + + for file_path in job.files[1:]: + testFile(conn, JOB_PREFIX, file_path, main_path) frame_args = [] for frame in job.frames: + print("frame", frame.number) frame_args += ["-f", str(frame.number)] start_t = time.time() - process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", NODE_PREFIX + job.id, "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + process = subprocess.Popen([sys.argv[0], "-b", job_full_path, "-o", JOB_PREFIX + "######", "-E", "BLENDER_RENDER", "-F", "MULTILAYER"] + frame_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) cancelled = False stdout = bytes() @@ -120,7 +146,7 @@ def render_slave(engine, scene): for frame in job.frames: headers["job-frame"] = str(frame.number) # send result back to server - f = open(NODE_PREFIX + job.id + "%04d" % frame.number + ".exr", 'rb') + f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb') conn.request("PUT", "render", f, headers=headers) f.close() response = conn.getresponse() diff --git a/release/io/netrender/ui.py b/release/io/netrender/ui.py index 71b013c5a63..f8179fedbda 100644 --- a/release/io/netrender/ui.py +++ b/release/io/netrender/ui.py @@ -48,9 +48,11 @@ class SCENE_PT_network_settings(RenderButtonsPanel): col.itemR(scene.network_render, "mode") col.itemR(scene.network_render, "server_address") col.itemR(scene.network_render, "server_port") + col.itemR(scene.network_render, "path") if scene.network_render.mode == "RENDER_CLIENT": col.itemR(scene.network_render, "chunks") + col.itemR(scene.network_render, "priority") col.itemR(scene.network_render, "job_name") col.itemO("render.netclientsend", text="send job to server") bpy.types.register(SCENE_PT_network_settings) @@ -84,7 +86,7 @@ class SCENE_PT_network_slaves(RenderButtonsPanel): slave = netrender.slaves[netrender.active_slave_index] layout.itemL(text="Name: " + slave.name) - layout.itemL(text="Adress: " + slave.adress) + layout.itemL(text="Address: " + slave.address) layout.itemL(text="Seen: " + slave.last_seen) layout.itemL(text="Stats: " + slave.stats) @@ -119,7 +121,7 @@ class SCENE_PT_network_slaves_blacklist(RenderButtonsPanel): slave = netrender.slaves_blacklist[netrender.active_blacklisted_slave_index] layout.itemL(text="Name: " + slave.name) - layout.itemL(text="Adress: " + slave.adress) + layout.itemL(text="Address: " + slave.address) layout.itemL(text="Seen: " + slave.last_seen) layout.itemL(text="Stats: " + slave.stats) @@ -189,6 +191,12 @@ NetRenderSettings.IntProperty( attr="server_port", min=1, max=65535) +NetRenderSettings.StringProperty( attr="path", + name="Path", + description="Path for temporary files", + maxlen = 128, + default = "/tmp/") + NetRenderSettings.StringProperty( attr="job_name", name="Job name", description="Name of the job", @@ -202,6 +210,13 @@ NetRenderSettings.IntProperty( attr="chunks", 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", @@ -249,8 +264,8 @@ NetRenderSlave.StringProperty( attr="name", maxlen = 64, default = "") -NetRenderSlave.StringProperty( attr="adress", - name="Adress of the slave", +NetRenderSlave.StringProperty( attr="address", + name="Address of the slave", description="", maxlen = 64, default = "") diff --git a/release/io/netrender/utils.py b/release/io/netrender/utils.py index c158ff115fa..d64b6fcda1e 100644 --- a/release/io/netrender/utils.py +++ b/release/io/netrender/utils.py @@ -3,9 +3,9 @@ import sys, os import http, http.client, http.server, urllib import subprocess, shutil, time, hashlib -VERSION = b"0.3" +import netrender.model -PATH_PREFIX = "/tmp/" +VERSION = b"0.3" QUEUED = 0 DISPATCHED = 1 @@ -41,40 +41,46 @@ def clientVerifyVersion(conn): return True def clientSendJob(conn, scene, anim = False, chunks = 5): + netsettings = scene.network_render + job = netrender.model.RenderJob() if anim: - job_frame = "%i:%i" % (scene.start_frame, scene.end_frame) + for f in range(scene.start_frame, scene.end_frame + 1): + job.addFrame(f) else: - job_frame = "%i" % (scene.current_frame, ) - - blacklist = [] + job.addFrame(scene.current_frame) filename = bpy.data.filename + job.files.append(filename) - name = scene.network_render.job_name - + name = netsettings.job_name if name == "[default]": path, name = os.path.split(filename) - for slave in scene.network_render.slaves_blacklist: - blacklist.append(slave.id) - - blacklist = " ".join(blacklist) + job.name = name - headers = {"job-frame":job_frame, "job-name":name, "job-chunks": str(chunks), "slave-blacklist": blacklist} + for slave in scene.network_render.slaves_blacklist: + job.blacklist.append(slave.id) + + job.chunks = netsettings.chunks + job.priority = netsettings.priority # try to send path first - conn.request("POST", "job", filename, headers=headers) + conn.request("POST", "job", repr(job.serialize())) response = conn.getresponse() + job_id = response.getheader("job-id") + # if not found, send whole file if response.status == http.client.NOT_FOUND: f = open(bpy.data.filename, "rb") - conn.request("PUT", "file", f, headers=headers) + conn.request("PUT", "file", f, headers={"job-id": job_id}) f.close() response = conn.getresponse() - return response.getheader("job-id") + # server will reply with NOT_FOUD until all files are found + + return job_id def clientRequestResult(conn, scene, job_id): conn.request("GET", "render", headers={"job-id": job_id, "job-frame":str(scene.current_frame)})