Cycles: add single program debug option for split kernel
[blender-staging.git] / intern / cycles / device / device_network.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "device.h"
18 #include "device_intern.h"
19 #include "device_network.h"
20
21 #include "util_foreach.h"
22 #include "util_logging.h"
23
24 #if defined(WITH_NETWORK)
25
26 CCL_NAMESPACE_BEGIN
27
28 typedef map<device_ptr, device_ptr> PtrMap;
29 typedef vector<uint8_t> DataVector;
30 typedef map<device_ptr, DataVector> DataMap;
31
32 /* tile list */
33 typedef vector<RenderTile> TileList;
34
35 /* search a list of tiles and find the one that matches the passed render tile */
36 static TileList::iterator tile_list_find(TileList& tile_list, RenderTile& tile)
37 {
38         for(TileList::iterator it = tile_list.begin(); it != tile_list.end(); ++it)
39                 if(tile.x == it->x && tile.y == it->y && tile.start_sample == it->start_sample)
40                         return it;
41         return tile_list.end();
42 }
43
44 class NetworkDevice : public Device
45 {
46 public:
47         boost::asio::io_service io_service;
48         tcp::socket socket;
49         device_ptr mem_counter;
50         DeviceTask the_task; /* todo: handle multiple tasks */
51
52         thread_mutex rpc_lock;
53
54         virtual bool show_samples() const
55         {
56                 return false;
57         }
58
59         NetworkDevice(DeviceInfo& info, Stats &stats, const char *address)
60         : Device(info, stats, true), socket(io_service)
61         {
62                 error_func = NetworkError();
63                 stringstream portstr;
64                 portstr << SERVER_PORT;
65
66                 tcp::resolver resolver(io_service);
67                 tcp::resolver::query query(address, portstr.str());
68                 tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
69                 tcp::resolver::iterator end;
70
71                 boost::system::error_code error = boost::asio::error::host_not_found;
72                 while(error && endpoint_iterator != end)
73                 {
74                         socket.close();
75                         socket.connect(*endpoint_iterator++, error);
76                 }
77
78                 if(error)
79                         error_func.network_error(error.message());
80
81                 mem_counter = 0;
82         }
83
84         ~NetworkDevice()
85         {
86                 RPCSend snd(socket, &error_func, "stop");
87                 snd.write();
88         }
89
90         void mem_alloc(const char *name, device_memory& mem, MemoryType type)
91         {
92                 if(name) {
93                         VLOG(1) << "Buffer allocate: " << name << ", "
94                                     << string_human_readable_number(mem.memory_size()) << " bytes. ("
95                                     << string_human_readable_size(mem.memory_size()) << ")";
96                 }
97
98                 thread_scoped_lock lock(rpc_lock);
99
100                 mem.device_pointer = ++mem_counter;
101
102                 RPCSend snd(socket, &error_func, "mem_alloc");
103
104                 snd.add(mem);
105                 snd.add(type);
106                 snd.write();
107         }
108
109         void mem_copy_to(device_memory& mem)
110         {
111                 thread_scoped_lock lock(rpc_lock);
112
113                 RPCSend snd(socket, &error_func, "mem_copy_to");
114
115                 snd.add(mem);
116                 snd.write();
117                 snd.write_buffer((void*)mem.data_pointer, mem.memory_size());
118         }
119
120         void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
121         {
122                 thread_scoped_lock lock(rpc_lock);
123
124                 size_t data_size = mem.memory_size();
125
126                 RPCSend snd(socket, &error_func, "mem_copy_from");
127
128                 snd.add(mem);
129                 snd.add(y);
130                 snd.add(w);
131                 snd.add(h);
132                 snd.add(elem);
133                 snd.write();
134
135                 RPCReceive rcv(socket, &error_func);
136                 rcv.read_buffer((void*)mem.data_pointer, data_size);
137         }
138
139         void mem_zero(device_memory& mem)
140         {
141                 thread_scoped_lock lock(rpc_lock);
142
143                 RPCSend snd(socket, &error_func, "mem_zero");
144
145                 snd.add(mem);
146                 snd.write();
147         }
148
149         void mem_free(device_memory& mem)
150         {
151                 if(mem.device_pointer) {
152                         thread_scoped_lock lock(rpc_lock);
153
154                         RPCSend snd(socket, &error_func, "mem_free");
155
156                         snd.add(mem);
157                         snd.write();
158
159                         mem.device_pointer = 0;
160                 }
161         }
162
163         void const_copy_to(const char *name, void *host, size_t size)
164         {
165                 thread_scoped_lock lock(rpc_lock);
166
167                 RPCSend snd(socket, &error_func, "const_copy_to");
168
169                 string name_string(name);
170
171                 snd.add(name_string);
172                 snd.add(size);
173                 snd.write();
174                 snd.write_buffer(host, size);
175         }
176
177         void tex_alloc(const char *name,
178                        device_memory& mem,
179                        InterpolationType interpolation,
180                        ExtensionType extension)
181         {
182                 VLOG(1) << "Texture allocate: " << name << ", "
183                         << string_human_readable_number(mem.memory_size()) << " bytes. ("
184                         << string_human_readable_size(mem.memory_size()) << ")";
185
186                 thread_scoped_lock lock(rpc_lock);
187
188                 mem.device_pointer = ++mem_counter;
189
190                 RPCSend snd(socket, &error_func, "tex_alloc");
191
192                 string name_string(name);
193
194                 snd.add(name_string);
195                 snd.add(mem);
196                 snd.add(interpolation);
197                 snd.add(extension);
198                 snd.write();
199                 snd.write_buffer((void*)mem.data_pointer, mem.memory_size());
200         }
201
202         void tex_free(device_memory& mem)
203         {
204                 if(mem.device_pointer) {
205                         thread_scoped_lock lock(rpc_lock);
206
207                         RPCSend snd(socket, &error_func, "tex_free");
208
209                         snd.add(mem);
210                         snd.write();
211
212                         mem.device_pointer = 0;
213                 }
214         }
215
216         bool load_kernels(const DeviceRequestedFeatures& requested_features)
217         {
218                 if(error_func.have_error())
219                         return false;
220
221                 thread_scoped_lock lock(rpc_lock);
222
223                 RPCSend snd(socket, &error_func, "load_kernels");
224                 snd.add(requested_features.experimental);
225                 snd.add(requested_features.max_closure);
226                 snd.add(requested_features.max_nodes_group);
227                 snd.add(requested_features.nodes_features);
228                 snd.write();
229
230                 bool result;
231                 RPCReceive rcv(socket, &error_func);
232                 rcv.read(result);
233
234                 return result;
235         }
236
237         void task_add(DeviceTask& task)
238         {
239                 thread_scoped_lock lock(rpc_lock);
240
241                 the_task = task;
242
243                 RPCSend snd(socket, &error_func, "task_add");
244                 snd.add(task);
245                 snd.write();
246         }
247
248         void task_wait()
249         {
250                 thread_scoped_lock lock(rpc_lock);
251
252                 RPCSend snd(socket, &error_func, "task_wait");
253                 snd.write();
254
255                 lock.unlock();
256
257                 TileList the_tiles;
258
259                 /* todo: run this threaded for connecting to multiple clients */
260                 for(;;) {
261                         if(error_func.have_error())
262                                 break;
263
264                         RenderTile tile;
265
266                         lock.lock();
267                         RPCReceive rcv(socket, &error_func);
268
269                         if(rcv.name == "acquire_tile") {
270                                 lock.unlock();
271
272                                 /* todo: watch out for recursive calls! */
273                                 if(the_task.acquire_tile(this, tile)) { /* write return as bool */
274                                         the_tiles.push_back(tile);
275
276                                         lock.lock();
277                                         RPCSend snd(socket, &error_func, "acquire_tile");
278                                         snd.add(tile);
279                                         snd.write();
280                                         lock.unlock();
281                                 }
282                                 else {
283                                         lock.lock();
284                                         RPCSend snd(socket, &error_func, "acquire_tile_none");
285                                         snd.write();
286                                         lock.unlock();
287                                 }
288                         }
289                         else if(rcv.name == "release_tile") {
290                                 rcv.read(tile);
291                                 lock.unlock();
292
293                                 TileList::iterator it = tile_list_find(the_tiles, tile);
294                                 if(it != the_tiles.end()) {
295                                         tile.buffers = it->buffers;
296                                         the_tiles.erase(it);
297                                 }
298
299                                 assert(tile.buffers != NULL);
300
301                                 the_task.release_tile(tile);
302
303                                 lock.lock();
304                                 RPCSend snd(socket, &error_func, "release_tile");
305                                 snd.write();
306                                 lock.unlock();
307                         }
308                         else if(rcv.name == "task_wait_done") {
309                                 lock.unlock();
310                                 break;
311                         }
312                         else
313                                 lock.unlock();
314                 }
315         }
316
317         void task_cancel()
318         {
319                 thread_scoped_lock lock(rpc_lock);
320                 RPCSend snd(socket, &error_func, "task_cancel");
321                 snd.write();
322         }
323
324         int get_split_task_count(DeviceTask& task)
325         {
326                 return 1;
327         }
328
329 private:
330         NetworkError error_func;
331 };
332
333 Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address)
334 {
335         return new NetworkDevice(info, stats, address);
336 }
337
338 void device_network_info(vector<DeviceInfo>& devices)
339 {
340         DeviceInfo info;
341
342         info.type = DEVICE_NETWORK;
343         info.description = "Network Device";
344         info.id = "NETWORK";
345         info.num = 0;
346         info.advanced_shading = true; /* todo: get this info from device */
347         info.pack_images = false;
348
349         devices.push_back(info);
350 }
351
352 class DeviceServer {
353 public:
354         thread_mutex rpc_lock;
355
356         void network_error(const string &message) {
357                 error_func.network_error(message);
358         }
359
360         bool have_error() { return error_func.have_error(); }
361
362         DeviceServer(Device *device_, tcp::socket& socket_)
363         : device(device_), socket(socket_), stop(false), blocked_waiting(false)
364         {
365                 error_func = NetworkError();
366         }
367
368         void listen()
369         {
370                 /* receive remote function calls */
371                 for(;;) {
372                         listen_step();
373
374                         if(stop)
375                                 break;
376                 }
377         }
378
379 protected:
380         void listen_step()
381         {
382                 thread_scoped_lock lock(rpc_lock);
383                 RPCReceive rcv(socket, &error_func);
384
385                 if(rcv.name == "stop")
386                         stop = true;
387                 else
388                         process(rcv, lock);
389         }
390
391         /* create a memory buffer for a device buffer and insert it into mem_data */
392         DataVector &data_vector_insert(device_ptr client_pointer, size_t data_size)
393         {
394                 /* create a new DataVector and insert it into mem_data */
395                 pair<DataMap::iterator,bool> data_ins = mem_data.insert(
396                         DataMap::value_type(client_pointer, DataVector()));
397
398                 /* make sure it was a unique insertion */
399                 assert(data_ins.second);
400
401                 /* get a reference to the inserted vector */
402                 DataVector &data_v = data_ins.first->second;
403
404                 /* size the vector */
405                 data_v.resize(data_size);
406
407                 return data_v;
408         }
409
410         DataVector &data_vector_find(device_ptr client_pointer)
411         {
412                 DataMap::iterator i = mem_data.find(client_pointer);
413                 assert(i != mem_data.end());
414                 return i->second;
415         }
416
417         /* setup mapping and reverse mapping of client_pointer<->real_pointer */
418         void pointer_mapping_insert(device_ptr client_pointer, device_ptr real_pointer)
419         {
420                 pair<PtrMap::iterator,bool> mapins;
421
422                 /* insert mapping from client pointer to our real device pointer */
423                 mapins = ptr_map.insert(PtrMap::value_type(client_pointer, real_pointer));
424                 assert(mapins.second);
425
426                 /* insert reverse mapping from real our device pointer to client pointer */
427                 mapins = ptr_imap.insert(PtrMap::value_type(real_pointer, client_pointer));
428                 assert(mapins.second);
429         }
430
431         device_ptr device_ptr_from_client_pointer(device_ptr client_pointer)
432         {
433                 PtrMap::iterator i = ptr_map.find(client_pointer);
434                 assert(i != ptr_map.end());
435                 return i->second;
436         }
437
438         device_ptr device_ptr_from_client_pointer_erase(device_ptr client_pointer)
439         {
440                 PtrMap::iterator i = ptr_map.find(client_pointer);
441                 assert(i != ptr_map.end());
442
443                 device_ptr result = i->second;
444
445                 /* erase the mapping */
446                 ptr_map.erase(i);
447
448                 /* erase the reverse mapping */
449                 PtrMap::iterator irev = ptr_imap.find(result);
450                 assert(irev != ptr_imap.end());
451                 ptr_imap.erase(irev);
452
453                 /* erase the data vector */
454                 DataMap::iterator idata = mem_data.find(client_pointer);
455                 assert(idata != mem_data.end());
456                 mem_data.erase(idata);
457
458                 return result;
459         }
460
461         /* note that the lock must be already acquired upon entry.
462          * This is necessary because the caller often peeks at
463          * the header and delegates control to here when it doesn't
464          * specifically handle the current RPC.
465          * The lock must be unlocked before returning */
466         void process(RPCReceive& rcv, thread_scoped_lock &lock)
467         {
468                 if(rcv.name == "mem_alloc") {
469                         MemoryType type;
470                         network_device_memory mem;
471                         device_ptr client_pointer;
472
473                         rcv.read(mem);
474                         rcv.read(type);
475
476                         lock.unlock();
477
478                         client_pointer = mem.device_pointer;
479
480                         /* create a memory buffer for the device buffer */
481                         size_t data_size = mem.memory_size();
482                         DataVector &data_v = data_vector_insert(client_pointer, data_size);
483
484                         if(data_size)
485                                 mem.data_pointer = (device_ptr)&(data_v[0]);
486                         else
487                                 mem.data_pointer = 0;
488
489                         /* perform the allocation on the actual device */
490                         device->mem_alloc(NULL, mem, type);
491
492                         /* store a mapping to/from client_pointer and real device pointer */
493                         pointer_mapping_insert(client_pointer, mem.device_pointer);
494                 }
495                 else if(rcv.name == "mem_copy_to") {
496                         network_device_memory mem;
497
498                         rcv.read(mem);
499                         lock.unlock();
500
501                         device_ptr client_pointer = mem.device_pointer;
502
503                         DataVector &data_v = data_vector_find(client_pointer);
504
505                         size_t data_size = mem.memory_size();
506
507                         /* get pointer to memory buffer for device buffer */
508                         mem.data_pointer = (device_ptr)&data_v[0];
509
510                         /* copy data from network into memory buffer */
511                         rcv.read_buffer((uint8_t*)mem.data_pointer, data_size);
512
513                         /* translate the client pointer to a real device pointer */
514                         mem.device_pointer = device_ptr_from_client_pointer(client_pointer);
515
516                         /* copy the data from the memory buffer to the device buffer */
517                         device->mem_copy_to(mem);
518                 }
519                 else if(rcv.name == "mem_copy_from") {
520                         network_device_memory mem;
521                         int y, w, h, elem;
522
523                         rcv.read(mem);
524                         rcv.read(y);
525                         rcv.read(w);
526                         rcv.read(h);
527                         rcv.read(elem);
528
529                         device_ptr client_pointer = mem.device_pointer;
530                         mem.device_pointer = device_ptr_from_client_pointer(client_pointer);
531
532                         DataVector &data_v = data_vector_find(client_pointer);
533
534                         mem.data_pointer = (device_ptr)&(data_v[0]);
535
536                         device->mem_copy_from(mem, y, w, h, elem);
537
538                         size_t data_size = mem.memory_size();
539
540                         RPCSend snd(socket, &error_func, "mem_copy_from");
541                         snd.write();
542                         snd.write_buffer((uint8_t*)mem.data_pointer, data_size);
543                         lock.unlock();
544                 }
545                 else if(rcv.name == "mem_zero") {
546                         network_device_memory mem;
547                         
548                         rcv.read(mem);
549                         lock.unlock();
550
551                         device_ptr client_pointer = mem.device_pointer;
552                         mem.device_pointer = device_ptr_from_client_pointer(client_pointer);
553
554                         DataVector &data_v = data_vector_find(client_pointer);
555
556                         mem.data_pointer = (device_ptr)&(data_v[0]);
557
558                         device->mem_zero(mem);
559                 }
560                 else if(rcv.name == "mem_free") {
561                         network_device_memory mem;
562                         device_ptr client_pointer;
563
564                         rcv.read(mem);
565                         lock.unlock();
566
567                         client_pointer = mem.device_pointer;
568
569                         mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer);
570
571                         device->mem_free(mem);
572                 }
573                 else if(rcv.name == "const_copy_to") {
574                         string name_string;
575                         size_t size;
576
577                         rcv.read(name_string);
578                         rcv.read(size);
579
580                         vector<char> host_vector(size);
581                         rcv.read_buffer(&host_vector[0], size);
582                         lock.unlock();
583
584                         device->const_copy_to(name_string.c_str(), &host_vector[0], size);
585                 }
586                 else if(rcv.name == "tex_alloc") {
587                         network_device_memory mem;
588                         string name;
589                         InterpolationType interpolation;
590                         ExtensionType extension_type;
591                         device_ptr client_pointer;
592
593                         rcv.read(name);
594                         rcv.read(mem);
595                         rcv.read(interpolation);
596                         rcv.read(extension_type);
597                         lock.unlock();
598
599                         client_pointer = mem.device_pointer;
600
601                         size_t data_size = mem.memory_size();
602
603                         DataVector &data_v = data_vector_insert(client_pointer, data_size);
604
605                         if(data_size)
606                                 mem.data_pointer = (device_ptr)&(data_v[0]);
607                         else
608                                 mem.data_pointer = 0;
609
610                         rcv.read_buffer((uint8_t*)mem.data_pointer, data_size);
611
612                         device->tex_alloc(name.c_str(), mem, interpolation, extension_type);
613
614                         pointer_mapping_insert(client_pointer, mem.device_pointer);
615                 }
616                 else if(rcv.name == "tex_free") {
617                         network_device_memory mem;
618                         device_ptr client_pointer;
619
620                         rcv.read(mem);
621                         lock.unlock();
622
623                         client_pointer = mem.device_pointer;
624
625                         mem.device_pointer = device_ptr_from_client_pointer_erase(client_pointer);
626
627                         device->tex_free(mem);
628                 }
629                 else if(rcv.name == "load_kernels") {
630                         DeviceRequestedFeatures requested_features;
631                         rcv.read(requested_features.experimental);
632                         rcv.read(requested_features.max_closure);
633                         rcv.read(requested_features.max_nodes_group);
634                         rcv.read(requested_features.nodes_features);
635
636                         bool result;
637                         result = device->load_kernels(requested_features);
638                         RPCSend snd(socket, &error_func, "load_kernels");
639                         snd.add(result);
640                         snd.write();
641                         lock.unlock();
642                 }
643                 else if(rcv.name == "task_add") {
644                         DeviceTask task;
645
646                         rcv.read(task);
647                         lock.unlock();
648
649                         if(task.buffer)
650                                 task.buffer = device_ptr_from_client_pointer(task.buffer);
651
652                         if(task.rgba_half)
653                                 task.rgba_half = device_ptr_from_client_pointer(task.rgba_half);
654
655                         if(task.rgba_byte)
656                                 task.rgba_byte = device_ptr_from_client_pointer(task.rgba_byte);
657
658                         if(task.shader_input)
659                                 task.shader_input = device_ptr_from_client_pointer(task.shader_input);
660
661                         if(task.shader_output)
662                                 task.shader_output = device_ptr_from_client_pointer(task.shader_output);
663
664                         if(task.shader_output_luma)
665                                 task.shader_output_luma = device_ptr_from_client_pointer(task.shader_output_luma);
666
667
668                         task.acquire_tile = function_bind(&DeviceServer::task_acquire_tile, this, _1, _2);
669                         task.release_tile = function_bind(&DeviceServer::task_release_tile, this, _1);
670                         task.update_progress_sample = function_bind(&DeviceServer::task_update_progress_sample, this);
671                         task.update_tile_sample = function_bind(&DeviceServer::task_update_tile_sample, this, _1);
672                         task.get_cancel = function_bind(&DeviceServer::task_get_cancel, this);
673
674                         device->task_add(task);
675                 }
676                 else if(rcv.name == "task_wait") {
677                         lock.unlock();
678
679                         blocked_waiting = true;
680                         device->task_wait();
681                         blocked_waiting = false;
682
683                         lock.lock();
684                         RPCSend snd(socket, &error_func, "task_wait_done");
685                         snd.write();
686                         lock.unlock();
687                 }
688                 else if(rcv.name == "task_cancel") {
689                         lock.unlock();
690                         device->task_cancel();
691                 }
692                 else if(rcv.name == "acquire_tile") {
693                         AcquireEntry entry;
694                         entry.name = rcv.name;
695                         rcv.read(entry.tile);
696                         acquire_queue.push_back(entry);
697                         lock.unlock();
698                 }
699                 else if(rcv.name == "acquire_tile_none") {
700                         AcquireEntry entry;
701                         entry.name = rcv.name;
702                         acquire_queue.push_back(entry);
703                         lock.unlock();
704                 }
705                 else if(rcv.name == "release_tile") {
706                         AcquireEntry entry;
707                         entry.name = rcv.name;
708                         acquire_queue.push_back(entry);
709                         lock.unlock();
710                 }
711                 else {
712                         cout << "Error: unexpected RPC receive call \"" + rcv.name + "\"\n";
713                         lock.unlock();
714                 }
715         }
716
717         bool task_acquire_tile(Device *device, RenderTile& tile)
718         {
719                 thread_scoped_lock acquire_lock(acquire_mutex);
720
721                 bool result = false;
722
723                 RPCSend snd(socket, &error_func, "acquire_tile");
724                 snd.write();
725
726                 do {
727                         if(blocked_waiting)
728                                 listen_step();
729
730                         /* todo: avoid busy wait loop */
731                         thread_scoped_lock lock(rpc_lock);
732
733                         if(!acquire_queue.empty()) {
734                                 AcquireEntry entry = acquire_queue.front();
735                                 acquire_queue.pop_front();
736
737                                 if(entry.name == "acquire_tile") {
738                                         tile = entry.tile;
739
740                                         if(tile.buffer) tile.buffer = ptr_map[tile.buffer];
741                                         if(tile.rng_state) tile.rng_state = ptr_map[tile.rng_state];
742
743                                         result = true;
744                                         break;
745                                 }
746                                 else if(entry.name == "acquire_tile_none") {
747                                         break;
748                                 }
749                                 else {
750                                         cout << "Error: unexpected acquire RPC receive call \"" + entry.name + "\"\n";
751                                 }
752                         }
753                 } while(acquire_queue.empty() && !stop && !have_error());
754
755                 return result;
756         }
757
758         void task_update_progress_sample()
759         {
760                 ; /* skip */
761         }
762
763         void task_update_tile_sample(RenderTile&)
764         {
765                 ; /* skip */
766         }
767
768         void task_release_tile(RenderTile& tile)
769         {
770                 thread_scoped_lock acquire_lock(acquire_mutex);
771
772                 if(tile.buffer) tile.buffer = ptr_imap[tile.buffer];
773                 if(tile.rng_state) tile.rng_state = ptr_imap[tile.rng_state];
774
775                 {
776                         thread_scoped_lock lock(rpc_lock);
777                         RPCSend snd(socket, &error_func, "release_tile");
778                         snd.add(tile);
779                         snd.write();
780                         lock.unlock();
781                 }
782
783                 do {
784                         if(blocked_waiting)
785                                 listen_step();
786
787                         /* todo: avoid busy wait loop */
788                         thread_scoped_lock lock(rpc_lock);
789
790                         if(!acquire_queue.empty()) {
791                                 AcquireEntry entry = acquire_queue.front();
792                                 acquire_queue.pop_front();
793
794                                 if(entry.name == "release_tile") {
795                                         lock.unlock();
796                                         break;
797                                 }
798                                 else {
799                                         cout << "Error: unexpected release RPC receive call \"" + entry.name + "\"\n";
800                                 }
801                         }
802                 } while(acquire_queue.empty() && !stop);
803         }
804
805         bool task_get_cancel()
806         {
807                 return false;
808         }
809
810         /* properties */
811         Device *device;
812         tcp::socket& socket;
813
814         /* mapping of remote to local pointer */
815         PtrMap ptr_map;
816         PtrMap ptr_imap;
817         DataMap mem_data;
818
819         struct AcquireEntry {
820                 string name;
821                 RenderTile tile;
822         };
823
824         thread_mutex acquire_mutex;
825         list<AcquireEntry> acquire_queue;
826
827         bool stop;
828         bool blocked_waiting;
829 private:
830         NetworkError error_func;
831
832         /* todo: free memory and device (osl) on network error */
833
834 };
835
836 void Device::server_run()
837 {
838         try {
839                 /* starts thread that responds to discovery requests */
840                 ServerDiscovery discovery;
841
842                 for(;;) {
843                         /* accept connection */
844                         boost::asio::io_service io_service;
845                         tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), SERVER_PORT));
846
847                         tcp::socket socket(io_service);
848                         acceptor.accept(socket);
849
850                         string remote_address = socket.remote_endpoint().address().to_string();
851                         printf("Connected to remote client at: %s\n", remote_address.c_str());
852
853                         DeviceServer server(this, socket);
854                         server.listen();
855
856                         printf("Disconnected.\n");
857                 }
858         }
859         catch(exception& e) {
860                 fprintf(stderr, "Network server exception: %s\n", e.what());
861         }
862 }
863
864 CCL_NAMESPACE_END
865
866 #endif
867
868