627 lines
23 KiB
Python
627 lines
23 KiB
Python
# ##### BEGIN GPL LICENSE BLOCK #####
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
# ##### END GPL LICENSE BLOCK #####
|
|
|
|
import bpy
|
|
import os
|
|
import time
|
|
|
|
import netrender
|
|
|
|
from netrender.utils import *
|
|
|
|
from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, CollectionProperty
|
|
|
|
VERSION = b"0.5"
|
|
|
|
PATH_PREFIX = "/tmp/"
|
|
|
|
LAST_ADDRESS_TEST = 0
|
|
ADDRESS_TEST_TIMEOUT = 30
|
|
|
|
def base_poll(cls, context):
|
|
rd = context.scene.render
|
|
return (rd.engine in cls.COMPAT_ENGINES)
|
|
|
|
|
|
def init_file():
|
|
if netrender.init_file != bpy.data.filepath:
|
|
netrender.init_file = bpy.data.filepath
|
|
netrender.init_data = True
|
|
netrender.valid_address = False
|
|
|
|
def init_data(netsettings):
|
|
init_file()
|
|
|
|
if netrender.init_data:
|
|
netrender.init_data = False
|
|
|
|
netsettings.active_slave_index = 0
|
|
while(len(netsettings.slaves) > 0):
|
|
netsettings.slaves.remove(0)
|
|
|
|
netsettings.active_blacklisted_slave_index = 0
|
|
while(len(netsettings.slaves_blacklist) > 0):
|
|
netsettings.slaves_blacklist.remove(0)
|
|
|
|
netsettings.active_job_index = 0
|
|
while(len(netsettings.jobs) > 0):
|
|
netsettings.jobs.remove(0)
|
|
|
|
def verify_address(netsettings, force=False):
|
|
global LAST_ADDRESS_TEST
|
|
init_file()
|
|
|
|
if force or LAST_ADDRESS_TEST + ADDRESS_TEST_TIMEOUT < time.time():
|
|
LAST_ADDRESS_TEST = time.time()
|
|
|
|
try:
|
|
conn = clientConnection(netsettings, scan = False, timeout = 1)
|
|
except:
|
|
conn = None
|
|
|
|
if conn:
|
|
netrender.valid_address = True
|
|
conn.close()
|
|
else:
|
|
netrender.valid_address = False
|
|
|
|
return netrender.valid_address
|
|
|
|
class NeedValidAddress():
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return super().poll(context) and verify_address(context.scene.network_render)
|
|
|
|
class NetRenderButtonsPanel():
|
|
bl_space_type = "PROPERTIES"
|
|
bl_region_type = "WINDOW"
|
|
bl_context = "render"
|
|
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
rd = context.scene.render
|
|
return rd.engine == 'NET_RENDER'
|
|
|
|
# Setting panel, use in the scene for now.
|
|
class RENDER_PT_network_settings(NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Network Settings"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return super().poll(context)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
verify_address(netsettings)
|
|
|
|
layout.prop(netsettings, "mode", expand=True)
|
|
|
|
if netsettings.mode in {'RENDER_MASTER', 'RENDER_SLAVE'}:
|
|
layout.operator("render.netclientstart", icon='PLAY')
|
|
|
|
layout.prop(netsettings, "path")
|
|
|
|
row = layout.row()
|
|
|
|
split = layout.split(factor=0.5)
|
|
|
|
col = split.column()
|
|
col.prop(netsettings, "server_address", text="Address")
|
|
|
|
col = split.column()
|
|
row = col.row()
|
|
row.prop(netsettings, "server_port", text="Port")
|
|
row.prop(netsettings, "use_ssl", text="SSL")
|
|
|
|
if netsettings.mode != "RENDER_MASTER":
|
|
layout.operator("render.netclientscan", icon='FILE_REFRESH', text="")
|
|
|
|
if not netrender.valid_address:
|
|
layout.label(text="No master at specified address")
|
|
|
|
|
|
if netsettings.use_ssl and netsettings.mode == "RENDER_MASTER":
|
|
layout.prop(netsettings, "cert_path", text="Certificate")
|
|
layout.prop(netsettings, "key_path", text="Key")
|
|
|
|
layout.operator("render.netclientweb", icon='QUESTION')
|
|
|
|
|
|
|
|
class RENDER_PT_network_slave_settings(NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Slave Settings"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
return super().poll(context) and scene.network_render.mode == "RENDER_SLAVE"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
rd = context.scene.render
|
|
netsettings = context.scene.network_render
|
|
|
|
layout.prop(netsettings, "slave_tags", text="Tags")
|
|
layout.prop(netsettings, "slave_render")
|
|
layout.prop(netsettings, "slave_bake")
|
|
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)
|
|
|
|
col = layout.column()
|
|
col.enabled = rd.threads_mode == 'FIXED'
|
|
col.prop(rd, "threads")
|
|
|
|
class RENDER_PT_network_master_settings(NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Master Settings"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
return super().poll(context) and scene.network_render.mode == "RENDER_MASTER"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
layout.prop(netsettings, "use_master_broadcast")
|
|
layout.prop(netsettings, "use_master_force_upload")
|
|
layout.prop(netsettings, "use_master_clear")
|
|
|
|
class RENDER_PT_network_job(NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Job Settings"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
verify_address(netsettings)
|
|
|
|
if netsettings.server_address != "[default]":
|
|
layout.operator("render.netclientanim", icon='RENDER_ANIMATION')
|
|
layout.operator("render.netclientsend", icon='FILE_BLEND')
|
|
layout.operator("render.netclientsendbake", icon='PHYSICS')
|
|
layout.operator("render.netclientsendframe", icon='RENDER_STILL')
|
|
if netsettings.job_id:
|
|
row = layout.row()
|
|
row.operator("render.render", text="Get Image", icon='RENDER_STILL')
|
|
row.operator("render.render", text="Get Animation", icon='RENDER_ANIMATION').animation = True
|
|
|
|
layout.prop(netsettings, "job_type", text="Type")
|
|
layout.prop(netsettings, "job_name", text="Name")
|
|
layout.prop(netsettings, "job_category", text="Category")
|
|
layout.prop(netsettings, "job_tags", text="Tags")
|
|
layout.prop(netsettings, "job_render_engine", text="Engine")
|
|
|
|
if netsettings.job_render_engine == "OTHER":
|
|
layout.prop(netsettings, "job_render_engine_other", text="Other Engine")
|
|
|
|
row = layout.row()
|
|
row.prop(netsettings, "priority")
|
|
row.prop(netsettings, "chunks")
|
|
|
|
if netsettings.job_type == "JOB_BLENDER":
|
|
layout.prop(netsettings, "save_before_job")
|
|
|
|
|
|
|
|
class RENDER_PT_network_job_vcs(NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "VCS Job Settings"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
return (super().poll(context)
|
|
and scene.network_render.mode == "RENDER_CLIENT"
|
|
and scene.network_render.job_type == "JOB_VCS")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
layout.operator("render.netclientvcsguess", icon='FILE_REFRESH', text="")
|
|
|
|
layout.prop(netsettings, "vcs_system")
|
|
layout.prop(netsettings, "vcs_revision")
|
|
layout.prop(netsettings, "vcs_rpath")
|
|
layout.prop(netsettings, "vcs_wpath")
|
|
|
|
class RENDER_PT_network_slaves(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Slaves Status"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
netsettings = context.scene.network_render
|
|
return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
row = layout.row()
|
|
row.template_list("UI_UL_list", "net_render_slaves", netsettings, "slaves",
|
|
netsettings, "active_slave_index", rows=2)
|
|
|
|
sub = row.column(align=True)
|
|
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
|
|
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
|
|
|
|
if len(netrender.slaves) > netsettings.active_slave_index >= 0:
|
|
layout.separator()
|
|
|
|
slave = netrender.slaves[netsettings.active_slave_index]
|
|
|
|
layout.label(text="Name: " + slave.name)
|
|
layout.label(text="Address: " + slave.address[0])
|
|
layout.label(text="Seen: " + time.ctime(slave.last_seen))
|
|
layout.label(text="Stats: " + slave.stats)
|
|
|
|
class RENDER_PT_network_slaves_blacklist(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Slaves Blacklist"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
netsettings = context.scene.network_render
|
|
return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
row = layout.row()
|
|
row.template_list("UI_UL_list", "net_render_slaves_blacklist", netsettings, "slaves_blacklist",
|
|
netsettings, "active_blacklisted_slave_index", rows=2)
|
|
|
|
sub = row.column(align=True)
|
|
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
|
|
|
|
if len(netrender.blacklist) > netsettings.active_blacklisted_slave_index >= 0:
|
|
layout.separator()
|
|
|
|
slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
|
|
|
|
layout.label(text="Name: " + slave.name)
|
|
layout.label(text="Address: " + slave.address[0])
|
|
layout.label(text="Seen: " + time.ctime(slave.last_seen))
|
|
layout.label(text="Stats: " + slave.stats)
|
|
|
|
class RENDER_PT_network_jobs(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Jobs"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
netsettings = context.scene.network_render
|
|
return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
netsettings = context.scene.network_render
|
|
|
|
row = layout.row()
|
|
row.template_list("UI_UL_list", "net_render", netsettings, "jobs", netsettings, "active_job_index", rows=2)
|
|
|
|
sub = row.column(align=True)
|
|
sub.operator("render.netclientstatus", icon='FILE_REFRESH', text="")
|
|
sub.operator("render.netclientcancel", icon='ZOOMOUT', text="")
|
|
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
|
|
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
|
|
|
|
if len(netrender.jobs) > netsettings.active_job_index >= 0:
|
|
layout.separator()
|
|
|
|
job = netrender.jobs[netsettings.active_job_index]
|
|
|
|
layout.label(text="Name: %s" % job.name)
|
|
layout.label(text="Length: %04i" % len(job))
|
|
layout.label(text="Done: %04i" % job.results[netrender.model.FRAME_DONE])
|
|
layout.label(text="Error: %04i" % job.results[netrender.model.FRAME_ERROR])
|
|
|
|
import bl_ui.properties_output as properties_output
|
|
class RENDER_PT_network_output(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
|
|
bl_label = "Output"
|
|
COMPAT_ENGINES = {'NET_RENDER'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
netsettings = context.scene.network_render
|
|
return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
|
|
|
|
draw = properties_output.RENDER_PT_output.draw
|
|
|
|
|
|
class NetRenderSlave(bpy.types.PropertyGroup):
|
|
@classmethod
|
|
def register(NetRenderSlave):
|
|
|
|
NetRenderSlave.name = StringProperty(
|
|
name="Name of the slave",
|
|
description="",
|
|
maxlen = 64,
|
|
default = "")
|
|
|
|
class NetRenderJob(bpy.types.PropertyGroup):
|
|
@classmethod
|
|
def register(NetRenderJob):
|
|
|
|
NetRenderJob.name = StringProperty(
|
|
name="Name of the job",
|
|
description="",
|
|
maxlen = 128,
|
|
default = "")
|
|
|
|
class NetRenderSettings(bpy.types.PropertyGroup):
|
|
@classmethod
|
|
def register(NetRenderSettings):
|
|
|
|
def address_update_callback(self, context):
|
|
netsettings = context.scene.network_render
|
|
verify_address(netsettings, True)
|
|
|
|
NetRenderSettings.server_address = StringProperty(
|
|
name="Server address",
|
|
description="IP or name of the master render server",
|
|
maxlen = 128,
|
|
default = "[default]",
|
|
update = address_update_callback)
|
|
|
|
NetRenderSettings.server_port = IntProperty(
|
|
name="Server port",
|
|
description="port of the master render server",
|
|
default = 8000,
|
|
min=1,
|
|
max=65535)
|
|
|
|
NetRenderSettings.use_master_broadcast = BoolProperty(
|
|
name="Broadcast",
|
|
description="broadcast master server address on local network",
|
|
default = True)
|
|
NetRenderSettings.use_ssl = BoolProperty(
|
|
name="use ssl",
|
|
description="use ssl encryption for communication",
|
|
default = False)
|
|
NetRenderSettings.cert_path = StringProperty(
|
|
name="CertPath",
|
|
description="Path to ssl certificate",
|
|
maxlen = 128,
|
|
default = "",
|
|
subtype='FILE_PATH')
|
|
NetRenderSettings.key_path = StringProperty(
|
|
name="key",
|
|
description="Path to ssl key file",
|
|
maxlen = 128,
|
|
default = "",
|
|
subtype='FILE_PATH')
|
|
|
|
NetRenderSettings.use_slave_clear = BoolProperty(
|
|
name="Clear on exit",
|
|
description="delete downloaded files on exit",
|
|
default = True)
|
|
|
|
NetRenderSettings.use_slave_thumb = BoolProperty(
|
|
name="Generate thumbnails",
|
|
description="Generate thumbnails on slaves instead of master",
|
|
default = False)
|
|
|
|
NetRenderSettings.slave_tags = StringProperty(
|
|
name="Tags",
|
|
description="Tags to associate with the slave (semi-colon separated)",
|
|
maxlen = 256,
|
|
default = "")
|
|
|
|
NetRenderSettings.use_slave_output_log = BoolProperty(
|
|
name="Output render log on console",
|
|
description="Output render text log to console as well as sending it to the master",
|
|
default = True)
|
|
|
|
NetRenderSettings.slave_render = BoolProperty(
|
|
name="Render on slave",
|
|
description="Use slave for render jobs",
|
|
default = True)
|
|
|
|
NetRenderSettings.slave_bake = BoolProperty(
|
|
name="Bake on slave",
|
|
description="Use slave for baking jobs",
|
|
default = True)
|
|
|
|
NetRenderSettings.use_master_clear = BoolProperty(
|
|
name="Clear on exit",
|
|
description="Delete saved files on exit",
|
|
default = False)
|
|
|
|
NetRenderSettings.use_master_force_upload = BoolProperty(
|
|
name="Force Dependency Upload",
|
|
description="Force client to upload dependency files to master",
|
|
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.path = StringProperty(
|
|
name="Path",
|
|
description="Path for temporary files",
|
|
maxlen = 128,
|
|
default = default_path,
|
|
subtype='FILE_PATH')
|
|
|
|
NetRenderSettings.job_type = EnumProperty(
|
|
items=(
|
|
("JOB_BLENDER", "Blender", "Standard Blender Job"),
|
|
("JOB_PROCESS", "Process", "Custom Process Job"),
|
|
("JOB_VCS", "VCS", "Version Control System Managed Job"),
|
|
),
|
|
name="Job Type",
|
|
description="Type of render job",
|
|
default="JOB_BLENDER")
|
|
|
|
NetRenderSettings.job_name = StringProperty(
|
|
name="Job name",
|
|
description="Name of the job",
|
|
maxlen = 128,
|
|
default = "[default]")
|
|
|
|
NetRenderSettings.job_category = StringProperty(
|
|
name="Job category",
|
|
description="Category of the job",
|
|
maxlen = 128,
|
|
default = "")
|
|
|
|
NetRenderSettings.job_tags = StringProperty(
|
|
name="Tags",
|
|
description="Tags to associate with the job (semi-colon separated)",
|
|
maxlen = 256,
|
|
default = "")
|
|
|
|
NetRenderSettings.job_render_engine = EnumProperty(
|
|
items = (
|
|
("BLENDER_RENDER", "BLENDER", "Standard Blender Render"),
|
|
("CYCLES", "CYCLES", "Cycle Render"),
|
|
("OTHER", "OTHER", "Other non-default Render"),
|
|
),
|
|
name="render",
|
|
description="Render engine used to render this job",
|
|
default="BLENDER_RENDER")
|
|
|
|
NetRenderSettings.job_render_engine_other = StringProperty(
|
|
name="Render engine",
|
|
description="Render engine other than the builtin defaults (POVRAY_RENDER, ...)",
|
|
maxlen = 128,
|
|
default = "")
|
|
|
|
NetRenderSettings.save_before_job = BoolProperty(
|
|
name="Save Before Job",
|
|
description="Save current file before sending a job",
|
|
default = False)
|
|
|
|
NetRenderSettings.chunks = IntProperty(
|
|
name="Chunks",
|
|
description="Number of frame to dispatch to each slave in one chunk",
|
|
default = 5,
|
|
min=1,
|
|
max=65535)
|
|
|
|
NetRenderSettings.priority = IntProperty(
|
|
name="Priority",
|
|
description="Priority of the job",
|
|
default = 1,
|
|
min=1,
|
|
max=10)
|
|
|
|
NetRenderSettings.vcs_wpath = StringProperty(
|
|
name="Working Copy",
|
|
description="Path of the local working copy",
|
|
maxlen = 1024,
|
|
default = "")
|
|
|
|
NetRenderSettings.vcs_rpath = StringProperty(
|
|
name="Remote Path",
|
|
description="Path of the server copy (protocol specific)",
|
|
maxlen = 1024,
|
|
default = "")
|
|
|
|
NetRenderSettings.vcs_revision = StringProperty(
|
|
name="Revision",
|
|
description="Revision for this job",
|
|
maxlen = 256,
|
|
default = "")
|
|
|
|
NetRenderSettings.vcs_system = EnumProperty(
|
|
items= netrender.versioning.ITEMS,
|
|
name="VCS mode",
|
|
description="Version Control System",
|
|
default=netrender.versioning.ITEMS[0][0])
|
|
|
|
NetRenderSettings.job_id = StringProperty(
|
|
name="Network job id",
|
|
description="id of the last sent render job",
|
|
maxlen = 64,
|
|
default = "")
|
|
|
|
NetRenderSettings.active_slave_index = IntProperty(
|
|
name="Index of the active slave",
|
|
description="",
|
|
default = -1,
|
|
min= -1,
|
|
max=65535)
|
|
|
|
NetRenderSettings.active_blacklisted_slave_index = IntProperty(
|
|
name="Index of the active slave",
|
|
description="",
|
|
default = -1,
|
|
min= -1,
|
|
max=65535)
|
|
|
|
NetRenderSettings.active_job_index = IntProperty(
|
|
name="Index of the active job",
|
|
description="",
|
|
default = -1,
|
|
min= -1,
|
|
max=65535)
|
|
|
|
NetRenderSettings.mode = EnumProperty(
|
|
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.slaves = CollectionProperty(type=NetRenderSlave, name="Slaves", description="")
|
|
NetRenderSettings.slaves_blacklist = CollectionProperty(type=NetRenderSlave, name="Slaves Blacklist", description="")
|
|
NetRenderSettings.jobs = CollectionProperty(type=NetRenderJob, name="Job List", description="")
|
|
|
|
bpy.types.Scene.network_render = PointerProperty(type=NetRenderSettings, name="Network Render", description="Network Render Settings")
|
|
|
|
@classmethod
|
|
def unregister(cls):
|
|
del bpy.types.Scene.network_render
|