diff options
Diffstat (limited to 'release/scripts/io/netrender/client.py')
-rw-r--r-- | release/scripts/io/netrender/client.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py new file mode 100644 index 00000000000..65b2937867f --- /dev/null +++ b/release/scripts/io/netrender/client.py @@ -0,0 +1,203 @@ +import bpy +import sys, os, re +import http, http.client, http.server, urllib +import subprocess, shutil, time, hashlib + +import netrender.slave as slave +import netrender.master as master +from netrender.utils import * + + +def clientSendJob(conn, scene, anim = False, chunks = 5): + netsettings = scene.network_render + job = netrender.model.RenderJob() + + if anim: + for f in range(scene.start_frame, scene.end_frame + 1): + job.addFrame(f) + else: + job.addFrame(scene.current_frame) + + filename = bpy.data.filename + job.addFile(filename) + + job_name = netsettings.job_name + path, name = os.path.split(filename) + if job_name == "[default]": + job_name = name + + ########################### + # LIBRARIES + ########################### + for lib in bpy.data.libraries: + lib_path = lib.filename + + if lib_path.startswith("//"): + lib_path = path + os.sep + lib_path[2:] + + job.addFile(lib_path) + + ########################### + # POINT CACHES + ########################### + + root, ext = os.path.splitext(name) + cache_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that + + if os.path.exists(cache_path): + caches = {} + pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)_[0-9]+\.bphys") + for cache_file in sorted(os.listdir(cache_path)): + match = pattern.match(cache_file) + + if match: + cache_id = match.groups()[0] + cache_frame = int(match.groups()[1]) + + cache_files = caches.get(cache_id, []) + cache_files.append((cache_frame, cache_file)) + caches[cache_id] = cache_files + + for cache in caches.values(): + cache.sort() + + if len(cache) == 1: + cache_frame, cache_file = cache[0] + job.addFile(cache_path + cache_file, cache_frame, cache_frame) + else: + for i in range(len(cache)): + current_item = cache[i] + next_item = cache[i+1] if i + 1 < len(cache) else None + previous_item = cache[i - 1] if i > 0 else None + + current_frame, current_file = current_item + + if not next_item and not previous_item: + job.addFile(cache_path + current_file, current_frame, current_frame) + elif next_item and not previous_item: + next_frame = next_item[0] + job.addFile(cache_path + current_file, current_frame, next_frame - 1) + elif not next_item and previous_item: + previous_frame = previous_item[0] + job.addFile(cache_path + current_file, previous_frame + 1, current_frame) + else: + next_frame = next_item[0] + previous_frame = previous_item[0] + job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1) + + ########################### + # IMAGES + ########################### + for image in bpy.data.images: + if image.source == "FILE" and not image.packed_file: + job.addFile(image.filename) + + # print(job.files) + + job.name = job_name + + 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", repr(job.serialize())) + response = conn.getresponse() + + job_id = response.getheader("job-id") + + # if not ACCEPTED (but not processed), send files + if response.status == http.client.ACCEPTED: + for filepath, start, end in job.files: + f = open(filepath, "rb") + conn.request("PUT", "/file", f, headers={"job-id": job_id, "job-file": filepath}) + f.close() + response = conn.getresponse() + + # server will reply with NOT_FOUD until all files are found + + return job_id + +def requestResult(conn, job_id, frame): + conn.request("GET", "/render", headers={"job-id": job_id, "job-frame":str(frame)}) + +@rnaType +class NetworkRenderEngine(bpy.types.RenderEngine): + __idname__ = 'NET_RENDER' + __label__ = "Network Render" + def render(self, scene): + if scene.network_render.mode == "RENDER_CLIENT": + self.render_client(scene) + elif scene.network_render.mode == "RENDER_SLAVE": + self.render_slave(scene) + elif scene.network_render.mode == "RENDER_MASTER": + self.render_master(scene) + else: + print("UNKNOWN OPERATION MODE") + + def render_master(self, scene): + netsettings = scene.network_render + + address = "" if netsettings.server_address == "[default]" else netsettings.server_address + + master.runMaster((address, netsettings.server_port), netsettings.server_broadcast, netsettings.path, self.update_stats, self.test_break) + + + def render_slave(self, scene): + slave.render_slave(self, scene) + + def render_client(self, scene): + netsettings = scene.network_render + self.update_stats("", "Network render client initiation") + + + conn = clientConnection(scene) + + if conn: + # Sending file + + self.update_stats("", "Network render exporting") + + job_id = netsettings.job_id + + # reading back result + + self.update_stats("", "Network render waiting for results") + + requestResult(conn, job_id, scene.current_frame) + response = conn.getresponse() + + if response.status == http.client.NO_CONTENT: + netsettings.job_id = clientSendJob(conn, scene) + requestResult(conn, job_id, scene.current_frame) + + while response.status == http.client.ACCEPTED and not self.test_break(): + time.sleep(1) + requestResult(conn, job_id, scene.current_frame) + response = conn.getresponse() + + if response.status != http.client.OK: + conn.close() + return + + r = scene.render_data + 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") + buf = response.read(1024) + + while buf: + f.write(buf) + buf = response.read(1024) + + f.close() + + result = self.begin_result(0, 0, x, y) + result.load_from_file(netsettings.path + "output.exr", 0, 0) + self.end_result(result) + + conn.close() + |