Code refactor: move more memory allocation logic into device API.
[blender-staging.git] / intern / cycles / device / device_network.h
index 3cdb70bb4dfccab6646996969ed857f1cefaa38a..a38d962c0af9ab83d0740088a32c89ffe038fb3c 100644 (file)
@@ -1,19 +1,17 @@
 /*
- * Copyright 2011, Blender Foundation.
+ * Copyright 2011-2013 Blender Foundation
  *
- * 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- * 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.
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #ifndef __DEVICE_NETWORK_H__
@@ -23,6 +21,8 @@
 
 #include <boost/archive/text_iarchive.hpp>
 #include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/binary_oarchive.hpp>
 #include <boost/array.hpp>
 #include <boost/asio.hpp>
 #include <boost/bind.hpp>
 #include <boost/thread.hpp>
 
 #include <iostream>
+#include <sstream>
+#include <deque>
 
-#include "util_foreach.h"
-#include "util_list.h"
-#include "util_string.h"
+#include "render/buffers.h"
+
+#include "util/util_foreach.h"
+#include "util/util_list.h"
+#include "util/util_map.h"
+#include "util/util_param.h"
+#include "util/util_string.h"
 
 CCL_NAMESPACE_BEGIN
 
 using std::cout;
 using std::cerr;
-using std::endl;
 using std::hex;
 using std::setw;
 using std::exception;
@@ -51,11 +56,104 @@ static const int DISCOVER_PORT = 5121;
 static const string DISCOVER_REQUEST_MSG = "REQUEST_RENDER_SERVER_IP";
 static const string DISCOVER_REPLY_MSG = "REPLY_RENDER_SERVER_IP";
 
-typedef struct RPCSend {
-       RPCSend(tcp::socket& socket_, const string& name_ = "")
-       : name(name_), socket(socket_), archive(archive_stream)
+#if 0
+typedef boost::archive::text_oarchive o_archive;
+typedef boost::archive::text_iarchive i_archive;
+#else
+typedef boost::archive::binary_oarchive o_archive;
+typedef boost::archive::binary_iarchive i_archive;
+#endif
+
+/* Serialization of device memory */
+
+class network_device_memory : public device_memory
+{
+public:
+       network_device_memory(Device *device)
+       : device_memory(device, "", MEM_READ_ONLY)
+       {
+       }
+
+       ~network_device_memory()
+       {
+               device_pointer = 0;
+       };
+
+       vector<char> local_data;
+};
+
+/* Common netowrk error function / object for both DeviceNetwork and DeviceServer*/
+class NetworkError {
+public:
+       NetworkError() {
+               error = "";
+               error_count = 0;
+       }
+
+       ~NetworkError() {}
+
+       void network_error(const string& message) {
+               error = message;
+               error_count += 1;
+       }
+
+       bool have_error() {
+               return true ? error_count > 0 : false;
+       }
+
+private:
+       string error;
+       int error_count;
+};
+
+
+/* Remote procedure call Send */
+
+class RPCSend {
+public:
+       RPCSend(tcp::socket& socket_, NetworkError* e, const string& name_ = "")
+       : name(name_), socket(socket_), archive(archive_stream), sent(false)
        {
                archive & name_;
+               error_func = e;
+               fprintf(stderr, "rpc send %s\n", name.c_str());
+       }
+
+       ~RPCSend()
+       {
+       }
+
+       void add(const device_memory& mem)
+       {
+               archive & mem.data_type & mem.data_elements & mem.data_size;
+               archive & mem.data_width & mem.data_height & mem.data_depth & mem.device_pointer;
+               archive & mem.type & string(mem.name);
+               archive & mem.interpolation & mem.extension;
+               archive & mem.device_pointer;
+       }
+
+       template<typename T> void add(const T& data)
+       {
+               archive & data;
+       }
+
+       void add(const DeviceTask& task)
+       {
+               int type = (int)task.type;
+               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.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.resolution & tile.offset & tile.stride;
+               archive & tile.buffer;
        }
 
        void write()
@@ -75,7 +173,7 @@ typedef struct RPCSend {
                        boost::asio::transfer_all(), error);
 
                if(error.value())
-                       cout << "Network send error: " << error.message() << "\n";
+                       error_func->network_error(error.message());
 
                /* then send actual data */
                boost::asio::write(socket,
@@ -83,7 +181,9 @@ typedef struct RPCSend {
                        boost::asio::transfer_all(), error);
                
                if(error.value())
-                       cout << "Network send error: " << error.message() << "\n";
+                       error_func->network_error(error.message());
+
+               sent = true;
        }
 
        void write_buffer(void *buffer, size_t size)
@@ -95,22 +195,34 @@ typedef struct RPCSend {
                        boost::asio::transfer_all(), error);
                
                if(error.value())
-                       cout << "Network send error: " << error.message() << "\n";
+                       error_func->network_error(error.message());
        }
 
+protected:
        string name;
        tcp::socket& socket;
        ostringstream archive_stream;
-       boost::archive::text_oarchive archive;
-} RPCSend;
+       o_archive archive;
+       bool sent;
+       NetworkError *error_func;
+};
 
-typedef struct RPCReceive {
-       RPCReceive(tcp::socket& socket_)
+/* Remote procedure call Receive */
+
+class RPCReceive {
+public:
+       RPCReceive(tcp::socket& socket_, NetworkError* e )
        : socket(socket_), archive_stream(NULL), archive(NULL)
        {
+               error_func = e;
                /* read head with fixed size */
-               vector<char> header(8);
-               size_t len = boost::asio::read(socket, boost::asio::buffer(header));
+               vector<char> header(8);
+               boost::system::error_code error;
+               size_t len = boost::asio::read(socket, boost::asio::buffer(header), error);
+
+               if(error.value()) {
+                       error_func->network_error(error.message());
+               }
 
                /* verify if we got something */
                if(len == header.size()) {
@@ -121,26 +233,34 @@ typedef struct RPCReceive {
                        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));
+                               size_t len = boost::asio::read(socket, boost::asio::buffer(data), error);
+
+                               if(error.value())
+                                       error_func->network_error(error.message());
+
 
                                if(len == data_size) {
                                        archive_str = (data.size())? string(&data[0], data.size()): string("");
-                                       /*istringstream archive_stream(archive_str);
-                                       boost::archive::text_iarchive archive(archive_stream);*/
+
                                        archive_stream = new istringstream(archive_str);
-                                       archive = new boost::archive::text_iarchive(*archive_stream);
+                                       archive = new i_archive(*archive_stream);
 
                                        *archive & name;
+                                       fprintf(stderr, "rpc receive %s\n", name.c_str());
+                               }
+                               else {
+                                       error_func->network_error("Network receive error: data size doesn't match header");
                                }
-                               else
-                                       cout << "Network receive error: data size doens't match header\n";
                        }
-                       else
-                               cout << "Network receive error: can't decode data size from header\n";
+                       else {
+                               error_func->network_error("Network receive error: can't decode data size from header");
+                       }
+               }
+               else {
+                       error_func->network_error("Network receive error: invalid header size");
                }
-               else
-                       cout << "Network receive error: invalid header size\n";
        }
 
        ~RPCReceive()
@@ -149,28 +269,84 @@ typedef struct RPCReceive {
                delete archive_stream;
        }
 
+       void read(network_device_memory& mem, string& name)
+       {
+               *archive & mem.data_type & mem.data_elements & mem.data_size;
+               *archive & mem.data_width & mem.data_height & mem.data_depth & mem.device_pointer;
+               *archive & mem.type & name;
+               *archive & mem.interpolation & mem.extension;
+               *archive & mem.device_pointer;
+
+               mem.name = name.c_str();
+               mem.data_pointer = 0;
+
+               /* Can't transfer OpenGL texture over network. */
+               if(mem.type == MEM_PIXELS) {
+                       mem.type = MEM_WRITE_ONLY;
+               }
+       }
+
+       template<typename T> void read(T& data)
+       {
+               *archive & data;
+       }
+
        void read_buffer(void *buffer, size_t size)
        {
-               size_t len = boost::asio::read(socket, boost::asio::buffer(buffer, size));
+               boost::system::error_code error;
+               size_t len = boost::asio::read(socket, boost::asio::buffer(buffer, size), error);
+
+               if(error.value()) {
+                       error_func->network_error(error.message());
+               }
 
                if(len != size)
                        cout << "Network receive error: buffer size doesn't match expected size\n";
        }
 
+       void read(DeviceTask& task)
+       {
+               int type;
+
+               *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.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;
+       }
+
+       void read(RenderTile& tile)
+       {
+               *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.buffers = NULL;
+       }
+
        string name;
+
+protected:
        tcp::socket& socket;
        string archive_str;
        istringstream *archive_stream;
-       boost::archive::text_iarchive *archive;
-} RPCReceive;
+       i_archive *archive;
+       NetworkError *error_func;
+};
+
+/* Server auto discovery */
 
 class ServerDiscovery {
 public:
-       ServerDiscovery(bool discover = false)
+       explicit ServerDiscovery(bool discover = false)
        : listen_socket(io_service), collect_servers(false)
        {
                /* setup listen socket */
-               listen_endpoint.address(boost::asio::ip::address_v4::any());
+               listen_endpoint.address(boost::asio::ip::address_v4::any());
                listen_endpoint.port(DISCOVER_PORT);
 
                listen_socket.open(listen_endpoint.protocol());
@@ -178,7 +354,7 @@ public:
                boost::asio::socket_base::reuse_address option(true);
                listen_socket.set_option(option);
 
-               listen_socket.bind(listen_endpoint);
+               listen_socket.bind(listen_endpoint);
 
                /* setup receive callback */
                async_receive();
@@ -204,12 +380,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;
@@ -234,11 +410,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);
@@ -294,10 +467,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