diff options
author | Martijn Berger <martijn.berger@gmail.com> | 2013-12-07 05:29:53 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2013-12-07 15:26:58 +0400 |
commit | 85a0c5d4e1030a5fa95ad7450958a1b0fa033381 (patch) | |
tree | 8e43b6167b7e4df8fad2a4f0f39c82fe5b3c2807 | |
parent | 5c07f62fabc9b6a20c85ec5ea5e15a99353bd091 (diff) |
Cycles: network render code updated for latest changes and improved
This actually works somewhat now, although viewport rendering is broken and any
kind of network error or connection failure will kill Blender.
* Experimental WITH_CYCLES_NETWORK cmake option
* Networked Device is shown as an option next to CPU and GPU Compute
* Various updates to work with the latest Cycles code
* Locks and thread safety for RPC calls and tiles
* Refactored pointer mapping code
* Fix error in CPU brand string retrieval code
This includes work by Doug Gale, Martijn Berger and Brecht Van Lommel.
Reviewers: brecht
Differential Revision: http://developer.blender.org/D36
22 files changed, 487 insertions, 149 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ff10d9377b..abca0eeac6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -737,6 +737,9 @@ if(UNIX AND NOT APPLE) if(WITH_INTERNATIONAL) list(APPEND __boost_packages locale) endif() + if(WITH_CYCLES_NETWORK) + list(APPEND __boost_packages serialization) + endif() find_package(Boost 1.48 COMPONENTS ${__boost_packages}) unset(__boost_packages) if(Boost_USE_STATIC_LIBS AND WITH_BOOST_ICU) @@ -1700,6 +1703,9 @@ elseif(APPLE) list(APPEND BOOST_LIBRARIES boost_locale-mt) set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -liconv") # boost_locale needs it ! endif() + if(WITH_CYCLES_NETWORK) + list(APPEND BOOST_LIBRARIES boost_serialization-mt) + endif() set(BOOST_LIBPATH ${BOOST}/lib) set(BOOST_DEFINITIONS) endif() diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index ada5ea55fb2..8a81ddde1e1 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -30,6 +30,10 @@ set(LIBRARIES ${TIFF_LIBRARY} ) +if(UNIX) + list(APPEND LIBRARIES dl) +endif() + if(WIN32) list(APPEND LIBRARIES ${PTHREADS_LIBRARIES}) endif() diff --git a/intern/cycles/app/cycles_server.cpp b/intern/cycles/app/cycles_server.cpp index e80fc0cb95f..f4cacb2d001 100644 --- a/intern/cycles/app/cycles_server.cpp +++ b/intern/cycles/app/cycles_server.cpp @@ -35,6 +35,7 @@ int main(int argc, const char **argv) string devicelist = ""; string devicename = "cpu"; bool list = false; + int threads = 0; vector<DeviceType>& types = Device::available_types(); @@ -51,6 +52,7 @@ int main(int argc, const char **argv) ap.options ("Usage: cycles_server [options]", "--device %s", &devicename, ("Devices to use: " + devicelist).c_str(), "--list-devices", &list, "List information about all available devices", + "--threads %d", &threads, "Number of threads to use for CPU device", NULL); if(ap.parse(argc, argv) < 0) { @@ -84,11 +86,11 @@ int main(int argc, const char **argv) } } - TaskScheduler::init(); + TaskScheduler::init(threads); while(1) { Stats stats; - Device *device = Device::create(device_info, stats); + Device *device = Device::create(device_info, stats, true); printf("Cycles Server with device: %s\n", device->info.description.c_str()); device->server_run(); delete device; diff --git a/intern/cycles/blender/CCL_api.h b/intern/cycles/blender/CCL_api.h index 29d8ed0d98e..6532315cf39 100644 --- a/intern/cycles/blender/CCL_api.h +++ b/intern/cycles/blender/CCL_api.h @@ -30,7 +30,7 @@ typedef struct CCLDeviceInfo { int value; } CCLDeviceInfo; -CCLDeviceInfo *CCL_compute_device_list(int opencl); +CCLDeviceInfo *CCL_compute_device_list(int device_type); /* create python module _cycles used by addon */ diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 3f15e232de7..66dc5e78e5a 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -88,3 +88,7 @@ def available_devices(): def with_osl(): import _cycles return _cycles.with_osl + +def with_network(): + import _cycles + return _cycles.with_network diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 791f1ed51fb..f5c052e7f0c 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -25,9 +25,15 @@ from bpy.props import (BoolProperty, # enums +import _cycles + enum_devices = ( - ('CPU', "CPU", "Use CPU for rendering"), - ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences")) + ('CPU', "CPU", "Use CPU for rendering"), + ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"), + ) + +if _cycles.with_network: + enum_devices += (('NETWORK', "Networked Device", "Use networked device for rendering"),) enum_feature_set = ( ('SUPPORTED', "Supported", "Only use finished and supported features"), diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 14e78c4bf1f..42d5e011b83 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1254,6 +1254,8 @@ def draw_device(self, context): layout.prop(cscene, "device") elif device_type == 'OPENCL': layout.prop(cscene, "device") + elif device_type == 'NETWORK': + layout.prop(cscene, "device") if engine.with_osl() and (cscene.device == 'CPU' or device_type == 'NONE'): layout.prop(cscene, "shading_system") diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 71c84869ff6..8e6bcaee350 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -482,12 +482,34 @@ void *CCL_python_module_init() Py_INCREF(Py_False); #endif +#ifdef WITH_NETWORK + PyModule_AddObject(mod, "with_network", Py_True); + Py_INCREF(Py_True); +#else /* WITH_NETWORK */ + PyModule_AddObject(mod, "with_network", Py_False); + Py_INCREF(Py_False); +#endif /* WITH_NETWORK */ + return (void*)mod; } -CCLDeviceInfo *CCL_compute_device_list(int opencl) +CCLDeviceInfo *CCL_compute_device_list(int device_type) { - ccl::DeviceType type = (opencl)? ccl::DEVICE_OPENCL: ccl::DEVICE_CUDA; + ccl::DeviceType type; + switch(device_type) { + case 0: + type = ccl::DEVICE_CUDA; + break; + case 1: + type = ccl::DEVICE_OPENCL; + break; + case 2: + type = ccl::DEVICE_NETWORK; + break; + default: + type = ccl::DEVICE_NONE; + break; + } return ccl::compute_device_list(type); } diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt index 920223dd8a4..825e82209aa 100644 --- a/intern/cycles/device/CMakeLists.txt +++ b/intern/cycles/device/CMakeLists.txt @@ -26,7 +26,7 @@ set(SRC device_task.cpp ) -if(WITH_NETWORK) +if(WITH_CYCLES_NETWORK) list(APPEND SRC device_network.cpp ) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 5c771aa1c8b..6283e34f563 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -127,7 +127,7 @@ Device *Device::create(DeviceInfo& info, Stats &stats, bool background) switch(info.type) { case DEVICE_CPU: - device = device_cpu_create(info, stats); + device = device_cpu_create(info, stats, background); break; #ifdef WITH_CUDA case DEVICE_CUDA: @@ -159,9 +159,6 @@ Device *Device::create(DeviceInfo& info, Stats &stats, bool background) return NULL; } - if(device) - device->info = info; - return device; } diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 18868d19a85..bd309e35788 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -71,7 +71,7 @@ public: class Device { protected: - Device(Stats &stats_) : stats(stats_) {} + Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), info(info_), stats(stats_) {} bool background; string error_msg; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 85a7b9c186d..e084116c72d 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -45,11 +45,13 @@ class CPUDevice : public Device public: TaskPool task_pool; KernelGlobals kernel_globals; + #ifdef WITH_OSL OSLGlobals osl_globals; #endif - CPUDevice(Stats &stats) : Device(stats) + CPUDevice(DeviceInfo& info, Stats &stats, bool background) + : Device(info, stats, background) { #ifdef WITH_OSL kernel_globals.osl = &osl_globals; @@ -401,9 +403,9 @@ public: } }; -Device *device_cpu_create(DeviceInfo& info, Stats &stats) +Device *device_cpu_create(DeviceInfo& info, Stats &stats, bool background) { - return new CPUDevice(stats); + return new CPUDevice(info, stats, background); } void device_cpu_info(vector<DeviceInfo>& devices) diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 4ce7f6fd729..8db915f769c 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -171,7 +171,8 @@ public: cuda_assert(cuCtxSetCurrent(NULL)); } - CUDADevice(DeviceInfo& info, Stats &stats, bool background_) : Device(stats) + CUDADevice(DeviceInfo& info, Stats &stats, bool background_) + : Device(info, stats, background_) { first_error = true; background = background_; diff --git a/intern/cycles/device/device_intern.h b/intern/cycles/device/device_intern.h index d667478beed..7eb66c25a81 100644 --- a/intern/cycles/device/device_intern.h +++ b/intern/cycles/device/device_intern.h @@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN class Device; -Device *device_cpu_create(DeviceInfo& info, Stats &stats); +Device *device_cpu_create(DeviceInfo& info, Stats &stats, bool background); Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background); Device *device_cuda_create(DeviceInfo& info, Stats &stats, bool background); Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address); diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 4df0fdbd4c7..27b9de0769e 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -45,25 +45,24 @@ public: device_ptr unique_ptr; MultiDevice(DeviceInfo& info, Stats &stats, bool background_) - : Device(stats), unique_ptr(1) + : Device(info, stats, background_), unique_ptr(1) { Device *device; - background = background_; foreach(DeviceInfo& subinfo, info.multi_devices) { device = Device::create(subinfo, stats, background); devices.push_back(SubDevice(device)); } -#if 0 //def WITH_NETWORK +#ifdef WITH_NETWORK /* try to add network devices */ ServerDiscovery discovery(true); time_sleep(1.0); - list<string> servers = discovery.get_server_list(); + vector<string> servers = discovery.get_server_list(); foreach(string& server, servers) { - device = device_network_create(info, server.c_str()); + device = device_network_create(info, stats, server.c_str()); if(device) devices.push_back(SubDevice(device)); } diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 23c1a10fa0a..90339b89cce 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -20,9 +20,25 @@ #include "util_foreach.h" +#if defined(WITH_NETWORK) + CCL_NAMESPACE_BEGIN -#ifdef WITH_NETWORK +typedef map<device_ptr, device_ptr> PtrMap; +typedef vector<uint8_t> DataVector; +typedef map<device_ptr, DataVector> DataMap; + +/* tile list */ +typedef vector<RenderTile> TileList; + +/* search a list of tiles and find the one that matches the passed render tile */ +static TileList::iterator tile_list_find(TileList& tile_list, RenderTile& tile) +{ + for(TileList::iterator it = tile_list.begin(); it != tile_list.end(); ++it) + if(tile.x == it->x && tile.y == it->y && tile.start_sample == it->start_sample) + return it; + return tile_list.end(); +} class NetworkDevice : public Device { @@ -32,8 +48,10 @@ public: device_ptr mem_counter; DeviceTask the_task; /* todo: handle multiple tasks */ - NetworkDevice(Stats &stats, const char *address) - : Device(stats), socket(io_service) + thread_mutex rpc_lock; + + NetworkDevice(DeviceInfo& info, Stats &stats, const char *address) + : Device(info, stats, true), socket(io_service) { stringstream portstr; portstr << SERVER_PORT; @@ -64,6 +82,8 @@ public: void mem_alloc(device_memory& mem, MemoryType type) { + thread_scoped_lock lock(rpc_lock); + mem.device_pointer = ++mem_counter; RPCSend snd(socket, "mem_alloc"); @@ -75,6 +95,8 @@ public: void mem_copy_to(device_memory& mem) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "mem_copy_to"); snd.add(mem); @@ -84,6 +106,10 @@ public: void mem_copy_from(device_memory& mem, int y, int w, int h, int elem) { + thread_scoped_lock lock(rpc_lock); + + size_t data_size = mem.memory_size(); + RPCSend snd(socket, "mem_copy_from"); snd.add(mem); @@ -94,11 +120,13 @@ public: snd.write(); RPCReceive rcv(socket); - rcv.read_buffer((void*)mem.data_pointer, mem.memory_size()); + rcv.read_buffer((void*)mem.data_pointer, data_size); } void mem_zero(device_memory& mem) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "mem_zero"); snd.add(mem); @@ -108,6 +136,8 @@ public: void mem_free(device_memory& mem) { if(mem.device_pointer) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "mem_free"); snd.add(mem); @@ -119,6 +149,8 @@ public: void const_copy_to(const char *name, void *host, size_t size) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "const_copy_to"); string name_string(name); @@ -131,6 +163,8 @@ public: void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic) { + thread_scoped_lock lock(rpc_lock); + mem.device_pointer = ++mem_counter; RPCSend snd(socket, "tex_alloc"); @@ -148,6 +182,8 @@ public: void tex_free(device_memory& mem) { if(mem.device_pointer) { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "tex_free"); snd.add(mem); @@ -157,8 +193,25 @@ public: } } + bool load_kernels(bool experimental) + { + thread_scoped_lock lock(rpc_lock); + + RPCSend snd(socket, "load_kernels"); + snd.add(experimental); + snd.write(); + + bool result; + RPCReceive rcv(socket); + rcv.read(result); + + return result; + } + void task_add(DeviceTask& task) { + thread_scoped_lock lock(rpc_lock); + the_task = task; RPCSend snd(socket, "task_add"); @@ -168,55 +221,73 @@ public: void task_wait() { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "task_wait"); snd.write(); - list<RenderTile> the_tiles; + lock.unlock(); + + TileList the_tiles; /* todo: run this threaded for connecting to multiple clients */ for(;;) { - RPCReceive rcv(socket); RenderTile tile; + lock.lock(); + RPCReceive rcv(socket); + if(rcv.name == "acquire_tile") { + lock.unlock(); + /* todo: watch out for recursive calls! */ if(the_task.acquire_tile(this, tile)) { /* write return as bool */ the_tiles.push_back(tile); + lock.lock(); RPCSend snd(socket, "acquire_tile"); snd.add(tile); snd.write(); + lock.unlock(); } else { + lock.lock(); RPCSend snd(socket, "acquire_tile_none"); snd.write(); + lock.unlock(); } } else if(rcv.name == "release_tile") { rcv.read(tile); + lock.unlock(); - for(list<RenderTile>::iterator it = the_tiles.begin(); it != the_tiles.end(); it++) { - if(tile.x == it->x && tile.y == it->y && tile.start_sample == it->start_sample) { - tile.buffers = it->buffers; - the_tiles.erase(it); - break; - } + TileList::iterator it = tile_list_find(the_tiles, tile); + if (it != the_tiles.end()) { + tile.buffers = it->buffers; + the_tiles.erase(it); } assert(tile.buffers != NULL); the_task.release_tile(tile); + lock.lock(); RPCSend snd(socket, "release_tile"); snd.write(); + lock.unlock(); } - else if(rcv.name == "task_wait_done") + else if(rcv.name == "task_wait_done") { + lock.unlock(); break; + } + else + lock.unlock(); } } void task_cancel() { + thread_scoped_lock lock(rpc_lock); RPCSend snd(socket, "task_cancel"); snd.write(); } @@ -224,7 +295,7 @@ public: Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address) { - return new NetworkDevice(stats, address); + return new NetworkDevice(info, stats, address); } void device_network_info(vector<DeviceInfo>& devices) @@ -243,8 +314,10 @@ void device_network_info(vector<DeviceInfo>& devices) class DeviceServer { public: + thread_mutex rpc_lock; + DeviceServer(Device *device_, tcp::socket& socket_) - : device(device_), socket(socket_) + : device(device_), socket(socket_), stop(false), blocked_waiting(false) { } @@ -252,56 +325,151 @@ public: { /* receive remote function calls */ for(;;) { - RPCReceive rcv(socket); + listen_step(); - if(rcv.name == "stop") + if(stop) break; - - process(rcv); } } protected: - void process(RPCReceive& rcv) + void listen_step() + { + thread_scoped_lock lock(rpc_lock); + RPCReceive rcv(socket); + + if(rcv.name == "stop") + stop = true; + else + process(rcv, lock); + } + + /* create a memory buffer for a device buffer and insert it into mem_data */ + DataVector &data_vector_insert(device_ptr client_pointer, size_t data_size) + { + /* create a new DataVector and insert it into mem_data */ + pair<DataMap::iterator,bool> data_ins = mem_data.insert( + DataMap::value_type(client_pointer, DataVector())); + + /* make sure it was a unique insertion */ + assert(data_ins.second); + + /* get a reference to the inserted vector */ + DataVector &data_v = data_ins.first->second; + + /* size the vector */ + data_v.resize(data_size); + + return data_v; + } + + DataVector &data_vector_find(device_ptr client_pointer) { - // fprintf(stderr, "receive process %s\n", rcv.name.c_str()); + DataMap::iterator i = mem_data.find(client_pointer); + assert(i != mem_data.end()); + return i->second; + } + + /* setup mapping and reverse mapping of client_pointer<->real_pointer */ + void pointer_mapping_insert(device_ptr client_pointer, device_ptr real_pointer) + { + pair<PtrMap::iterator,bool> mapins; + + /* insert mapping from client pointer to our real device pointer */ + mapins = ptr_map.insert(PtrMap::value_type(client_pointer, real_pointer)); + assert(mapins.second); + + /* insert reverse mapping from real our device pointer to client pointer */ + mapins = ptr_imap.insert(PtrMap::value_type(real_pointer, client_pointer)); + assert(mapins.second); + } + + device_ptr device_ptr_from_client_pointer(device_ptr client_pointer) + { + PtrMap::iterator i = ptr_map.find(client_pointer); + assert(i != ptr_map.end()); + return i->second; + } + + device_ptr device_ptr_from_client_pointer_erase(device_ptr client_pointer) + { + PtrMap::iterator i = ptr_map.find(client_pointer); + assert(i != ptr_map.end()); + + device_ptr result = i->second; + /* erase the mapping */ + ptr_map.erase(i); + + /* erase the reverse mapping */ + PtrMap::iterator irev = ptr_imap.find(result); + assert(irev != ptr_imap.end()); + ptr_imap.erase(irev); + + /* erase the data vector */ + DataMap::iterator idata = mem_data.find(client_pointer); + assert(idata != mem_data.end()); + mem_data.erase(idata); + + return result; + } + + /* note that the lock must be already acquired upon entry. + * This is necessary because the caller often peeks at + * the header and delegates control to here when it doesn't + * specifically handle the current RPC. + * The lock must be unlocked before returning */ + void process(RPCReceive& rcv, thread_scoped_lock &lock) + { if(rcv.name == "mem_alloc") { MemoryType type; network_device_memory mem; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(mem); rcv.read(type); - /* todo: CPU needs mem.data_pointer */ + lock.unlock(); + + client_pointer = mem.device_pointer; - remote_pointer = mem.device_pointer; + /* create a memory buffer for the device buffer */ + size_t data_size = mem.memory_size(); + DataVector &data_v = data_vector_insert(client_pointer, data_size); - mem_data[remote_pointer] = vector<uint8_t>(); - mem_data[remote_pointer].resize(mem.memory_size()); - if(mem.memory_size()) - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + if(data_size) + mem.data_pointer = (device_ptr)&(data_v[0]); else mem.data_pointer = 0; + /* perform the allocation on the actual device */ device->mem_alloc(mem, type); - ptr_map[remote_pointer] = mem.device_pointer; - ptr_imap[mem.device_pointer] = remote_pointer; + /* store a mapping to/from client_pointer and real device pointer */ + pointer_mapping_insert(client_pointer, mem.device_pointer); } else if(rcv.name == "mem_copy_to") { network_device_memory mem; rcv.read(mem); + lock.unlock(); - device_ptr remote_pointer = mem.device_pointer; - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + device_ptr client_pointer = mem.device_pointer; - rcv.read_buffer((uint8_t*)mem.data_pointer, mem.memory_size()); + DataVector &data_v = data_vector_find(client_pointer); - mem.device_pointer = ptr_map[remote_pointer]; + size_t data_size = mem.memory_size(); + /* get pointer to memory buffer for device buffer */ + mem.data_pointer = (device_ptr)&data_v[0]; + + /* copy data from network into memory buffer */ + rcv.read_buffer((uint8_t*)mem.data_pointer, data_size); + + /* translate the client pointer to a real device pointer */ + mem.device_pointer = device_ptr_from_client_pointer(client_pointer); + + /* copy the data from the memory buffer to the device buffer */ device->mem_copy_to(mem); } else if(rcv.name == "mem_copy_from") { @@ -314,37 +482,47 @@ protected: rcv.read(h); rcv.read(elem); - device_ptr remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[remote_pointer]; - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + device_ptr client_pointer = mem.device_pointer; + mem.device_pointer = device_ptr_from_client_pointer(client_pointer); + + DataVector &data_v = data_vector_find(client_pointer); + + mem.data_pointer = (device_ptr)&(data_v[0]); device->mem_copy_from(mem, y, w, h, elem); + size_t data_size = mem.memory_size(); + RPCSend snd(socket); snd.write(); - snd.write_buffer((uint8_t*)mem.data_pointer, mem.memory_size()); + snd.write_buffer((uint8_t*)mem.data_pointer, data_size); + lock.unlock(); } else if(rcv.name == "mem_zero") { network_device_memory mem; rcv.read(mem); - device_ptr remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[mem.device_pointer]; - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + lock.unlock(); + + device_ptr client_pointer = mem.device_pointer; + mem.device_pointer = device_ptr_from_client_pointer(client_pointer); + + DataVector &data_v = data_vector_find(client_pointer); + + mem.data_pointer = (device_ptr)&(data_v[0]); device->mem_zero(mem); } else if(rcv.name == "mem_free") { network_device_memory mem; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(mem); + lock.unlock(); + + client_pointer = mem.device_pointer; - remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[mem.device_pointer]; - ptr_map.erase(remote_pointer); - ptr_imap.erase(mem.device_pointer); - mem_data.erase(remote_pointer); + mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer); device->mem_free(mem); } @@ -357,6 +535,7 @@ protected: vector<char> host_vector(size); rcv.read_buffer(&host_vector[0], size); + lock.unlock(); device->const_copy_to(name_string.c_str(), &host_vector[0], size); } @@ -365,53 +544,76 @@ protected: string name; bool interpolation; bool periodic; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(name); rcv.read(mem); rcv.read(interpolation); rcv.read(periodic); + lock.unlock(); + + client_pointer = mem.device_pointer; + + size_t data_size = mem.memory_size(); - remote_pointer = mem.device_pointer; + DataVector &data_v = data_vector_insert(client_pointer, data_size); - mem_data[remote_pointer] = vector<uint8_t>(); - mem_data[remote_pointer].resize(mem.memory_size()); - if(mem.memory_size()) - mem.data_pointer = (device_ptr)&(mem_data[remote_pointer][0]); + if(data_size) + mem.data_pointer = (device_ptr)&(data_v[0]); else mem.data_pointer = 0; - rcv.read_buffer((uint8_t*)mem.data_pointer, mem.memory_size()); + rcv.read_buffer((uint8_t*)mem.data_pointer, data_size); device->tex_alloc(name.c_str(), mem, interpolation, periodic); - ptr_map[remote_pointer] = mem.device_pointer; - ptr_imap[mem.device_pointer] = remote_pointer; + pointer_mapping_insert(client_pointer, mem.device_pointer); } else if(rcv.name == "tex_free") { network_device_memory mem; - device_ptr remote_pointer; + device_ptr client_pointer; rcv.read(mem); + lock.unlock(); - remote_pointer = mem.device_pointer; - mem.device_pointer = ptr_map[mem.device_pointer]; - ptr_map.erase(remote_pointer); - ptr_map.erase(mem.device_pointer); - mem_data.erase(remote_pointer); + client_pointer = mem.device_pointer; + + mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer); device->tex_free(mem); } + else if(rcv.name == "load_kernels") { + bool experimental; + rcv.read(experimental); + + bool result; + result = device->load_kernels(experimental); + RPCSend snd(socket); + snd.add(result); + snd.write(); + lock.unlock(); + } else if(rcv.name == "task_add") { DeviceTask task; rcv.read(task); + lock.unlock(); + + if(task.buffer) + task.buffer = device_ptr_from_client_pointer(task.buffer); + + if(task.rgba_half) + task.rgba_half = device_ptr_from_client_pointer(task.rgba_half); + + if(task.rgba_byte) + task.rgba_byte = device_ptr_from_client_pointer(task.rgba_byte); + + if(task.shader_input) + task.shader_input = device_ptr_from_client_pointer(task.shader_input); + + if(task.shader_output) + task.shader_output = device_ptr_from_client_pointer(task.shader_output); - if(task.buffer) task.buffer = ptr_map[task.buffer]; - if(task.rgba_byte) task.rgba_byte = ptr_map[task.rgba_byte]; - if(task.rgba_half) task.rgba_half = ptr_map[task.rgba_half]; - if(task.shader_input) task.shader_input = ptr_map[task.shader_input]; - if(task.shader_output) task.shader_output = ptr_map[task.shader_output]; task.acquire_tile = function_bind(&DeviceServer::task_acquire_tile, this, _1, _2); task.release_tile = function_bind(&DeviceServer::task_release_tile, this, _1); @@ -422,14 +624,44 @@ protected: device->task_add(task); } else if(rcv.name == "task_wait") { + lock.unlock(); + + blocked_waiting = true; device->task_wait(); + blocked_waiting = false; + lock.lock(); RPCSend snd(socket, "task_wait_done"); snd.write(); + lock.unlock(); } else if(rcv.name == "task_cancel") { + lock.unlock(); device->task_cancel(); } + else if(rcv.name == "acquire_tile") { + AcquireEntry entry; + entry.name = rcv.name; + rcv.read(entry.tile); + acquire_queue.push_back(entry); + lock.unlock(); + } + else if(rcv.name == "acquire_tile_none") { + AcquireEntry entry; + entry.name = rcv.name; + acquire_queue.push_back(entry); + lock.unlock(); + } + else if(rcv.name == "release_tile") { + AcquireEntry entry; + entry.name = rcv.name; + acquire_queue.push_back(entry); + lock.unlock(); + } + else { + cout << "Error: unexpected RPC receive call \"" + rcv.name + "\"\n"; + lock.unlock(); + } } bool task_acquire_tile(Device *device, RenderTile& tile) @@ -441,23 +673,34 @@ protected: RPCSend snd(socket, "acquire_tile"); snd.write(); - while(1) { - RPCReceive rcv(socket); + do { + if(blocked_waiting) + listen_step(); - if(rcv.name == "acquire_tile") { - rcv.read(tile); + /* todo: avoid busy wait loop */ + thread_scoped_lock lock(rpc_lock); - if(tile.buffer) tile.buffer = ptr_map[tile.buffer]; - if(tile.rng_state) tile.rng_state = ptr_map[tile.rng_state]; + if(!acquire_queue.empty()) { + AcquireEntry entry = acquire_queue.front(); + acquire_queue.pop_front(); - result = true; - break; + if(entry.name == "acquire_tile") { + tile = entry.tile; + + if(tile.buffer) tile.buffer = ptr_map[tile.buffer]; + if(tile.rng_state) tile.rng_state = ptr_map[tile.rng_state]; + + result = true; + break; + } + else if(entry.name == "acquire_tile_none") { + break; + } + else { + cout << "Error: unexpected acquire RPC receive call \"" + entry.name + "\"\n"; + } } - else if(rcv.name == "acquire_tile_none") - break; - else - process(rcv); - } + } while(acquire_queue.empty() && !stop); return result; } @@ -479,18 +722,34 @@ protected: if(tile.buffer) tile.buffer = ptr_imap[tile.buffer]; if(tile.rng_state) tile.rng_state = ptr_imap[tile.rng_state]; - RPCSend snd(socket, "release_tile"); - snd.add(tile); - snd.write(); + { + thread_scoped_lock lock(rpc_lock); + RPCSend snd(socket, "release_tile"); + snd.add(tile); + snd.write(); + lock.unlock(); + } - while(1) { - RPCReceive rcv(socket); + do { + if(blocked_waiting) + listen_step(); - if(rcv.name == "release_tile") - break; - else - process(rcv); - } + /* todo: avoid busy wait loop */ + thread_scoped_lock lock(rpc_lock); + + if(!acquire_queue.empty()) { + AcquireEntry entry = acquire_queue.front(); + acquire_queue.pop_front(); + + if(entry.name == "release_tile") { + lock.unlock(); + break; + } + else { + cout << "Error: unexpected release RPC receive call \"" + entry.name + "\"\n"; + } + } + } while(acquire_queue.empty() && !stop); } bool task_get_cancel() @@ -503,11 +762,20 @@ protected: tcp::socket& socket; /* mapping of remote to local pointer */ - map<device_ptr, device_ptr> ptr_map; - map<device_ptr, device_ptr> ptr_imap; - map<device_ptr, vector<uint8_t> > mem_data; + PtrMap ptr_map; + PtrMap ptr_imap; + DataMap mem_data; + + struct AcquireEntry { + string name; + RenderTile tile; + }; thread_mutex acquire_mutex; + list<AcquireEntry> acquire_queue; + + bool stop; + bool blocked_waiting; /* todo: free memory and device (osl) on network error */ }; @@ -540,7 +808,8 @@ void Device::server_run() } } +CCL_NAMESPACE_END + #endif -CCL_NAMESPACE_END diff --git a/intern/cycles/device/device_network.h b/intern/cycles/device/device_network.h index db399cf4240..d639450b9ea 100644 --- a/intern/cycles/device/device_network.h +++ b/intern/cycles/device/device_network.h @@ -28,6 +28,8 @@ #include <boost/thread.hpp> #include <iostream> +#include <sstream> +#include <deque> #include "buffers.h" @@ -70,12 +72,12 @@ public: : name(name_), socket(socket_), archive(archive_stream), sent(false) { archive & name_; + + fprintf(stderr, "rpc send %s\n", name.c_str()); } ~RPCSend() { - if(!sent) - fprintf(stderr, "Error: RPC %s not sent\n", name.c_str()); } void add(const device_memory& mem) @@ -98,13 +100,14 @@ public: archive & task.offset & task.stride; archive & task.shader_input & task.shader_output & task.shader_eval_type; archive & task.shader_x & task.shader_w; + archive & task.need_finish_queue; } void add(const RenderTile& tile) { archive & tile.x & tile.y & tile.w & tile.h; archive & tile.start_sample & tile.num_samples & tile.sample; - archive & tile.offset & tile.stride; + archive & tile.resolution & tile.offset & tile.stride; archive & tile.buffer & tile.rng_state; } @@ -178,6 +181,7 @@ public: size_t data_size; if((header_stream >> hex >> data_size)) { + vector<char> data(data_size); size_t len = boost::asio::read(socket, boost::asio::buffer(data)); @@ -191,15 +195,19 @@ public: archive = new boost::archive::text_iarchive(*archive_stream); *archive & name; + fprintf(stderr, "rpc receive %s\n", name.c_str()); + } + else { + cout << "Network receive error: data size doesn't match header\n"; } - else - cout << "Network receive error: data size doens't match header\n"; } - else + else { cout << "Network receive error: can't decode data size from header\n"; + } } - else + else { cout << "Network receive error: invalid header size\n"; + } } ~RPCReceive() @@ -235,9 +243,10 @@ public: *archive & type & task.x & task.y & task.w & task.h; *archive & task.rgba_byte & task.rgba_half & task.buffer & task.sample & task.num_samples; - *archive & task.resolution & task.offset & task.stride; + *archive & task.offset & task.stride; *archive & task.shader_input & task.shader_output & task.shader_eval_type; *archive & task.shader_x & task.shader_w; + *archive & task.need_finish_queue; task.type = (DeviceTask::Type)type; } @@ -247,7 +256,7 @@ public: *archive & tile.x & tile.y & tile.w & tile.h; *archive & tile.start_sample & tile.num_samples & tile.sample; *archive & tile.resolution & tile.offset & tile.stride; - *archive & tile.buffer & tile.rng_state & tile.rgba_byte & tile.rgba_half; + *archive & tile.buffer & tile.rng_state; tile.buffers = NULL; } @@ -303,12 +312,12 @@ public: delete work; } - list<string> get_server_list() + vector<string> get_server_list() { - list<string> result; + vector<string> result; mutex.lock(); - result = servers; + result = vector<string>(servers.begin(), servers.end()); mutex.unlock(); return result; @@ -333,11 +342,8 @@ private: mutex.lock(); /* add address if it's not already in the list */ - bool found = false; - - foreach(string& server, servers) - if(server == address) - found = true; + bool found = std::find(servers.begin(), servers.end(), + address) != servers.end(); if(!found) servers.push_back(address); @@ -393,10 +399,21 @@ private: /* buffer and endpoint for receiving messages */ char receive_buffer[256]; boost::asio::ip::udp::endpoint receive_endpoint; + + // os, version, devices, status, host name, group name, ip as far as fields go + struct ServerInfo { + string cycles_version; + string os; + int device_count; + string status; + string host_name; + string group_name; + string host_addr; + }; /* collection of server addresses in list */ bool collect_servers; - list<string> servers; + vector<string> servers; }; CCL_NAMESPACE_END diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 11c7bc6f099..98d3b07b7ee 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -423,9 +423,8 @@ public: } OpenCLDevice(DeviceInfo& info, Stats &stats, bool background_) - : Device(stats) + : Device(info, stats, background_) { - background = background_; cpPlatform = NULL; cdDevice = NULL; cxContext = NULL; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 6c15849d815..0805a685467 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -95,7 +95,7 @@ Session::~Session() wait(); } - if(display && params.output_path != "") { + if(display && !params.output_path.empty()) { tonemap(); progress.set_status("Writing Image", params.output_path); @@ -242,7 +242,7 @@ void Session::run_gpu() /* update scene */ update_scene(); - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); if(progress.get_cancel()) @@ -263,7 +263,7 @@ void Session::run_gpu() device->task_wait(); - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); /* update status and timing */ @@ -283,7 +283,7 @@ void Session::run_gpu() } } - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); tiles_written = update_progressive_refine(progress.get_cancel()); @@ -531,7 +531,7 @@ void Session::run_cpu() /* update scene */ update_scene(); - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); if(progress.get_cancel()) @@ -549,7 +549,7 @@ void Session::run_cpu() if(!params.background) need_tonemap = true; - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); } @@ -571,7 +571,7 @@ void Session::run_cpu() tonemap(); } - if(device->error_message() != "") + if(!device->error_message().empty()) progress.set_cancel(device->error_message()); tiles_written = update_progressive_refine(progress.get_cancel()); @@ -592,7 +592,7 @@ void Session::run() if(!device->load_kernels(params.experimental)) { string message = device->error_message(); - if(message == "") + if(message.empty()) message = "Failed loading render kernel, see console for errors"; progress.set_status("Error", message); @@ -796,7 +796,7 @@ void Session::update_status_time(bool show_pause, bool show_done) } else { status = substatus; - substatus = ""; + substatus.clear(); } progress.set_status(status, substatus); diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index c4a81fc7190..61a16b63351 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -96,5 +96,14 @@ bool string_endswith(const string& s, const char *end) return strncmp(s.c_str() + s.size() - len, end, len) == 0; } +string string_strip(const string& s) +{ + string result = s; + result.erase(0, result.find_first_not_of(' ')); + result.erase(result.find_last_not_of(' ') + 1); + return result; + +} + CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h index 2d63a075e71..6808f085834 100644 --- a/intern/cycles/util/util_string.h +++ b/intern/cycles/util/util_string.h @@ -41,6 +41,7 @@ string string_printf(const char *format, ...) PRINTF_ATTRIBUTE; bool string_iequals(const string& a, const string& b); void string_split(vector<string>& tokens, const string& str, const string& separators = "\t "); bool string_endswith(const string& s, const char *end); +string string_strip(const string& s); CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index 8b249106913..79bf5fd26b7 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -101,9 +101,7 @@ string system_cpu_brand_string() replace_string(brand, "(TM)", ""); replace_string(brand, "(R)", ""); - size_t i; - if((i = brand.find(" ")) != string::npos) - brand = brand.substr(0, i); + brand = string_strip(brand); return brand; } |