forked from bartvdbraak/blender
netrender
- Patch by Olivier Amrein (prettying the web interface with css, fixing some notification bugs) - More error checks on the slave (better behavior when job is canceled) - Client: when using "Animate on Network" and canceling render midway, also cancel job. Use Send Job and Animate if you want a real background job.
This commit is contained in:
parent
54c9557b85
commit
5057ac80ee
@ -215,6 +215,8 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
|
|||||||
|
|
||||||
self.update_stats("", "Network render exporting")
|
self.update_stats("", "Network render exporting")
|
||||||
|
|
||||||
|
new_job = False
|
||||||
|
|
||||||
job_id = netsettings.job_id
|
job_id = netsettings.job_id
|
||||||
|
|
||||||
# reading back result
|
# reading back result
|
||||||
@ -225,6 +227,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
|
|||||||
response = conn.getresponse()
|
response = conn.getresponse()
|
||||||
|
|
||||||
if response.status == http.client.NO_CONTENT:
|
if response.status == http.client.NO_CONTENT:
|
||||||
|
new_job = True
|
||||||
netsettings.job_id = clientSendJob(conn, scene)
|
netsettings.job_id = clientSendJob(conn, scene)
|
||||||
requestResult(conn, job_id, scene.current_frame)
|
requestResult(conn, job_id, scene.current_frame)
|
||||||
|
|
||||||
@ -233,6 +236,13 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
|
|||||||
requestResult(conn, job_id, scene.current_frame)
|
requestResult(conn, job_id, scene.current_frame)
|
||||||
response = conn.getresponse()
|
response = conn.getresponse()
|
||||||
|
|
||||||
|
# cancel new jobs (animate on network) on break
|
||||||
|
if self.test_break() and new_job:
|
||||||
|
conn.request("POST", cancelURL(job_id))
|
||||||
|
response = conn.getresponse()
|
||||||
|
print( response.status, response.reason )
|
||||||
|
netsettings.job_id = 0
|
||||||
|
|
||||||
if response.status != http.client.OK:
|
if response.status != http.client.OK:
|
||||||
conn.close()
|
conn.close()
|
||||||
return
|
return
|
||||||
|
@ -611,6 +611,9 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||||
elif self.path == "/render":
|
elif self.path == "/render":
|
||||||
self.server.stats("", "Receiving render result")
|
self.server.stats("", "Receiving render result")
|
||||||
|
|
||||||
|
# need some message content here or the slave doesn't like it
|
||||||
|
self.wfile.write(bytes("foo", encoding='utf8'))
|
||||||
|
|
||||||
slave_id = self.headers['slave-id']
|
slave_id = self.headers['slave-id']
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ def get(handler):
|
|||||||
output("<title>")
|
output("<title>")
|
||||||
output(title)
|
output(title)
|
||||||
output("</title></head><body>")
|
output("</title></head><body>")
|
||||||
|
output("<link rel='stylesheet' href='/html/netrender.css' type='text/css'>")
|
||||||
|
|
||||||
|
|
||||||
def link(text, url):
|
def link(text, url):
|
||||||
return "<a href='%s'>%s</a>" % (url, text)
|
return "<a href='%s'>%s</a>" % (url, text)
|
||||||
@ -67,6 +69,13 @@ def get(handler):
|
|||||||
shutil.copyfileobj(f, handler.wfile)
|
shutil.copyfileobj(f, handler.wfile)
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
elif handler.path == "/html/netrender.css":
|
||||||
|
f = open(os.path.join(src_folder, "netrender.css"), 'rb')
|
||||||
|
|
||||||
|
handler.send_head(content = "text/css")
|
||||||
|
shutil.copyfileobj(f, handler.wfile)
|
||||||
|
|
||||||
|
f.close()
|
||||||
elif handler.path == "/html" or handler.path == "/":
|
elif handler.path == "/html" or handler.path == "/":
|
||||||
handler.send_head(content = "text/html")
|
handler.send_head(content = "text/html")
|
||||||
head("NetRender")
|
head("NetRender")
|
||||||
@ -90,7 +99,7 @@ def get(handler):
|
|||||||
startTable()
|
startTable()
|
||||||
headerTable(
|
headerTable(
|
||||||
" ",
|
" ",
|
||||||
" ",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"category",
|
"category",
|
||||||
"chunks",
|
"chunks",
|
||||||
@ -111,16 +120,17 @@ def get(handler):
|
|||||||
for job in handler.server.jobs:
|
for job in handler.server.jobs:
|
||||||
results = job.framesStatus()
|
results = job.framesStatus()
|
||||||
rowTable(
|
rowTable(
|
||||||
"""<button title="cancel job" onclick="request('/cancel_%s', null);">X</button>""" % job.id,
|
"""<button title="cancel job" onclick="request('/cancel_%s', null);">X</button>""" % job.id +
|
||||||
"""<button title="reset all frames" onclick="request('/resetall_%s_0', null);">R</button>""" % job.id,
|
"""<button title="reset all frames" onclick="request('/resetall_%s_0', null);">R</button>""" % job.id,
|
||||||
|
job.id,
|
||||||
link(job.name, "/html/job" + job.id),
|
link(job.name, "/html/job" + job.id),
|
||||||
job.category if job.category else "<i>None</i>",
|
job.category if job.category else "<i>None</i>",
|
||||||
str(job.chunks) +
|
str(job.chunks) +
|
||||||
"""<button title="increase priority" onclick="request('/edit_%s', "{'chunks': %i}");">+</button>""" % (job.id, job.chunks + 1) +
|
"""<button title="increase priority" onclick="request('/edit_%s', "{'chunks': %i}");">+</button>""" % (job.id, job.chunks + 1) +
|
||||||
"""<button title="decrease priority" onclick="request('/edit_%s', "{'chunks': %i}");" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
|
"""<button title="decrease priority" onclick="request('/edit_%s', "{'chunks': %i}");" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
|
||||||
str(job.priority) +
|
str(job.priority) +
|
||||||
"""<button title="increase priority" onclick="request('/edit_%s', "{'priority': %i}");">+</button>""" % (job.id, job.priority + 1) +
|
"""<button title="increase chunks size" onclick="request('/edit_%s', "{'priority': %i}");">+</button>""" % (job.id, job.priority + 1) +
|
||||||
"""<button title="decrease priority" onclick="request('/edit_%s', "{'priority': %i}");" %s>-</button>""" % (job.id, job.priority - 1, "disabled=True" if job.priority == 1 else ""),
|
"""<button title="decrease chunks size" onclick="request('/edit_%s', "{'priority': %i}");" %s>-</button>""" % (job.id, job.priority - 1, "disabled=True" if job.priority == 1 else ""),
|
||||||
"%0.1f%%" % (job.usage * 100),
|
"%0.1f%%" % (job.usage * 100),
|
||||||
"%is" % int(time.time() - job.last_dispatched),
|
"%is" % int(time.time() - job.last_dispatched),
|
||||||
job.statusText(),
|
job.statusText(),
|
||||||
|
51
release/scripts/io/netrender/netrender.css
Normal file
51
release/scripts/io/netrender/netrender.css
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
body {
|
||||||
|
background-color:#eee;
|
||||||
|
font-size:12px;
|
||||||
|
font-family: "Lucida Sans","Lucida Sans Unicode","Lucida Grande",Lucida,sans-serif;
|
||||||
|
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
/*text-decoration:none;*/
|
||||||
|
color:#666;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color:#000;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
background-color:#ddd;
|
||||||
|
font-size:120%
|
||||||
|
padding:5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
text-align:center;
|
||||||
|
border:0;
|
||||||
|
background-color:#ddd;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
thead{
|
||||||
|
font-size:90%;
|
||||||
|
color:#555;
|
||||||
|
background-color:#ccc;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
border:0;
|
||||||
|
padding:2px;
|
||||||
|
padding-left:10px;
|
||||||
|
padding-right:10px;
|
||||||
|
margin-left:20px
|
||||||
|
background-color:#ddd;
|
||||||
|
}
|
||||||
|
td:hover {
|
||||||
|
background-color:#ccc;
|
||||||
|
}
|
||||||
|
tr {
|
||||||
|
border:0;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
color: #111;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
@ -54,10 +54,9 @@ def slave_Info():
|
|||||||
|
|
||||||
def testCancel(conn, job_id, frame_number):
|
def testCancel(conn, job_id, frame_number):
|
||||||
conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)})
|
conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)})
|
||||||
response = conn.getresponse()
|
|
||||||
|
|
||||||
# cancelled if job isn't found anymore
|
# cancelled if job isn't found anymore
|
||||||
if response.status == http.client.NO_CONTENT:
|
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -125,7 +124,7 @@ def render_slave(engine, netsettings):
|
|||||||
job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
|
job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
|
||||||
print("Fullpath", job_full_path)
|
print("Fullpath", job_full_path)
|
||||||
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
|
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
|
||||||
engine.update_stats("", "Render File", main_file, "for job", job.id)
|
engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
|
||||||
|
|
||||||
for rfile in job.files[1:]:
|
for rfile in job.files[1:]:
|
||||||
print("\t", rfile.filepath)
|
print("\t", rfile.filepath)
|
||||||
@ -202,10 +201,12 @@ def render_slave(engine, netsettings):
|
|||||||
if stdout:
|
if stdout:
|
||||||
# (only need to update on one frame, they are linked
|
# (only need to update on one frame, they are linked
|
||||||
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
|
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
|
||||||
response = conn.getresponse()
|
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||||
|
continue
|
||||||
|
|
||||||
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
|
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
|
||||||
|
|
||||||
|
|
||||||
if status == 0: # non zero status is error
|
if status == 0: # non zero status is error
|
||||||
headers["job-result"] = str(DONE)
|
headers["job-result"] = str(DONE)
|
||||||
for frame in job.frames:
|
for frame in job.frames:
|
||||||
@ -216,17 +217,20 @@ def render_slave(engine, netsettings):
|
|||||||
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
|
f = open(JOB_PREFIX + "%06d" % frame.number + ".exr", 'rb')
|
||||||
conn.request("PUT", "/render", f, headers=headers)
|
conn.request("PUT", "/render", f, headers=headers)
|
||||||
f.close()
|
f.close()
|
||||||
response = conn.getresponse()
|
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||||
|
continue
|
||||||
elif job.type == netrender.model.JOB_PROCESS:
|
elif job.type == netrender.model.JOB_PROCESS:
|
||||||
conn.request("PUT", "/render", headers=headers)
|
conn.request("PUT", "/render", headers=headers)
|
||||||
response = conn.getresponse()
|
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
headers["job-result"] = str(ERROR)
|
headers["job-result"] = str(ERROR)
|
||||||
for frame in job.frames:
|
for frame in job.frames:
|
||||||
headers["job-frame"] = str(frame.number)
|
headers["job-frame"] = str(frame.number)
|
||||||
# send error result back to server
|
# send error result back to server
|
||||||
conn.request("PUT", "/render", headers=headers)
|
conn.request("PUT", "/render", headers=headers)
|
||||||
response = conn.getresponse()
|
if conn.getresponse().status == http.client.NO_CONTENT:
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
if timeout < MAX_TIMEOUT:
|
if timeout < MAX_TIMEOUT:
|
||||||
timeout += INCREMENT_TIMEOUT
|
timeout += INCREMENT_TIMEOUT
|
||||||
@ -240,4 +244,4 @@ def render_slave(engine, netsettings):
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
pass
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user