]> git.pld-linux.org Git - packages/povray.git/blame - povray-pvm.patch
another attempt
[packages/povray.git] / povray-pvm.patch
CommitLineData
1ca6bd2c
MP
1diff -Naur source.ori/optin.c source/optin.c
2--- source.ori/optin.c Sat Jun 30 01:49:21 2001
b7dcac6d 3+++ source/optin.c Sat Jun 30 13:55:01 2001
1ca6bd2c
MP
4@@ -30,7 +30,8 @@
5 *
6 * Written by CEY 4/94 based on existing code and INI code from CDW.
7 *
8-* ---
9+* Modified Oct. 96 by Deischi for PVM
10+* Modified Jun 2001 by Agaran for conditional PVM build
11 *
12 * Modification by Thomas Willhalm, March 1999, used with permission.
13 *
14@@ -56,7 +57,9 @@
15 #include "targa.h"
16 #include "userio.h"
17 #include "png_pov.h"
18-
19+#ifdef USE_PVM
20+#include "pvm.h"
21+#endif
22
23
24 /*****************************************************************************
b7dcac6d 25@@ -188,6 +191,21 @@
1ca6bd2c
MP
26 { BITS_PER_COLOR_OP, "Bits_Per_Color" },
27 { BITS_PER_COLOUR_OP, "Bits_Per_Colour" },
b7dcac6d 28 { INCLUDE_INI_OP, "Include_Ini" }
1ca6bd2c 29+#ifdef USE_PVM
b7dcac6d 30+ ,
1ca6bd2c
MP
31+
32+ /* new options for PVM-Pov */
33+ { PVM_TASKS_OP, "PVM_Tasks" },
34+ { PVM_WIDTH_OP, "PVM_Width" },
35+ { PVM_HEIGHT_OP, "PVM_Height" },
36+ { PVM_SLAVE_OP, "PVM_Slave" },
37+ { PVM_ARCH_OP, "PVM_Arch" },
38+ { PVM_NICE_OP, "PVM_Nice" },
39+ { PVM_WD_OP, "PVM_WD" },
40+ { PVM_HOSTS_OP, "PVM_Hosts" },
41+ { PVM_USE_OP, "PVM" }
42+
1ca6bd2c
MP
43+#endif
44 };
45
46 static char temp_string[3]="\0\0";
b7dcac6d 47@@ -229,7 +247,8 @@
1ca6bd2c
MP
48 *
49 * CHANGES
50 *
51-* -
52+* Oct. 1996: Added options for PVMPOV [Deischi]
53+* jun 2001: conditional pvm
54 *
55 ******************************************************************************/
56
b7dcac6d 57@@ -560,6 +579,44 @@
1ca6bd2c
MP
58 case INCLUDE_INI_OP:
59 value[0] = '\0';
60 return value;
61+#ifdef USE_PVM
62+ /*
63+ * PVM Options
64+ */
65+ case PVM_TASKS_OP:
66+ sprintf(value, "%d", PvmTasks);
67+ return value;
68+ case PVM_WIDTH_OP:
69+ sprintf(value, "%d", PvmChunkWidth);
70+ return value;
71+ case PVM_HEIGHT_OP:
72+ sprintf(value, "%d", PvmChunkHeight);
73+ return value;
74+ case PVM_SLAVE_OP:
75+ strncpy(value, PvmSlavename ? PvmSlavename : "", 128);
76+ return value;
77+ case PVM_ARCH_OP:
78+ sprintf(value, "%s", PvmArch);
79+ return value;
80+ case PVM_NICE_OP:
81+ sprintf(value, "%d", PvmNice);
82+ return value;
83+ case PVM_WD_OP:
84+ strncpy(value, PvmWorkingDir, PATH_MAX);
85+ return value;
86+ case PVM_HOSTS_OP:
87+ if(PvmHosts) {
88+ int i;
89+ for(i=0; i < PvmHostsN; i++) {
90+ strncat(value, PvmHosts[i], 128);
91+ strncat(value, ",", 128);
92+ }
93+ }
94+ return value;
95+ case PVM_USE_OP:
96+ sprintf(value, "%s", (PvmTasks || PvmSlave) ? "On" : "Off");
97+ return value;
98+#endif
99
100 default:
101 Error("Unknown INI option in Write_INI.");
b7dcac6d 102@@ -602,6 +659,8 @@
1ca6bd2c
MP
103 * Sep 1994 : Added options for union splitting, vista/light buffer. [DB]
104 * Jan 1995 : Added options for histogram grid. [CJC]
105 * Feb 1995 : Added options for console/file redirection and .INI writing [SCD]
106+* Oct 1996 : Added options for PVMPOV [Deischi]
107+* jun 2001 : added condititional build for pvm
108 *
109 ******************************************************************************/
110
b7dcac6d 111@@ -1024,13 +1083,67 @@
1ca6bd2c
MP
112 break;
113
114 /* "N" option flag is used by networking (multi-processor) options.
115-
116- case 'N':
117- case 'n':
118-
119- break;
120-
121 */
122+#ifdef USE_PVM
123+ /*
124+ * PVM-POV
125+ *
126+ */
127+ case 'N': /* switches used for PVMPOV */
128+ case 'n':
129+ switch( Option_String[1]) {
130+ case '\0': /* Start one slave/available PVM host */
131+ process_variable(PVM_USE_OP, Add_Option ? "On" : "Off");
132+ break;
133+ case 'a': /* Select a particular architecture to run the slaves on */
134+ case 'A':
135+ process_variable(PVM_ARCH_OP, Option_String+2);
136+ break;
137+ case 'n': /* Sets the niceness (priority) level */
138+ case 'N':
139+ process_variable(PVM_NICE_OP, Option_String+2);
140+ break;
141+ case 't': /* Sets the number of tasks to run. Default is 1 per host */
142+ case 'T':
143+ process_variable(PVM_TASKS_OP, Option_String+2);
144+ break;
145+ case 'h': /* The height of a single grid block, in pixels */
146+ case 'H':
147+ process_variable(PVM_HEIGHT_OP, Option_String+2);
148+ break;
149+ case 'w': /* The width of a single grid block, in pixels */
150+ case 'W':
151+ process_variable(PVM_WIDTH_OP, Option_String+2);
152+ break;
153+ case 's': /* specify the name of the slave */
154+ case 'S':
155+ process_variable(PVM_SLAVE_OP, Option_String+2);
156+ break;
157+ case 'd': /* specify working directory for the slaves */
158+ case 'D':
159+ process_variable(PVM_WD_OP, Option_String+2);
160+ break;
161+ /* Internal sub-option "-nI" indicates a PVM slave task.
162+ * This will be appended to current argv string, so it will override
163+ * the previous -nxx options. */
164+ case 'i':
165+ case 'I':
166+ PvmTasks = 1;
167+ PvmSlave = 1;
168+
169+ if (chdir(&Option_String[2]) < 0) {
170+ fprintf(stderr, "Slave cannot cd to %s.\n", &Option_String[2]);
171+ exit(1);
172+ }
173+ break;
174+
175+ default:
176+ fprintf(stderr, "Illegal +N%c switch setting\n", Option_String[1]);
177+ break;
178+ } /* switch */
179+ break;
180+#endif
181+
182
183 case 'O':
184 case 'o':
b7dcac6d 185@@ -1262,7 +1375,8 @@
1ca6bd2c
MP
186 *
187 * CHANGES
188 *
189-* -
190+* Oct 1996 : Added options for PVMPOV [Deischi]
191+* jun 2001 : conditional build for pvm
192 *
193 ******************************************************************************/
194
b7dcac6d 195@@ -1445,21 +1559,36 @@
1ca6bd2c
MP
196 return;
197
198 case END_COLUMN_OP:
199+#ifdef USE_PVM
200+ /* tw */
201+ if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF) {
202+#else
203 { /* tw */
204 if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF)
205+#endif
206 if(floatval > 0.0 && floatval <= 1.0)
207 {
208 opts.Last_Column = -1;
209 opts.Last_Column_Percent = floatval;
210 }
211+#ifdef USE_PVM
212+ else {
213+ opts.Last_Column = (int) floatval; }
214+#else
215 else
216 opts.Last_Column = (int) floatval;
217+#endif
218 } /* tw */
219 return;
220
221 case END_ROW_OP:
222+#ifdef USE_PVM
223+ /* tw */
224+ if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF) {
225+#else
226 { /* tw */
227 if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF)
228+#endif
229 if(floatval > 0.0 && floatval <= 1.0)
230 {
231 opts.Last_Line = -1;
b7dcac6d 232@@ -1831,6 +1960,86 @@
1ca6bd2c
MP
233 Error ("Could not open Include_Ini='%s'.\n", value);
234 }
235 return;
236+
237+#ifdef USE_PVM
238+ /*
239+ * Options for PVMPOV
240+ */
241+ case PVM_TASKS_OP:
242+ if (sscanf(value, "%d", &PvmTasks) != 1 || PvmTasks < 1) {
243+ PvmTasks = 9999; /* Try to start one slave/available PVM host */
244+ }
245+ return;
246+
247+ case PVM_WIDTH_OP:
248+ if (sscanf(value, "%d", &PvmChunkWidth) != 1 || PvmChunkWidth < 4)
249+ PvmChunkWidth = PVM_DEFAULT_GRID_WIDTH;
250+ return;
251+
252+ case PVM_HEIGHT_OP:
253+ if (sscanf(value, "%d", &PvmChunkHeight) != 1 || PvmChunkHeight < 4)
254+ PvmChunkHeight = PVM_DEFAULT_GRID_HEIGHT;
255+ return;
256+
257+ case PVM_SLAVE_OP:
258+ PvmSlavename = POV_MALLOC( sizeof(char)*(strlen(value)+1),
259+ "PVM Slavename");
260+ strcpy(PvmSlavename, value);
261+ return;
262+
263+ case PVM_ARCH_OP:
264+ strncpy(PvmArch,value,19);
265+ PvmArch[19] = '\0';
266+
267+ if (PvmTasks < 1)
268+ PvmTasks = 9999; /* Try to start one slave/available PVM host */
269+ return;
270+
271+ case PVM_NICE_OP:
272+ if (sscanf(value, "%d", &PvmNice) != 1 || PvmNice < 0) {
273+ PvmNice = PVM_DEFAULT_NICE;
274+ }
275+ return;
276+
277+ case PVM_WD_OP:
278+ strncpy(PvmWorkingDir, value, PATH_MAX);
279+ return;
280+
281+ case PVM_HOSTS_OP: {
282+ char * c = value;
283+ char * c2;
284+ int n;
285+
286+ PvmHostsN = 1; /* count number of names */
287+ while((c = strchr(c, ',')) != NULL) {
288+ c ++;
289+ PvmHostsN ++;
290+ }
291+ PvmHosts = (char**)POV_MALLOC( sizeof(char*) * PvmHostsN, "PvmHosts");
292+
293+ c = value;
294+ c2 = strchr(c,',');
295+ for(i=0; i < PvmHostsN; i++) {
296+ n = (c2) ? c2 - c : strlen(c);
297+ PvmHosts[i] = (char*)POV_MALLOC( sizeof(char) * (n + 1), "PvmHosts[i]");
298+ strncpy(PvmHosts[i], c, n);
299+ PvmHosts[i][n] = '\0';
300+
301+ if(c2) c = c2 + 1;
302+ c2 = strchr(c, ',');
303+ }
304+
305+ PvmTasks = PvmHostsN;
306+
307+ return;
308+
309+ }
310+ case PVM_USE_OP:
311+ PvmTasks = istrue(value) ? 9999 : 0;
312+ return;
313+
314+#endif
315+
316
317 default:
318 Warning(0.0,"Unimplemented INI '%s'.\n",Option_Variable[variable].Token_Name);
319diff -Naur source.ori/optin.h source/optin.h
320--- source.ori/optin.h Sat Jun 30 01:49:21 2001
321+++ source/optin.h Sat Jun 30 03:43:53 2001
322@@ -19,6 +19,10 @@
323 * DKBTrace was originally written by David K. Buck.
324 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
325 *
326+*
327+* Oct 1996 : Added options for PVMPOV [Deischi]
328+* Jun 2001 : Added conditional build for PVM Support [Agaran]
329+*
330 *****************************************************************************/
331
332
333@@ -131,6 +135,19 @@
334 BITS_PER_COLOR_OP,
335 BITS_PER_COLOUR_OP,
336 INCLUDE_INI_OP,
337+
338+#ifdef USE_PVM
339+ /* new options for PVMPOV */
340+ PVM_TASKS_OP,
341+ PVM_WIDTH_OP,
342+ PVM_HEIGHT_OP,
343+ PVM_SLAVE_OP,
344+ PVM_ARCH_OP,
345+ PVM_NICE_OP,
346+ PVM_WD_OP,
347+ PVM_HOSTS_OP,
348+ PVM_USE_OP,
349+#endif
350
351 MAX_OPTION
352 } INI_OP;
353diff -Naur source.ori/optout.c source/optout.c
354--- source.ori/optout.c Sat Jun 30 01:49:21 2001
b7dcac6d 355+++ source/optout.c Sat Jun 30 13:56:11 2001
1ca6bd2c
MP
356@@ -19,6 +19,9 @@
357 * DKBTrace was originally written by David K. Buck.
358 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
359 *
360+* Oct 1996 : Added options for PVMPOV [Deischi]
361+* jun 2001 : added conditional build for pvm
362+*
363 *****************************************************************************/
364
365 #include <ctype.h>
366@@ -65,8 +68,9 @@
367 #include "povray.h"
368 #include "optin.h"
369 #include "optout.h"
370-
371-
372+#ifdef USE_PVM
373+#include "pvm.h"
374+#endif
375
376 /*****************************************************************************
377 * Local preprocessor defines
378@@ -611,6 +615,9 @@
379 * Dec 1994 : Changed to show options depending on parameter n. [DB]
380 *
381 * Feb 1995 : Changed to terminate only if f != 0. [DB]
382+*
383+* Oct 1996 : Added options from PVMPOV [Deischi]
384+* Jun 2001 : conditional build for pvm
385 *
386 ******************************************************************************/
387
388@@ -640,7 +647,12 @@
389 Banner(" 4 Output Options - file related\n");
390 Banner(" 5 Tracing Options\n");
391 Banner(" 6 Animation Options\n");
392+#ifdef USE_PVM
393+ Banner(" 7 PVM Options\n");
394+ Banner(" 8 Redirecting Options\n");
395+#else
396 Banner(" 7 Redirecting Options\n");
397+#endif
398
399 break;
400
b7dcac6d 401@@ -767,6 +779,45 @@
1ca6bd2c
MP
402
403 break;
404
405+#ifdef USE_PVM
406+ /* PVM options. */
407+
408+ case 7:
409+
410+ Banner("\n");
411+ Banner("PVM options\n");
412+ Banner("\n");
413+ Banner(" N = Turn on PVM\n");
414+ Banner(" NTnnn = Spawn number of tasks\n");
415+ Banner(" NAs = Spawn only on architecture\n");
416+ Banner(" NWnnn = Width of each chunk\n");
417+ Banner(" NHnnn = Height of each chunk\n");
418+ Banner(" NNnnn = Niceness of slaves\n");
419+ Banner(" NSs = Name of slaves (executable)\n");
420+ Banner(" NDnnn = Name of the working directory\n");
421+ Banner(" pvm_hosts = n,n,.. = List of hostnames to use\n");
422+ Banner("\n");
423+
b7dcac6d
MP
424+ break;
425+
426+ case 8:
427+
428+
1ca6bd2c
MP
429+ /* Redirecting options. */
430+
431+ Banner("\n");
432+ Banner("Redirecting options\n");
433+ Banner("\n");
434+ Banner(" GI<name>= write all .INI parameters to file name\n");
435+ Banner(" Gx<name>= write stream x to console and/or file name\n");
436+ Banner(" GA - All streams (except status)\n");
437+ Banner(" GD - Debug stream\n");
438+ Banner(" GF - Fatal stream\n");
439+ Banner(" GR - Render stream\n");
440+ Banner(" GS - Statistics stream\n");
441+ Banner(" GW - Warning stream\n");
442+#else
443+
444 /* Redirecting options. */
445
446 case 7:
b7dcac6d 447@@ -782,6 +833,7 @@
1ca6bd2c
MP
448 Banner(" GR - Render stream\n");
449 Banner(" GS - Statistics stream\n");
450 Banner(" GW - Warning stream\n");
451+#endif
452
453 break;
454
b7dcac6d 455@@ -867,7 +919,8 @@
1ca6bd2c
MP
456 *
457 * CHANGES
458 *
459-* -
460+* Oct 1996 : Added options from PVMPOV [Deischi]
461+* Jun 2001 : Added conditional build for PVM Support [Agaran]
462 *
463 ******************************************************************************/
464
b7dcac6d 465@@ -1089,6 +1142,26 @@
1ca6bd2c
MP
466 }
467
468 Render_Info("\n");
469+#if USE_PVM
470+ if(PvmTasks) {
471+ int i;
472+ Render_Info("PVM Options\n");
473+ Render_Info(" Block Width....%8d", PvmChunkWidth);
474+ Render_Info(" Block Height...%8d\n", PvmChunkHeight);
475+ Render_Info(" PVM Tasks......%8d\n", PvmTasks);
476+ Render_Info(" PVM Nice.......%8d\n", PvmNice);
477+ Render_Info(" PVM Arch....... %s\n", PvmArch);
478+ Render_Info(" PVM Slave...... %s\n", PvmSlavename ? PvmSlavename : "");
479+ Render_Info(" PVM WorkingDir. %s\n", PvmWorkingDir);
480+ if(PvmHosts) {
481+ Render_Info(" Pvm Hosts......");
482+ for(i=0; i < PvmHostsN; i++) {
483+ Render_Info(" %s", PvmHosts[i]);
484+ }
485+ Render_Info("\n");
486+ }
487+ }
488+#endif
489
490 /* Print redirecting options. */
491
492diff -Naur source.ori/optout.h source/optout.h
493--- source.ori/optout.h Sat Jun 30 01:49:21 2001
494+++ source/optout.h Sat Jun 30 02:17:45 2001
495@@ -19,6 +19,10 @@
496 * DKBTrace was originally written by David K. Buck.
497 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
498 *
499+* Oct 1996 : Added options for PVMPOV [Deischi]
500+* May 1999 : Changed code to work with POVRAY 3.1e [Flierl]
501+* Jun 2001 : conditional build for PVM [agaran]
502+*
503 *****************************************************************************/
504
505
506@@ -36,12 +40,19 @@
507 #define POV_RAY_VERSION "3.1g"
508
509 #define DISTRIBUTION_MESSAGE_1 "This is an unofficial version compiled by:"
510+#ifdef USE_PVM
511+#define DISTRIBUTION_MESSAGE_2 "Jakob Flierl <flierl@luga.de> - PVMPOV Version 3.1e.2"
512+#else
513 #define DISTRIBUTION_MESSAGE_2 "FILL IN NAME HERE........................."
514+#endif
515 #define DISTRIBUTION_MESSAGE_3 "The POV-Ray Team(tm) is not responsible for supporting this version."
516
517 /* Number of help pages (numbered 0 to MAX_HELP_PAGE). */
518-
519+#ifdef USE_PVM
520+#define MAX_HELP_PAGE 8
521+#else
522 #define MAX_HELP_PAGE 7
523+#endif
524
525
526
527diff -Naur source.ori/povray.c source/povray.c
528--- source.ori/povray.c Sat Jun 30 01:49:21 2001
b7dcac6d 529+++ source/povray.c Sat Jun 30 19:29:39 2001
1ca6bd2c
MP
530@@ -20,6 +20,10 @@
531 * DKBTrace was originally written by David K. Buck.
532 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
533 *
534+* Oct 1996 : Added options for PVMPOV [Deischi]
535+* May 1999 : Changed code to work with POVRAY 3.1e [Flierl]
536+* Jun 2001 : Added conditional build for PVM [Agaran]
537+*
538 *****************************************************************************/
539
540 #include <ctype.h>
541@@ -69,7 +73,9 @@
542 #include "userio.h" /*Error,Warning,Init_Text_Streams*/
543 #include "lbuffer.h"
544 #include "vbuffer.h"
545-
546+#ifdef USE_PVM
547+#include "pvm.h"
548+#endif
549
550 /*****************************************************************************
551 * Local preprocessor defines
552@@ -157,9 +163,15 @@
553 static void fix_up_rendering_window (void);
554 static void fix_up_animation_values (void);
555 static void fix_up_scene_name (void);
556+#ifdef USE_PVM
557+void set_output_file_handle (void);
558+void setup_output_file_name (void);
559+void open_output_file (void);
560+#else
561 static void set_output_file_handle (void);
562 static void setup_output_file_name (void);
563 static void open_output_file (void);
564+#endif
565 static void FrameRender (void);
566 static void init_statistics (COUNTER *);
567 static void sum_statistics (COUNTER *, COUNTER *);
568@@ -192,7 +204,8 @@
569 *
570 * CHANGES
571 *
572-* -
573+* Oct 1996 : Added PVM Support [Deischi]
574+* Jun 2001 : Added conditional build for PVM Support [Agaran]
575 *
576 ******************************************************************************/
577
578@@ -262,17 +275,31 @@
579 }
580 #endif
581
582+#ifdef USE_PVM
583+ /* If slave, turn off certain optiongs */
584+ if ( PvmSlave)
585+ opts.Options &= ~(DISPLAY | VERBOSE);
586+#endif
587+
588 /* Strip path and extension off input name to create scene name */
589 fix_up_scene_name ();
590
591 /* Redirect text streams [SCD 2/95] */
592 Open_Text_Streams();
593
594+#ifdef USE_PVM
595+ if ( !PvmSlave) {
596+ /* Write .INI file [SCD 2/95] */
597+ Write_INI_File();
598+
599+ ALT_WRITE_INI_FILE
600+ }
601+#else
602 /* Write .INI file [SCD 2/95] */
603 Write_INI_File();
604
605 ALT_WRITE_INI_FILE
606-
607+#endif
608 /* Make sure clock is okay, validate animation parameters */
609 fix_up_animation_values();
610
611@@ -282,9 +309,18 @@
612 /* Set output file handle for options screen. */
613 set_output_file_handle();
614
615+#ifdef USE_PVM
616+ /* Initialize PVM master */
617+ if ( !PvmSlave && PvmTasks)
618+ Pvm_Master_Init(argc, argv);
619+
620+ /* Print options used. */
621+ if ( !PvmSlave)
622+ Print_Options();
623+#else
624 /* Print options used. */
625 Print_Options();
626-
627+#endif
628 /* BEGIN SECTION */
629 /* VARIOUS INITIALIZATION THAT ONLY NEEDS TO BE DONE 1/EXECUTION */
630
631@@ -306,6 +342,32 @@
632
633 /* END SECTION */
634
635+#ifdef USE_PVM
636+ /* PVM Slave */
637+ if (PvmSlave ) {
638+ if( Pvm_Slave_Init() < 0)
639+ return;
640+
641+ Pvm_Slave_Control(); /* get the first block to do */
642+ while(PvmNextFrame <= opts.FrameSeq.FinalFrame) {
643+ /* set frame number */
644+ opts.FrameSeq.FrameNumber = PvmNextFrame;
645+ /* calculate clock value */
646+ opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock +
647+ ((DBL)(opts.FrameSeq.FrameNumber - opts.FrameSeq.InitialFrame)) *
648+ Clock_Delta;
649+
650+ FrameRender();
651+ }
652+
653+ Pvm_Slave_Exit();
654+
655+ Terminate_POV(0);
656+
657+ MAIN_RETURN_STATEMENT
658+ }
659+#endif
660+
661 /* Execute the first shell-out command */
662 Pre_Scene_Result=(POV_SHELLOUT_CAST)POV_SHELLOUT(PRE_SCENE_SHL);
663
b7dcac6d
MP
664@@ -313,6 +375,54 @@
665
1ca6bd2c
MP
666 if (Pre_Scene_Result != ALL_SKIP_RET)
667 {
1ca6bd2c 668+#ifdef USE_PVM
b7dcac6d 669+ if (Pre_Scene_Result != SKIP_ONCE_RET)
1ca6bd2c
MP
670+ if(!PvmSlave && PvmTasks) {
671+ START_TIME
672+ Pvm_Master_Control(); /* distribute work,
673+ and collect results,
674+ call shellout commands */
675+ STOP_TIME
676+ trender = TIME_ELAPSED
677+
678+ PRINT_STATS(totalstats);
679+ } else {
680+ for (opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame,
681+ opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock;
682+
683+ opts.FrameSeq.FrameNumber <= opts.FrameSeq.FinalFrame;
684+
685+ opts.FrameSeq.FrameNumber++,
686+ opts.FrameSeq.Clock_Value += Clock_Delta)
687+ {
b7dcac6d
MP
688+ setup_output_file_name();
689+
690+ /* Execute a shell-out command before tracing */
691+
692+ Frame_Result=(POV_SHELLOUT_CAST)POV_SHELLOUT(PRE_FRAME_SHL);
693+
694+ if (Frame_Result == ALL_SKIP_RET)
695+ {
696+ break;
697+ }
698+
699+ if (Frame_Result != SKIP_ONCE_RET)
700+ {
701+ FrameRender();
702+
703+ /* Execute a shell-out command after tracing */
704+
705+ Frame_Result = (POV_SHELLOUT_CAST)POV_SHELLOUT(POST_FRAME_SHL);
706+
707+ if ((Frame_Result==SKIP_ONCE_RET) || (Frame_Result==ALL_SKIP_RET))
708+ {
709+ break;
710+ }
711+ }
712+ }
713+ }
714+
1ca6bd2c 715+#else
b7dcac6d 716 if (Pre_Scene_Result != SKIP_ONCE_RET)
1ca6bd2c
MP
717 {
718 for (opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame,
b7dcac6d 719@@ -349,8 +459,10 @@
1ca6bd2c
MP
720 }
721 }
b7dcac6d
MP
722
723+
724+#endif
1ca6bd2c 725 /* Print total stats ... */
b7dcac6d
MP
726-
727+
1ca6bd2c 728 if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME)
b7dcac6d
MP
729 {
730 Statistics("\nTotal Statistics");
731@@ -371,7 +483,6 @@
732 /* And finish. */
733
734 Terminate_POV(0);
735-
736 MAIN_RETURN_STATEMENT
737 } /* main */
738
739@@ -399,6 +510,8 @@
1ca6bd2c
MP
740 * CHANGES
741 *
742 * Feb 1996: Make sure we are displaying when doing a mosaic preview [AED]
743+* Oct 1996: Added PVM support [Deischi]
744+* Jun 2001: Added conditional build for PVM Support [agaran]
745 *
746 ******************************************************************************/
747
b7dcac6d 748@@ -483,6 +596,30 @@
1ca6bd2c
MP
749 /* Save variable values. */
750 variable_store(STORE);
751
752+#ifdef USE_PVM
753+ if( !PvmSlave) {
754+
755+ /* Open output file and if we are continuing an interrupted trace,
756+ * read in the previous file settings and any data there. This has to
757+ * be done before any image-size related allocations, since the settings
758+ * in a resumed file take precedence over that specified by the user. [AED]
759+ */
760+ open_output_file();
761+
762+ /* Start the display. */
763+ if (opts.Options & DISPLAY)
764+ {
765+ Status_Info ("\nDisplaying...");
766+
767+ POV_DISPLAY_INIT(Frame.Screen_Width, Frame.Screen_Height);
768+
769+ Display_Started = TRUE;
770+
771+ /* Display vista tree. */
772+ Draw_Vista_Buffer();
773+ }
774+ } /* !PvmTasks */
775+#else
776 /* Open output file and if we are continuing an interrupted trace,
777 * read in the previous file settings and any data there. This has to
778 * be done before any image-size related allocations, since the settings
b7dcac6d 779@@ -502,15 +639,45 @@
1ca6bd2c
MP
780 /* Display vista tree. */
781 Draw_Vista_Buffer();
782 }
783-
784+#endif
785 /* Get things ready for ray tracing (misc init, mem alloc) */
786 Initialize_Renderer();
787+#ifdef USE_PVM
788+ /* If a PVM slave, re-assign Write_Line to PVM */
789+ if (PvmSlave) {
790+ Output_File_Handle->Write_Line_p = Pvm_Write_Line;
791+ }
792+#endif
793
794 /* This had to be taken out of open_output_file() because we don't have
795 * the final image size until the output file has been opened, so we can't
796 * initialize the display until we know this, which in turn means we can't
797 * read the rendered part before the display is initialized. [AED]
798 */
799+#ifdef USE_PVM
800+ if (!PvmSlave) {
801+ if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE))
802+ {
803+ Read_Rendered_Part(Actual_Output_Name);
804+
805+ if (opts.Last_Line > Frame.Screen_Height)
806+ opts.Last_Line = Frame.Screen_Height;
807+
808+ if (opts.Last_Column > Frame.Screen_Width)
809+ opts.Last_Column = Frame.Screen_Width;
810+ }
811+ } /* !PvmSlave */
812+ if(PvmSlave || !PvmTasks) {
813+ /* Get parsing time. */
814+ STOP_TIME
815+ tparse = TIME_ELAPSED
816+
817+ /* Get total parsing time. */
818+ tparse_total += tparse;
819+
820+ } /* PvmSlave || !PvmTasks */
821+
822+#else
823 if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE))
824 {
825 Read_Rendered_Part(Actual_Output_Name);
b7dcac6d 826@@ -529,7 +696,7 @@
1ca6bd2c
MP
827
828 /* Get total parsing time. */
829 tparse_total += tparse;
830-
831+#endif
832 /* Store start time for trace. */
833 START_TIME
834
b7dcac6d 835@@ -547,7 +714,65 @@
1ca6bd2c
MP
836 POV_PRE_RENDER
837
838 Status_Info ("\nRendering...\r");
839+#ifdef USE_PVM
840+ do {
b7dcac6d 841+
1ca6bd2c
MP
842+ /* Macro for setting up any special FP options */
843+ CONFIG_MATH
844+
845+ /* Ok, go for it - trace the picture. */
846+
847+ /* If radiosity preview has been done, we are continuing a trace, so it
848+ * is important NOT to do the preview, even if the user requests it, as it
849+ * will cause discontinuities in radiosity shading by (probably) calculating
850+ * a few more radiosity values.
851+ */
852+ if ( !opts.Radiosity_Preview_Done )
853+ {
854+ if ( opts.Options & RADIOSITY )
855+ {
856+ /* Note that radiosity REQUIRES a mosaic preview prior to main scan */
857+
858+ Start_Tracing_Mosaic_Smooth(opts.PreviewGridSize_Start, opts.PreviewGridSize_End);
859+ }
860+ else
861+ {
862+ if (opts.Options & PREVIEW && opts.Options & DISPLAY)
863+ {
864+ Start_Tracing_Mosaic_Preview(opts.PreviewGridSize_Start, opts.PreviewGridSize_End);
865+ }
866+ }
867+ }
868+
869+ switch (opts.Tracing_Method)
870+ {
871+ case 2 :
872+
873+ Start_Adaptive_Tracing();
874+
875+ break;
b7dcac6d 876
1ca6bd2c
MP
877+ case 1 :
878+ default:
879+
880+ Start_Non_Adaptive_Tracing();
881+ }
882+ } while(PvmSlave ? Pvm_Slave_Control() : 0); /* ask for more work */
883+
884+ /* We're done. */
885+
886+ /* Record time so well spent before file close so it can be in comments */
887+ STOP_TIME
888+ trender = TIME_ELAPSED
889+
890+ if(!PvmSlave) {
891+ /* Close out our file */
892+ if (Output_File_Handle)
893+ {
894+ Close_File(Output_File_Handle);
895+ }
896+ }
897+#else
898 /* Macro for setting up any special FP options */
899 CONFIG_MATH
900
b7dcac6d 901@@ -600,7 +825,7 @@
1ca6bd2c
MP
902 {
903 Close_File(Output_File_Handle);
904 }
905-
906+#endif
907 Stage = STAGE_SHUTDOWN;
908
909 POV_PRE_SHUTDOWN
b7dcac6d 910@@ -626,6 +851,27 @@
1ca6bd2c
MP
911 /* Get total render time. */
912 trender_total += trender;
913
914+#ifdef USE_PVM
915+ if(!PvmSlave) {
916+ POV_DISPLAY_FINISHED
917+
918+ if ((opts.Options & DISPLAY) && Display_Started)
919+ {
920+ POV_DISPLAY_CLOSE
921+
922+ Display_Started = FALSE;
923+ }
924+
925+ if (opts.histogram_on)
926+ write_histogram (opts.Histogram_File_Name) ;
927+ }
928+ Status_Info("\nDone Tracing");
929+
930+ /* Print stats ... */
931+ if(!PvmSlave)
932+ PRINT_STATS(stats);
933+
934+#else
935 POV_DISPLAY_FINISHED
936
937 if ((opts.Options & DISPLAY) && Display_Started)
b7dcac6d 938@@ -642,7 +888,7 @@
1ca6bd2c
MP
939
940 /* Print stats ... */
941 PRINT_STATS(stats);
942-
943+#endif
944 if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME)
945 {
946 /* Add them up */
b7dcac6d 947@@ -1030,8 +1276,11 @@
1ca6bd2c
MP
948 * NULL function pointer.
949 *
950 ******************************************************************************/
951-
952+#ifdef USE_PVM
953+void set_output_file_handle()
954+#else
955 static void set_output_file_handle()
956+#endif
957 {
958 char *def_ext = NULL;
959 char temp[FILE_NAME_LENGTH];
b7dcac6d 960@@ -1110,7 +1359,11 @@
1ca6bd2c
MP
961 * function appends a path separator on output.
962 *
963 ******************************************************************************/
964+#ifdef USE_PVM
965+void setup_output_file_name()
966+#else
967 static void setup_output_file_name()
968+#endif
969 {
970 char number_string[10];
971 char separator_string[2] = {FILENAME_SEPARATOR, 0} ;
b7dcac6d 972@@ -1219,8 +1472,11 @@
1ca6bd2c
MP
973 * -
974 *
975 ******************************************************************************/
976-
977+#ifdef USE_PVM
978+void open_output_file()
979+#else
980 static void open_output_file()
981+#endif
982 {
983 int Buffer_Size;
984
b7dcac6d 985@@ -1378,12 +1634,18 @@
1ca6bd2c
MP
986 opts.Radiosity_Nearest_Count = 6;
987 opts.Radiosity_Recursion_Limit = 1;
988 opts.Radiosity_Quality = 6; /* Q-flag value for light gathering */
989+#ifdef USE_PVM
990+ opts.Radiosity_File_ReadOnContinue = PvmSlave ? 0 : 1;
991+ opts.Radiosity_File_SaveWhileRendering = PvmSlave ? 0 : 1; /* Don't save radiostiry cache with PVM */
992+ opts.Radiosity_File_AlwaysReadAtStart = 0;
993+ opts.Radiosity_File_KeepOnAbort = PvmSlave ? 0 : 1;
994+#else
995 opts.Radiosity_File_ReadOnContinue = 1;
996 opts.Radiosity_File_SaveWhileRendering = 1;
997 opts.Radiosity_File_AlwaysReadAtStart = 0;
998 opts.Radiosity_File_KeepOnAbort = 1;
999+#endif
1000 opts.Radiosity_File_KeepAlways = 0;
1001-
1002
1003 init_statistics(stats);
1004 init_statistics(totalstats);
1005diff -Naur source.ori/pvm/PVMPOV.Changelog source/pvm/PVMPOV.Changelog
1006--- source.ori/pvm/PVMPOV.Changelog Thu Jan 1 01:00:00 1970
1007+++ source/pvm/PVMPOV.Changelog Sun Sep 12 00:25:35 1999
1008@@ -0,0 +1,17 @@
1009+ * 3.1e.2 [Jakob Flierl]
1010+ - fixed problem with the statistics collection in line 1331 of "pvm.c"
1011+ - minor changes in "sources/pvm/Makefile.aimk"
1012+ - updated documentation
1013+ - added "PVMPOV.Changelog" and "PVMPOV.benchmark"
1014+ * 3.1e.1 [Jakob Flierl]
1015+ - applied the patch to POV-Ray version 3.1e
1016+ - fixed at least partially a memory bug in "render.c". Thanks to Michael
1017+ Eilers for solving this problem at least partially.
1018+ * 3.0x [Harald Deischinger]
1019+ - applied the patch to POV-Ray 3.01 and 3.01
1020+ - several command line enhancements.
1021+ * 2.2 to 2.9 [Andreas Dilger]
1022+ - changes in optin.h, optin.c, optout.h, optout.c,
1023+ povray.c, render.h, render.c
1024+ - added pvm/Makefile.aimk, pvm/pvm.h, pvm/pvm.c
1025+ * Initial Version [Brad Kline, Cray Inc.]
1026diff -Naur source.ori/pvm/PVMPOV.benchmark source/pvm/PVMPOV.benchmark
1027--- source.ori/pvm/PVMPOV.benchmark Thu Jan 1 01:00:00 1970
1028+++ source/pvm/PVMPOV.benchmark Sun Sep 12 00:25:35 1999
1029@@ -0,0 +1 @@
1030+Surf to http://www.haveland.com/povbench/ to look at some render statistics.
1031diff -Naur source.ori/pvm/PVMPOV.example source/pvm/PVMPOV.example
1032--- source.ori/pvm/PVMPOV.example Thu Jan 1 01:00:00 1970
1033+++ source/pvm/PVMPOV.example Sun Sep 12 00:25:35 1999
1034@@ -0,0 +1,283 @@
1035+This file describes the command line options of PVMPOV, as well as the general
1036+theory behind how it operates.
1037+
1038+Theory of Operation
1039+-------------------
1040+Using the PVM model, there is one master and many slave tasks. The master has
1041+the responsibility of issuing the work sections to the slaves, and receiving
1042+portions of the rendered sections back. The master does not render anything
1043+by itself. The PVM component is only active if the user gives the "+N" option
1044+to POV. Otherwise, PVMPOV behaves the same as regular POV-Ray and runs a
1045+single task only on the local machine.
1046+
1047+Valid POV-Ray command-line options relating to PVM are:
1048+
1049+ pvm=on
1050+ +N This is the default for starting PVMPOV. One slave will be
1051+ started on each available host, regardless of architecture, and
1052+ the blocks will be 32x32 pixels in size. The slaves will be
1053+ started with a nice value of 5, which means they will run at a
1054+ lower priority than other user jobs.
1055+ pvm=off
1056+ -N Turns of PVM support. PVMPOV now runs exactly as normal POV-Ray.
1057+ You should do this when there are still errors in your pov-file.
1058+ PVMPOV will not display error message otherwise.
1059+
1060+ pvm_tasks=xx
1061+ +NTxx Start xx tasks on the available PVM hosts. This is usually only
1062+ useful if debugging on a single machine, or for starting more
1063+ than 1 task on multi-processor hosts. If, for example, you have
1064+ 10 machines with 4 CPUs each, you could specify +nt40 to start 4
1065+ processes on each host (and the OS will hopefully run 1 on each
1066+ CPU).
1067+
1068+ Note that PVM is stupid in the way it starts tasks, so if,
1069+ in the previous example, one of the hosts has only one CPU, it will
1070+ still have 4 slaves started on it. You can use the "pvm_hosts"
1071+ option (see below) to control on which machines the tasks are
1072+ started.
1073+
1074+ Starting multiple tasks on a single processor will always be less
1075+ efficient than a single task because of context switching and extra
1076+ message passing.
1077+
1078+ pvm_arch=arch
1079+ +NAarch Start the tasks only on the PVM architecture "arch". If +NT is not
1080+ given, one task will be started on each of the hosts of the given
1081+ architecture.
1082+
1083+ pvm_nice=xx
1084+ +NNxx Run the slaves at a niceness factor of xx. The default niceness
1085+ is 5. In general, changing the niceness value will not affect
1086+ performance very much, but may get others upset with you. The
1087+ nicest setting for pvmpov is 20, while the least nice setting is
1088+ 0. Note that these values are always used even on systems that
1089+ use nice values from 20-40. See the installation document and
1090+ the man page for nice for more information.
1091+
1092+ pvm_width=xx
1093+ +NWxx Change the width of the blocks to xx pixels. The default width
1094+ is 32 pixels.
1095+
1096+ pvm_height=xx
1097+ +NHxx Change the height of the blocks to xx pixels. The default height
1098+ is 32 pixels.
1099+
1100+ It is important to note that by varying the size of the grid
1101+ sections, you can affect the performance of the rendering. If you
1102+ have particular renderings that are very complex in a small portion
1103+ of the display, then a finer grain may help. In this way, more of
1104+ the tasks are able to migrate towards the grid sections that are
1105+ more complex. Conversely, if you have a shorter render or a
1106+ slower network, it may be advantageous to have larger blocks to
1107+ reduce network overhead, as well as ensure the slaves are not idle
1108+ waiting for blocks to render.
1109+
1110+ You must also consider overhead if using anti-aliasing. Anti-
1111+ aliasing requires the line segment above and below the grid section
1112+ to be traced so that super-sampling may occur. If the height of the
1113+ grid is reduced in size, and anti-aliasing is turned on, your
1114+ percentage of overhead goes up. For example, setting a height of
1115+ four (-NH4) using anti-aliasing would have more than 25% overhead.
1116+ If the image size is not an integer multiple of the grid size, the
1117+ edge blocks are smaller (ie extra pixels aren't rendered), so it
1118+ is not necessary to evenly divide the image into blocks.
1119+
1120+ pvm_slave=slave
1121+ +NSslave Uses slave as filename for the slave tasks. If you do not
1122+ specify this option PVMPOV will use the current executable name
1123+ also for the slaves.
1124+
1125+ Using this option you can for example run the X11 version
1126+ (x-pvmpov) as master (to display the results) and a version
1127+ without any display support (pvmpov) as slaves.
1128+
1129+ pvm_wd=dir
1130+ +NDdir Set the working directory for the slaves. By default PVMPOV
1131+ tries to run the slaves in the same directory, as the master.
1132+ But sometimes 'getcwd' gives misleading output (when automounting
1133+ is used), or you simply want to run the slaves in some other
1134+ directory, then you can use this option.
1135+
1136+ pvm_hosts=name1,name2,...
1137+ Set the names of the hosts to use for slaves. Note, that there are
1138+ not spaces allowed between the names!
1139+
1140+ By default PVM distributes the processes in some order to the
1141+ available machines. Sometimes the choice of PVM is not the best,
1142+ so you can specify explicitly which machines to use.
1143+
1144+ You can use more tasks, then you specify here. You can use the
1145+ options in this way: pvm_hosts=darkstar,darkstar,baby +nt6
1146+ This will start 6 tasks (+nt6 must come after the pvm_hosts),
1147+ 4 on darkstar and 2 on baby.
1148+
1149+
1150+For example, if I wanted to distribute an 1024x768 rendering and use eight PVM
1151+tasks to do the work, I would use the +NT8 option, and let the PVM master
1152+define 768 32x32 sections. Eight slave tasks would be launched, and when ready,
1153+they would request work to do from the master. The master then issues a column
1154+and row range back to the requesting slave.
1155+
1156+% pvmpov +nt8 +w1024 +h768 +iskyvase.pov +oskyvase.tga
1157+
1158+As each quarter of a grid is completed, the slave sends it back to the
1159+master, which buffers the incoming blocks until an entire line recieved, at
1160+which time it writes the line to disk with the specified file format. If
1161+all slaves did perfectly equal work in this example, they would be issued 96
1162+sections of work, and would have returned 384 messages of 32x8 pixels each.
1163+
1164+Note that the work issues are done essentially one at a time. As each slave
1165+starts up it requests a single block, and as it recieves a work request, it
1166+requests the next block. In this way, effective load balancing can occur.
1167+Tasks rendering the "easy" sections will eventually all migrate towards the
1168+harder sections. Seriously imbalanced distributions will be seen by widely
1169+varying percentages shown at the end of the rendering, assuming all of the
1170+hosts are identical. Since each slave always has a block to be rendered, it
1171+will be kept busy without waiting for the master to recieve its work request
1172+and reply with a new block assignment.
1173+
1174+If for some reason any of the slaves are very slow, or they are interrupted
1175+during their operation, their blocks are reassigned to other slaves after
1176+all of the blocks have been assigned a first time. This means that the render
1177+can be completed quickly even if some of the slaves have problems, or if some
1178+blocks have been assigned to slower slaves while the faster slaves are idle.
1179+This will show up as some percentage of late blocks for that machine in the
1180+statistics at the end. Note that blocks will NOT be reassigned to slaves that
1181+are significantly slower than average, in preference to reassigning it to a
1182+faster slave when it becomes available.
1183+
1184+Since only complete lines are written out to disk, interrupted traces will
1185+be restarted at the last complete line that was written to disk, regardless
1186+of how many blocks were buffered by the master at the time. However, it is
1187+possible to re-start an interrupted trace in the same method as POV-Ray.
1188+
1189+Known bugs (and other limitations)
1190+-------------------------------------
1191+All of the slaves must to share the same file system as the master process,
1192+and the source file must be mounted in the same location on each one. This
1193+may limit the number of hosts that can be used in some circumstances.
1194+
1195+The command line arguments for specifying hosts is not cumulative, so
1196+
1197+% pvmpov +naSUNMP +nt24 +n +iskyvase.pov +oskyvase.tga
1198+
1199+will not start 24 slaves on the multi-processor SUN system(s) (which may have
1200+4 CPUs each), and then start 1 slave on each of the remaining systems.
1201+
1202+The statistics for the image being rendered may not be accurate if any of the
1203+slaves is too slow, or stops for some reason. As well, since some sections
1204+may be rendered twice if the block is reassigned, the statistics will not be
1205+exactly the same as if it were rendered on a single host. The master only
1206+waits a few seconds for statistics to arrive before printing them.
1207+
1208+The master does not parse the input file. Because of that it displays
1209+no error messages concerning the input file. As long as your input file
1210+still contains error you should disable PVM support (-N or pvm=off)
1211+
1212+Execution example (from version 2.9):
1213+-------------------------------------
1214+You first must have a PVM daemon launched on each machine that will be
1215+participating in the rendering. Refer to the PVM 3.3 documentation. The
1216+following is an example is from Jason Hough, and was generated on a group
1217+of six Solaris based 4-processor SPARCstation 20s. His home directory is
1218+auto-mounted to all of these hosts.
1219+
1220+He keeps the pvm daemon installed in a directory called "bin", given by
1221+"dx=./bin/pvmd3" relative to his home directory, and pvmpov is in various
1222+subdirectories under "bin" (ie bin/SUN4, bin/SUNMP, bin/LINUX, etc.), given
1223+by the executable path "ex=./bin", so his pvm.hosts file looks like:
1224+
1225+% cat pvm.hosts
1226+glee dx=./bin/pvmd3 ep=./bin
1227+elation dx=./bin/pvmd3 ep=./bin
1228+ecstasy dx=./bin/pvmd3 ep=./bin
1229+bliss dx=./bin/pvmd3 ep=./bin
1230+delight dx=./bin/pvmd3 ep=./bin
1231+rapture dx=./bin/pvmd3 ep=./bin
1232+
1233+Note that, by default, PVM looks for executables in $HOME/pvm3/bin/$PVM_ARCH,
1234+and pvmd should be in $PVM_ROOT/lib, so if this is the case on your systems,
1235+you don't need to have anything in your pvm.hosts file except the hostnames,
1236+one per line. An exception is RS6K, which needs the dx= no matter what. See
1237+the PVM documentation and/or the pvmd3 man page for more information on what
1238+all of this means if you don't understand it.
1239+
1240+The following command launches the PVM daemons.
1241+
1242+% pvm pvm.hosts
1243+3.3.7
1244+t40001
1245+pvm> conf
1246+6 hosts, 1 data format
1247+ HOST DTID ARCH SPEED
1248+ glee 40000 SUNMP 1000
1249+ elation 80000 SUNMP 1000
1250+ ecstasy c0000 SUNMP 1000
1251+ bliss 100000 SUNMP 1000
1252+ delight 140000 SUNMP 1000
1253+ rapture 180000 SUNMP 1000
1254+pvm> quit
1255+
1256+pvmd still running.
1257+
1258+Now that the PVM daemons are up and waiting for work to do, we can render.
1259+Note that for these MP machines he forces pvmpov to start more tasks than
1260+the default 1 per host, and uses a 64x64 block size:
1261+
1262+% pvmpov -Iskyvase.pov -Oskyvase.tga +nt24 +nw64 +nh64 +v
1263+
1264+POV-Ray Options in effect: +v1 +ft +mb25 +nt24 +nn5 +nw64 +nh64 +a0.300
1265++j1.000 +b999 +r3 -q9 -w1024 -h768 -s1 -e768
1266+-k0.000 -mv2.0 -iskyvase.pov -oskyvase.tga
1267+ ...at least 13 tasks successfully spawned in time.
1268+ ...Don't worry, more are on the way, I'm just not waiting
1269+PVM Task Distribution: Tasks-24 Grid width-64 Grid height-64 Sections-192
1270+
1271+Waiting for slave stats.
1272+
1273+PVM Task Distribution Statistics:
1274+ host name [ done ] [ late ] host name [ done ] [ late ]
1275+ glee [ 4.17%] [ 0.00%] glee [ 4.17%] [ 0.00%]
1276+ glee [ 4.17%] [ 0.00%] glee [ 4.17%] [ 0.00%]
1277+ elation [ 4.69%] [ 0.00%] elation [ 4.17%] [ 0.00%]
1278+ elation [ 4.17%] [ 0.00%] elation [ 4.17%] [ 0.00%]
1279+ ecstasy [ 3.65%] [ 0.00%] ecstasy [ 4.69%] [ 0.00%]
1280+ ecstasy [ 4.69%] [ 0.00%] ecstasy [ 4.17%] [ 0.00%]
1281+ bliss [ 3.65%] [ 0.00%] bliss [ 4.17%] [ 0.00%]
1282+ bliss [ 4.69%] [ 0.00%] bliss [ 3.65%] [ 0.00%]
1283+ delight [ 3.65%] [ 0.00%] delight [ 4.17%] [ 0.00%]
1284+ delight [ 4.17%] [ 0.00%] delight [ 4.17%] [ 0.00%]
1285+ rapture [ 4.69%] [ 0.00%] rapture [ 4.17%] [ 0.00%]
1286+ rapture [ 4.17%] [ 0.00%] rapture [ 3.65%] [ 0.00%]
1287+
1288+
1289+skyvase.pov statistics
1290+--------------------------------------
1291+Resolution 1024 x 768
1292+# Rays: 3773743 # Pixels: 798720 # Pixels supersampled: 17381
1293+ Ray->Shape Intersection Tests:
1294+ Type Tests Succeeded Percentage
1295+ -----------------------------------------------------------
1296+ Sphere 6304452 1170727 18.57
1297+ Plane 63822062 35385552 55.44
1298+ Quadric 6304452 2770858 43.95
1299+ Cone 5918163 4839298 81.77
1300+ Bounds 5918163 3152226 53.26
1301+ Calls to Noise: 4327871
1302+ Calls to DNoise: 5141872
1303+ Shadow Ray Tests: 10498615 Blocking Objects Found: 254807
1304+ Reflected Rays: 2818594
1305+ Time For Trace: 0 hours 0 minutes 47.00 seconds
1306+
1307+------
1308+NB: Note that for comparison purposes with other skyvase benchmarks that this
1309+ is rendered at 1024x768 instead of the usual 640x480!
1310+
1311+Enjoy!
1312+
1313+Andreas Dilger
1314+adilger@enel.ucalgary.ca
1315+
1316+Harald Deischinger
1317+k3096e5@c210.edvz.uni-linz.ac.at
1318diff -Naur source.ori/pvm/PVMPOV.general source/pvm/PVMPOV.general
1319--- source.ori/pvm/PVMPOV.general Thu Jan 1 01:00:00 1970
1320+++ source/pvm/PVMPOV.general Sun Sep 12 00:25:35 1999
1321@@ -0,0 +1,98 @@
1322+
1323+ - PVMPOV - written by Andreas Dilger, June 1 1995
1324+ and Harald Deischinger, 1997
1325+ modified by Jakob Flierl, 1999
1326+
1327+
1328+***** NOTE - This is an UNOFFICIAL modification to POV-Ray 3.1e *****
1329+
1330+** DO NOT SEND PROBLEM REPORTS TO THE POV TEAM REGARDING THESE MODIFICATIONS. **
1331+
1332+The author disclaims all warranties with regard to this software, including
1333+all implied warranties of merchant-ability and fitness. The code is simply
1334+distributed as it is.
1335+
1336+
1337+General information
1338+-------------------
1339+
1340+"I only ask that credit (or blame) is attributed to me for the original work."
1341+ - Brad Kline
1342+
1343+The original author of the PVM POV-Ray patch on which this is based is Brad
1344+Kline, of Cray Research, Inc. Because of problems running the original code at
1345+my site, and a desire to learn more about PVM for my Master's work, I have
1346+changed large portions to not only be more user-friendly about reporting
1347+errors, but also hopefully more robust and faster.
1348+ - Andreas Dilger
1349+
1350+Because Andreas has other things to do, I have taken over the part of
1351+PVMing POV-Ray 3.1. If you have problems with this program, don't be afraid
1352+to ask me for help.
1353+
1354+Please send me a mail, if you're using PVMPOV Version 3.1e.2.
1355+ - Jakob Flierl
1356+Contact
1357+-------
1358+email : flierl@luga.de
1359+
1360+Important information/Problems
1361+------------------------------
1362+
1363+* This version is not tested very vell, so it is very likely, that you
1364+ find some errors - please tell me about them.
1365+
1366+ Especially the very time consuming new features (radiosity) are not
1367+ really tested.
1368+
1369+* Shellout commands are always done by the master process.
1370+
1371+* Now PVMPOV also supports animations. PVMPOV computes multiply frames
1372+ simultaniously, so it is not possible to do "recursive animations"
1373+ (like the desk example in povscn/level3). You have to run PVMPOV extra
1374+ for each frame.
1375+
1376+ All the pre-scene shellouts are done in the correct order, and the same
1377+ for the post-scene shellouts. BUT for example the pre-scene shellout for
1378+ frame 2, will be executed before the post-scene shellout for frame 1!
1379+
1380+ Field Rendering (+UF) is not working yet.
1381+
1382+* The X11 display now displays everything.
1383+ There are no longer "forgotten blocks".
1384+
1385+* The master process of PVMPOV does not parse the input file. So you will
1386+ NOT see errors in the .pov file - the slaves will simply not start.
1387+ So you should turn off PVM support (pvm=off or -N) while developing your
1388+ scene file.
1389+
1390+ You will also get no warning, if the slave can not find the input file.
1391+ The slave will simply never ask for work. Check "/tmp/pvml.<uid>" for
1392+ errors with the slaves.
1393+
1394+* You might get errors, that pvm can not find the executables for the slaves.
1395+ You can solve this in lot's of ways.
1396+ - Start pvmpov with an absolute filename,
1397+ e.g. '/usr/bin/pvmpov ...'
1398+ - Specify the absolute path for the slaves,
1399+ e.g. 'pvmpov -NS/usr/bin/pvmpov ...'
1400+ You can set this option in you '.povrayrc' file.
1401+ - Move your executables into ~/pvm3/bin/ARCH
1402+ - Use the 'ep=PATH' option in your hostfile
1403+ Read the PVM documentation for more information.
1404+
1405+* When using automount you might have the problem, that the slaves can't
1406+ change to the working directory. Use the +ND (pvm_wd) option.
1407+ Calling pvmpov with "+ND$PWD" should solve the problem.
1408+
1409+* For more information see "PVMPOV.1st_scene"
1410+
1411+Changed files
1412+-------------
1413+ optin.c Accept new options for PVMPOV
1414+ optin.h
1415+ optout.c Print new options and help texts for PVMPOV
1416+ optout.h
1417+ povray.c Major changes
1418+ render.c Minor changes
1419+ render.h
1420diff -Naur source.ori/pvm/PVMPOV.install source/pvm/PVMPOV.install
1421--- source.ori/pvm/PVMPOV.install Thu Jan 1 01:00:00 1970
1422+++ source/pvm/PVMPOV.install Sun Sep 12 00:25:35 1999
1423@@ -0,0 +1,39 @@
1424+How to compile and install PVMPOV.
1425+
1426+COMPILE
1427+-------
1428+Before compiling PVMPOV you must me sure to have PVM installed correctly.
1429+PVM is not included with this package. You have to download and install it
1430+manually: http://www.epm.ornl.gov/pvm/pvm_home.html
1431+
1432+After that you can compile and install PVMPOV:
1433+
1434+ tar xvfz pvmpov-3.1e.?.tgz <- unpack the PVMPOV distfiles
1435+ cd pvmpov3_1e_?
1436+ tar xvfz ~/povuni_s.tgz <- unpack the POV source from ftp://ftp.povray.org/
1437+[POV-Ray versions 3.1e - 3.1g are reported to work fine with PVMPOV 3.e1.2.]
1438+
1439+ ./inst-pvm <- apply the PVMPOV patch
1440+
1441+[This script applies the patch and searches for any rejected files.
1442+If there are any .rej-files the changes are not done correctly -
1443+you can try to do the changes by hand.]
1444+
1445+ cd pvmpov3_1e_?/povray31/source/pvm
1446+
1447+[You can choose:]
1448+ aimk newunix <- to create the UNIX text only binaries
1449+ aimk newsvga <- to create binaries for svgalib (Linux only)
1450+ aimk newxwin <- to create binaries using X11 to display
1451+
1452+This should create the executables 'pvmpov', 's-pvmpov' or 'x-pvmpov'.
1453+
1454+INSTALL
1455+------
1456+If your are running PVMPOV on a homogenous cluster, you can copy the
1457+executables to "/usr/bin" and "/usr/X11R6/bin".
1458+
1459+Read "PVMPOV.example" to get started.
1460+
1461+Jakob Flierl, flierl@luga.de
1462+May 1999
1463diff -Naur source.ori/pvm/PVMPOV.radiosity source/pvm/PVMPOV.radiosity
1464--- source.ori/pvm/PVMPOV.radiosity Thu Jan 1 01:00:00 1970
1465+++ source/pvm/PVMPOV.radiosity Sun Sep 12 00:25:35 1999
1466@@ -0,0 +1,39 @@
1467+[...] PVMPOV and radiosity:
1468+
1469+Radiosity is currently not working with PVMPOV; the resulting images look like
1470+mosaics. There's a currently only a workaround suggested by Andreas Dilger:
1471+
1472+You must create a .rca file for the whole image [when rendering with the
1473+radiosity option turned on], which I did manually by running
1474+"pvmpov -n +qr +d +i <scene>.pov" and stopping the rendering when the mosaic
1475+preview is complete, to give me <scene>.rca. Then I started a new
1476+"pvmpov +c +qr +d +i <scene>.pov +nt2" on my 2 CPU system, and it rendered
1477+the same image as letting "pvmpov -n +qr +d +i <scene>.pov" finish on 1 CPU.
1478+The <scene>.rca file was readable by both slave systems because they were local,
1479+but it would also be possible to use NFS for this, like normal PVMPOV.
1480+This is some work to do manually, but it will ensure that the radiosity
1481+will work properly with PVMPOV.
1482+
1483+[for programmers only:]
1484+What needs to be done now is to have the PVMPOV master run the mosaic
1485+preview for radiosity before the slave tasks start. It looks like this
1486+could be done in pvm.c:PvmStartFrame(), but the current design of the
1487+master doesn't allow it to do any rendering because it does not parse
1488+the scene, so it would need to be reworked to do this.
1489+
1490+In the old PVMPOV 2.2 design, the master did the parsing of the scene
1491+file to ensure that the syntax was correct. I think this is the better
1492+design. If radiosity is used, the master will render the preview before
1493+the rendering is started on the slaves, so the .rca file is available.
1494+If the master does the parsing, then it can also send the data to the
1495+slaves via the POB binary file format through PVM (no NFS needed) so we
1496+don't waste the time spent parsing the scene at the master.
1497+
1498+I think what needs to be done is modify povray.c so it doesn't call
1499+Pvm_Master_Control() instead of FrameRender() in povray.c:398. Then
1500+FrameRender() should be modified to work with PVMPOV code, replacing
1501+PvmStartFrame() entirely. This will mean that PVMPOV will render one
1502+frame at a time, which is OK I think, because it means that some of
1503+the problems with PVMPOV 3.x will be fixed, like post-scene shellouts.
1504+I think it will also make PVMPOV less complex also, because it only
1505+has to work on 1 frame at a time.
1506diff -Naur source.ori/pvm.c source/pvm.c
1507--- source.ori/pvm.c Thu Jan 1 01:00:00 1970
1508+++ source/pvm.c Sun Sep 12 00:25:35 1999
1509@@ -0,0 +1,1556 @@
1510+/****************************************************************************
1511+* pvm.c
1512+*
1513+* This module implements the PVM control routines for PVM'd POVRAY.
1514+*
1515+* This file was written by Brad Kline. April 1994.
1516+* modified by Andreas Dilger Jan - May 1995
1517+* modified by Harald Deischinger, 1996 - 1997
1518+*
1519+* NOTE - PVM is not supplied here.
1520+*
1521+* You need the PVM 3.x libraries, include files, and PVMD daemons.
1522+*
1523+* PVM is available from the University of Tennessee, Knoxville, TN.
1524+*
1525+* The author disclaims all warranties with regard to this software,
1526+* including all implied warranties of merchant-ability and fitness.
1527+* The code is simply distributed as it is.
1528+*
1529+* 970610 - New option PVM_WD. To specify a working directory for
1530+* the slaves. [Deischi]
1531+* New option PVM_Hosts. To give names for hosts to use
1532+* as slaves. [Deischi]
1533+*
1534+* 9704.. - changed to to animations, lots of changes
1535+* simplifications to the whole thing [Deischi]
1536+*
1537+* 96.... - Changed code to work with POVRAY 3.0 [Deischi]
1538+*
1539+* 950508 - Changed code that allocates blocks to be more robust.
1540+* Changed the write_line routines to hook into the existing routines.
1541+* Changed the slave startup processes to be more informative.
1542+*
1543+* 940511 - Remove code that tried to fit grid sections into whole parts. The
1544+* code now supports odd sized images.
1545+*
1546+*****************************************************************************/
1547+#include <sys/time.h>
1548+#include <sys/resource.h>
1549+#include "frame.h"
1550+#include "vector.h"
1551+#include "povproto.h"
1552+#include "frame.h"
1553+#include "povray.h"
1554+#include "render.h"
1555+#include "optout.h"
1556+#include "pvm3.h"
1557+#include "pvm.h"
1558+
1559+
1560+/* This distribution scheme breaks down the image into to two dimensional
1561+ * areas. Each area has a designated grid control point. The grid area
1562+ * is up to PvmChunkWidth (-NWxx) pixels wide by PvmChunkHeight (-NHxx)
1563+ * high. If one uses the default, then a grid section would be 32x32, or
1564+ * 1024 pixels. In a 640x480 image, this would create 300 grid control
1565+ * points, and therefore 300 different sections to do work on (not lines.).
1566+ */
1567+
1568+/*
1569+ * clock value in shellout command is not working correctly
1570+ * timings are not displayed (and done) correctly
1571+ * statistics can be wrong
1572+ * continue trace might produce wrong results -- needs testing
1573+ */
1574+
1575+/*
1576+ * Global variables
1577+ */
1578+char PvmArch[20] = { 0 };
1579+int PvmChunkHeight = PVM_DEFAULT_GRID_HEIGHT; /* height of a block */
1580+int PvmChunkWidth = PVM_DEFAULT_GRID_WIDTH; /* widht of a block */
1581+int PvmRowsToSend = 1;
1582+int PvmSlave = 0;
1583+int PvmTasks = 9999;
1584+int PvmNice = PVM_DEFAULT_NICE;
1585+int PvmMTid;
1586+int PvmBlockNum;
1587+char * PvmSlavename = NULL;
1588+int PvmNextFrame = 0;
1589+char PvmWorkingDir[PATH_MAX+1] = ""; /* PVM Working Directory */
1590+char ** PvmHosts = NULL;
1591+int PvmHostsN = 0;
1592+
1593+/*
1594+ * local functions
1595+ */
1596+static void PvmSpawnError PARAMS((int));
1597+static void PvmSpawnTidError PARAMS((int));
1598+static void PvmSpawn PARAMS((void));
1599+static void PvmCheckFirst PARAMS((void));
1600+static void PvmInitSlaveStat PARAMS((void));
1601+static void PvmInitFrameStat PARAMS((void));
1602+
1603+static int PvmMasterReceive PARAMS((void));
1604+static void PvmIdentifySlave PARAMS((void));
1605+static void PvmSendWork PARAMS((int block));
1606+static void PvmReassignWork PARAMS((int block));
1607+static void PvmAssignWork PARAMS((void));
1608+static void PvmMasterEnd PARAMS((void));
1609+static int PvmStartFrame PARAMS((void));
1610+static void PvmFinishFrame PARAMS((void));
1611+static void PvmReceiveData PARAMS((void));
1612+static void PvmWrite PARAMS((void));
1613+
1614+static void PvmUnpackStats PARAMS((void));
1615+
1616+
1617+static int grid_points; /* number of grid blocks for one frame */
1618+static int grid_ppline; /* Number of grid blocks in a row */
1619+static int frames; /* num. of frames to do */
1620+static int frame = -1; /* the current frame, start with 0 to count */
1621+static int next_frame_finish;
1622+static int frame_display; /* the frame that is displayed */
1623+
1624+static int grid_lines_done = 0; /* num. of PvmCthunkWidth lines done (only statistics) */
1625+
1626+static int npixels_done = 0; /* Number of pixels done, by all processors */
1627+
1628+static int row_start; /* First row in the block */
1629+static int row_end; /* Last row in the block */
1630+static int col_start; /* First column in the block */
1631+static int col_end; /* Last column in the block */
1632+static int msgtag;
1633+
1634+static struct timeval wait_time; /* Time to wait for slave stats */
1635+static struct pvmhostinfo *hostinfo; /* Info on each PVM host */
1636+static int minions; /* Number of slave tasks */
1637+static int nhost; /* Number of available pvm hosts */
1638+static pvm_slave_stat *slave_stat; /* Info on the slaves */
1639+static pvm_frame_stat *frame_stat;
1640+static int rtid; /* tid of the message sender */
1641+static int *tids; /* tids of all the slaves */
1642+static int slave_num; /* Relative host number of sender */
1643+static char *slave_name; /* Hostname of sending slave */
1644+static int nstat = 0; /* Number of slaves returning stats */
1645+
1646+static int bitmask; /* Start tasks on a specific arch */
1647+static int bufid; /* pvm recieve buffer id */
1648+static int bytesin; /* Size of message */
1649+static char **sargs; /* argv for the slaves */
1650+static char slave_option[PATH_MAX+4]; /* the directory argument */
1651+
1652+
1653+/* in povray.c */
1654+extern char Actual_Output_Name[FILE_NAME_LENGTH];
1655+void setup_output_file_name PARAMS((void));
1656+void open_output_file PARAMS((void));
1657+void set_output_file_handle();
1658+
1659+
1660+
1661+/********************************************************************************
1662+ * Initialize Master Process
1663+ *******************************************************************************/
1664+
1665+
1666+/*
1667+ * Spawn the slaves, and check for errors
1668+ */
1669+
1670+/* handle an error from pvm_spawn */
1671+static void PvmSpawnError(m)
1672+ int m;
1673+{
1674+ /* Only quit if we can't start many tasks, or an error condition. */
1675+ Error_Line( "...error spawning tasks because \n");
1676+ switch (m) {
1677+ case PvmBadParam:
1678+ Error_Line("of bad parameter.\n");
1679+ break;
1680+ case PvmNoHost:
1681+ Error_Line("host not in PVM.\n");
1682+ break;
1683+ case PvmNoFile:
1684+ Error_Line("executable not found.\n");
1685+ break;
1686+ case PvmNoMem:
1687+ Error_Line("no memory on host.\n");
1688+ break;
1689+ case PvmSysErr:
1690+ Error_Line("pvmd not responding.\n");
1691+ break;
1692+ case PvmOutOfRes:
1693+ Error_Line("lack of resources.\n");
1694+ break;
1695+ default:
1696+ Error_Line("of unknown error.\n");
1697+ }
1698+ pvm_perror("");
1699+ pvm_exit();
1700+ close_all();
1701+ exit(1);
1702+}
1703+
1704+static void PvmSpawnTidError(tid)
1705+ int tid;
1706+{
1707+
1708+ Warning(0.0, "...spawn failure because ");
1709+ switch (tid) {
1710+ case PvmBadParam:
1711+ Warning(0.0, "of bad parameter.\n");
1712+ break;
1713+ case PvmNoHost:
1714+ Warning(0.0, "host not in PVM.\n");
1715+ break;
1716+ case PvmNoFile:
1717+ Warning(0.0, "executable not found.\n");
1718+ break;
1719+ case PvmNoMem:
1720+ Warning(0.0, "no memory on host.\n");
1721+ break;
1722+ case PvmSysErr:
1723+ Warning(0.0, "pvmd not responding.\n");
1724+ break;
1725+ case PvmOutOfRes:
1726+ Warning(0.0, "lack of resources.\n");
1727+ break;
1728+ default:
1729+ Warning(0.0, "of unknown error.\n");
1730+ }
1731+}
1732+
1733+static void PvmSpawn() {
1734+ int i;
1735+
1736+ /* Start up the slave processes */
1737+ if (PvmArch[0] != '\0') {
1738+ Status_Info(" Spawning %s with %d PVM tasks on arch %s...\n",
1739+ PvmSlavename, PvmTasks,PvmArch);
1740+ } else {
1741+ Status_Info(" Spawning %s with %d PVM tasks on %d hosts...\n",
1742+ PvmSlavename, PvmTasks,nhost);
1743+ }
1744+
1745+ if(PvmHosts) { /* start at specified hosts */
1746+ int m;
1747+ minions = 0;
1748+ for(i=0; i < PvmTasks; i++) { /* start one by one */
1749+ m = pvm_spawn(PvmSlavename, sargs, PvmTaskHost, PvmHosts[i % PvmHostsN],
1750+ 1, tids+minions);
1751+ if( m < 0) { /* spawn failed */
1752+ PvmSpawnError(m);
1753+ } else if (m==0) { /* failed a little bit */
1754+ PvmSpawnTidError(tids[minions]);
1755+ }
1756+ minions += m;
1757+ }
1758+
1759+ } else { /* start all at once somwhere */
1760+ minions = pvm_spawn(PvmSlavename, sargs, bitmask, PvmArch, PvmTasks, tids);
1761+
1762+ if(minions < 0) /* check for total failure */
1763+ PvmSpawnError(minions);
1764+ for (i = minions; i < PvmTasks; i++) /* errors/process */
1765+ PvmSpawnTidError(tids[i]);
1766+ }
1767+
1768+ /* Check if "few" tasks could be started */
1769+ if (minions < (PvmTasks + 1) / 2) {
1770+ if(minions==0) {
1771+ Error_Line("...No tasks");
1772+ } else {
1773+ Error_Line("...only %d of %d tasks", minions, PvmTasks);
1774+ }
1775+ Error_Line(" spawned! Quitting.\n");
1776+ pvm_exit();
1777+ close_all();
1778+ exit(1);
1779+ } else {
1780+ Status_Info(" ...%d PVM tasks successfully spawned.\n", minions);
1781+ }
1782+
1783+ PvmTasks = minions;
1784+}
1785+
1786+
1787+/*
1788+ * Wait up to 120 seconds for the first to check in
1789+ */
1790+static void PvmCheckFirst() {
1791+ wait_time.tv_sec = 120;
1792+ wait_time.tv_usec = 0;
1793+
1794+ Status_Info(" Waiting up to %lds for first slave to start...\n",
1795+ wait_time.tv_sec);
1796+ minions = 0;
1797+
1798+ if( pvm_trecv(-1, PVM_INIT_SLAVE, &wait_time) <= 0 ) {
1799+ /* No slave checked in. Something is wrong */
1800+ Error_Line("First slave did not start in time! Quitting.\n");
1801+ Error_Line("See /tmp/pvml.<your uid> on the master PVM host for\n");
1802+ Error_Line("more info on why the slave didn't start correctly.\n");
1803+ pvm_exit();
1804+ close_all();
1805+ exit(1);
1806+ } else {
1807+ minions++;
1808+ }
1809+
1810+ if (opts.Options & VERBOSE) {
1811+ Status_Info(" Slave 0 successfully started.\n");
1812+ }
1813+}
1814+
1815+
1816+/*
1817+ * Get a status struct for each slave
1818+ */
1819+static void PvmInitSlaveStat() {
1820+
1821+ slave_stat = (pvm_slave_stat *)POV_CALLOC(PvmTasks, sizeof(pvm_slave_stat), "slave_stat");
1822+
1823+ /* Set up pointers to all the host names and the slave status */
1824+ for (slave_num = 0; slave_num < PvmTasks; slave_num++) {
1825+ int j;
1826+ int dtid;
1827+
1828+ dtid = pvm_tidtohost(tids[slave_num]);
1829+ slave_stat[slave_num].name = "unknown";
1830+
1831+ for (j = 0; j < nhost; j++) {
1832+ if (dtid == hostinfo[j].hi_tid) {
1833+ slave_stat[slave_num].name = (char*)POV_CALLOC(strlen(hostinfo[j].hi_name)+1,
1834+ sizeof(char), "hostnames");
1835+ strcpy(slave_stat[slave_num].name,hostinfo[j].hi_name);
1836+ break;
1837+ }
1838+ }
1839+ slave_stat[slave_num].frame_assigned = PVM_SLAVE_FREE;
1840+ slave_stat[slave_num].block_reassigned = PVM_SLAVE_FREE;
1841+ }
1842+}
1843+
1844+/*
1845+ * Get a status struct for each frame
1846+ */
1847+static void PvmInitFrameStat() {
1848+ int i,j;
1849+
1850+ frames = (opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME) ?
1851+ opts.FrameSeq.FinalFrame - opts.FrameSeq.InitialFrame + 1 :
1852+ 1;
1853+ frame_stat = (pvm_frame_stat *)POV_CALLOC(frames, sizeof(pvm_frame_stat), "frame_stat");
1854+ frame_display = -1;
1855+
1856+ for(i=0; i < frames; i++) {
1857+ frame_stat[i].block_to_assign = 0;
1858+ frame_stat[i].block_to_reassign = 0;
1859+
1860+ frame_stat[i].block_to_write = 0;
1861+
1862+ frame_stat[i].row_to_write = opts.First_Line;
1863+ frame_stat[i].row_to_malloc = opts.First_Line;
1864+
1865+ frame_stat[i].block_stat =
1866+ (pvm_block_stat *)POV_CALLOC(grid_points, sizeof(pvm_block_stat), "block_stat");
1867+
1868+ for(j=0; j < MaxStat; j++)
1869+ Init_Counter(frame_stat[i].stats[j]);
1870+ }
1871+}
1872+
1873+/*
1874+ * Initialize PVM Master
1875+ */
1876+void
1877+Pvm_Master_Init(argc, argv)
1878+ int argc;
1879+ char **argv;
1880+{
1881+ int i;
1882+
1883+ Status_Info("Initializing PVMPOV\n");
1884+
1885+ /* Get a table for the TIDs */
1886+ tids = (int *)POV_CALLOC(PvmTasks, sizeof(int), "tids");
1887+
1888+ /* Build a new arg list for the sub-tasks - add -ni in front */
1889+ sargs = (char **)POV_CALLOC(argc + 1, sizeof(char *), "sargs");
1890+
1891+ /* Move argument pointers to new list array, keep position 0 free for -ni option */
1892+ for (i = 1; i < argc; i++) {
1893+ sargs[i] = argv[i];
1894+ }
1895+
1896+ /* Get current directory for the slave tasks */
1897+ if(PvmWorkingDir[0] == '\0')
1898+ if ( GETCWD(PvmWorkingDir) == NULL) {
1899+ Error("PVM Master cannot get current directory.\n");
1900+ return;
1901+ }
1902+
1903+ /* Add slave flag */
1904+ sprintf(slave_option, "-nI%s", PvmWorkingDir);
1905+ sargs[0] = slave_option;
1906+
1907+ /* Enroll in PVM */
1908+ if (pvm_mytid() < 0) {
1909+ Error("Error starting master task.\n");
1910+ }
1911+
1912+ if (pvm_config(&nhost, (int *)NULL, &hostinfo) < 0) {
1913+ pvm_exit();
1914+ Error("Error getting PVM machine status.\n");
1915+ }
1916+
1917+ bitmask = PvmTaskDefault;
1918+
1919+ /* If PvmArch is specified, use that architecture */
1920+ if (PvmArch[0] != '\0') {
1921+ bitmask = PvmTaskArch;
1922+
1923+ /* If arch is psecified, but not the number of tasks, go and
1924+ * count how many hosts of that type there are.
1925+ */
1926+ if (PvmTasks >= 9999) {
1927+ PvmTasks = 0;
1928+
1929+ for (i = 0; i < nhost; i++) {
1930+ if (strcmp(PvmArch,hostinfo[i].hi_arch) == 0)
1931+ PvmTasks++;
1932+ }
1933+ }
1934+ }
1935+
1936+ /* If PvmTasks is specified, use that many tasks, otherwise use
1937+ * as many hosts as possible.
1938+ */
1939+ if (PvmTasks >= 9999) {
1940+ PvmTasks = nhost;
1941+ }
1942+
1943+ /* if no slavename was given, use name of current executable */
1944+ if(PvmSlavename == NULL)
1945+ PvmSlavename = argv[0];
1946+
1947+ PvmSpawn(); /* spawn the slaves */
1948+ PvmCheckFirst(); /* wait for first slave */
1949+
1950+ pvm_setopt(PvmRoute, PvmRouteDirect);
1951+
1952+ /* Max # of pixels in a grid row */
1953+ PvmChunkWidth = min(PvmChunkWidth, opts.Last_Column - opts.First_Column);
1954+
1955+ /* Grid points per line - rounded up */
1956+ grid_ppline = (opts.Last_Column - opts.First_Column + PvmChunkWidth - 1) / PvmChunkWidth;
1957+
1958+ /* Establish grid section height */
1959+ PvmChunkHeight = min(PvmChunkHeight, opts.Last_Line - opts.First_Line);
1960+
1961+ /* Total grid points in the image - round up PvmChunkHeight */
1962+ grid_points = ((opts.Last_Line - opts.First_Line + PvmChunkHeight - 1) / PvmChunkHeight) *
1963+ grid_ppline;
1964+
1965+ PvmInitSlaveStat();
1966+ PvmInitFrameStat();
1967+
1968+ /* initialize total stats */
1969+ for(i=0; i < MaxStat; i++) {
1970+ Init_Counter(totalstats[i]);
1971+ }
1972+}
1973+
1974+
1975+
1976+
1977+
1978+/********************************************************************************
1979+ * Master Control
1980+ ********************************************************************************/
1981+
1982+/*
1983+ * Receive a message
1984+ */
1985+static int PvmMasterReceive() {
1986+
1987+ /* wait for a message from the slaves */
1988+ if ((bufid = pvm_trecv(-1, -1, &wait_time)) < 0) {
1989+ Error_Line( "PVM Master cannot receive.\n");
1990+ pvm_perror("");
1991+ pvm_exit();
1992+ exit(1);
1993+ }
1994+
1995+ /* We timed out waiting for any messages */
1996+ if (bufid == 0) {
1997+ Status_Info(".");
1998+ fflush(stderr);
1999+
2000+ return 1;
2001+ }
2002+
2003+ return 0;
2004+}
2005+
2006+/*
2007+ * Find name and number of slave, of current message
2008+ */
2009+static void PvmIdentifySlave() {
2010+
2011+ /* get info about this msg. */
2012+ if (pvm_bufinfo(bufid, &bytesin, &msgtag, &rtid) < 0) {
2013+ Error_Line( "PVM Master cannot bufinfo.\n");
2014+ pvm_perror("");
2015+ pvm_exit();
2016+ return;
2017+ }
2018+
2019+ /* find the name of the slave, sending the msg. */
2020+ slave_name = "unknown";
2021+ for (slave_num = 0; slave_num < PvmTasks; slave_num++) {
2022+ if (tids[slave_num] == rtid) {
2023+ slave_name = slave_stat[slave_num].name;
2024+ break;
2025+ }
2026+ }
2027+}
2028+
2029+/*
2030+ * Send a PVM_WORK message
2031+ * Set block to PVM_GRID_POINT_ASSIGNED
2032+ */
2033+static void PvmSendWork(block)
2034+ int block;
2035+{
2036+ int row_start, row_end, col_start, col_end;
2037+#ifdef DEBUG
2038+ Status_Info("Assigning block: %d, frame: %d of %d to %s.\n", block, frame, frames, slave_name);
2039+#endif /* DEBUG */
2040+
2041+ frame_stat[frame].block_stat[block].status = PVM_GRID_POINT_ASSIGNED;
2042+ frame_stat[frame].block_stat[block].assigned_tid = rtid;
2043+
2044+ row_start = (block/grid_ppline) * PvmChunkHeight + opts.First_Line;
2045+ row_end = (row_start + PvmChunkHeight) - 1;
2046+
2047+ if (row_end >= opts.Last_Line)
2048+ row_end = opts.Last_Line - 1;
2049+
2050+ col_start = (block%grid_ppline) * PvmChunkWidth + opts.First_Column;
2051+ col_end = (col_start + PvmChunkWidth) - 1;
2052+
2053+ if (col_end >= opts.Last_Column)
2054+ col_end = opts.Last_Column - 1;
2055+
2056+ pvm_initsend(PvmDataDefault);
2057+ pvm_pkint(&frame,1,1);
2058+ pvm_pkint(&block,1,1);
2059+ pvm_pkint(&row_start,1,1);
2060+ pvm_pkint(&row_end,1,1);
2061+ pvm_pkint(&col_start,1,1);
2062+ pvm_pkint(&col_end,1,1);
2063+ if (pvm_send(rtid, PVM_WORK) < 0) {
2064+ Error_Line( "PVM Master can't send to slave on %s.\n",slave_name);
2065+ pvm_perror("");
2066+ pvm_exit();
2067+ exit(1);
2068+ }
2069+
2070+ frame_stat[frame].block_to_assign ++;
2071+}
2072+
2073+/*
2074+ * Send a PVM_WORK message
2075+ * Set block to PVM_GRID_POINT_REASSIGNED
2076+ */
2077+static void PvmReassignWork(block)
2078+ int block;
2079+{
2080+#ifdef DEBUG
2081+ Status_Info("Reassigning %d to %s.\n", block,
2082+ slave_name);
2083+#endif /* DEBUG */
2084+
2085+ frame_stat[frame].block_stat[block].status=PVM_GRID_POINT_REASSIGNED;
2086+ frame_stat[frame].block_stat[block].reassigned_tid = rtid;
2087+ slave_stat[slave_num].block_reassigned = block;
2088+
2089+ if (frame_stat[frame].block_stat[block].wr_line == 0) {
2090+ row_start = (block / grid_ppline)*PvmChunkHeight + opts.First_Line;
2091+ } else {
2092+ row_start = frame_stat[frame].block_stat[block].wr_line;
2093+ }
2094+ row_end = (block/grid_ppline + 1) * PvmChunkHeight - 1;
2095+
2096+ if (row_end >= opts.Last_Line)
2097+ row_end = opts.Last_Line - 1;
2098+
2099+ col_start = (block % grid_ppline) * PvmChunkWidth +
2100+ opts.First_Column;
2101+ col_end = (col_start + PvmChunkWidth) - 1;
2102+
2103+ if (col_end >= opts.Last_Column)
2104+ col_end = opts.Last_Column - 1;
2105+
2106+ pvm_initsend(PvmDataDefault);
2107+ pvm_pkint(&frame,1,1);
2108+ pvm_pkint(&block,1,1);
2109+ pvm_pkint(&row_start,1,1);
2110+ pvm_pkint(&row_end,1,1);
2111+ pvm_pkint(&col_start,1,1);
2112+ pvm_pkint(&col_end,1,1);
2113+ if (pvm_send(rtid, PVM_WORK) < 0) {
2114+ Error_Line( "PVM Master can't send to slave on %s.\n",slave_name);
2115+ pvm_perror("");
2116+ pvm_exit();
2117+ exit(1);
2118+ }
2119+
2120+ frame_stat[frame].block_to_reassign++;
2121+}
2122+
2123+
2124+/*
2125+ * Do all the stuff, that is necessary for a new frame
2126+ * This is called before the PVM_WORK is sent
2127+ *
2128+ * A lot of this is taken from 'FrameRender'
2129+ *
2130+ * ret: 0 .. OK send the PVMWOR
2131+ * 1 .. Shellout gave SKIP_ONCE_RET -> this frame is done
2132+ */
2133+static int PvmStartFrame() {
2134+ int Frame_Result;
2135+
2136+ if(frame_stat[frame].status != PVM_FRAME_FREE) {
2137+ Warning(0.0, "Frame %d already started.\n", frame);
2138+ return 1;
2139+ }
2140+
2141+ if(opts.Options & VERBOSE)
2142+ Status_Info("\nStarting frame %d...", opts.FrameSeq.InitialFrame + frame);
2143+
2144+ frame_stat[frame].status = PVM_FRAME_WORKING;
2145+
2146+ /* allocate row pointers */
2147+ frame_stat[frame].row_ptr = (COLOUR **)POV_CALLOC(opts.Last_Line, sizeof(COLOUR *), "row_ptr");
2148+
2149+ opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame + frame;
2150+ setup_output_file_name();
2151+
2152+ /* Execute a shell-out command before tracing */
2153+ Frame_Result = POV_SHELLOUT(PRE_FRAME_SHL);
2154+
2155+ if (Frame_Result == ALL_SKIP_RET) {
2156+ /* stop completely */
2157+ int i;
2158+ for(i=frame; i < frames; i++) {
2159+ frame_stat[i].block_to_assign = grid_points;
2160+ frame_stat[i].block_to_reassign = grid_points;
2161+ frame_stat[i].status = PVM_FRAME_DONE_SHELLOUT;
2162+ }
2163+ /* continue searching, frames before this one, should be finished */
2164+ return 1;
2165+ }
2166+
2167+ if (Frame_Result == SKIP_ONCE_RET) {
2168+ /* mark frame as done */
2169+ frame_stat[frame].block_to_assign = grid_points;
2170+ frame_stat[frame].block_to_reassign = grid_points;
2171+ frame_stat[frame].status = PVM_FRAME_DONE_SHELLOUT;
2172+
2173+ /* continue searching */
2174+ return 1;
2175+ }
2176+
2177+ /*
2178+ * open output file
2179+ */
2180+ set_output_file_handle();
2181+ open_output_file();
2182+
2183+ Initialize_Renderer();
2184+
2185+ /*
2186+ * Start displaying
2187+ */
2188+ if( (opts.Options & DISPLAY) && !Display_Started) {
2189+ Status_Info("\nDisplaying frame %d...", opts.FrameSeq.InitialFrame + frame);
2190+ POV_DISPLAY_INIT(Frame.Screen_Width, Frame.Screen_Height);
2191+ Display_Started = TRUE;
2192+ frame_display = frame;
2193+ Status_Info("\n");
2194+ }
2195+
2196+
2197+ /*
2198+ * read already rendered parts
2199+ */
2200+ if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE)) {
2201+ int i;
2202+ int fl = opts.First_Line; /* remember start of image */
2203+
2204+ Read_Rendered_Part(Actual_Output_Name); /* read -> changes opts.First_line */
2205+
2206+ frame_stat[frame].row_to_write =
2207+ frame_stat[frame].row_to_malloc = opts.First_Line;
2208+
2209+ frame_stat[frame].block_to_write =
2210+ frame_stat[frame].block_to_assign = (opts.First_Line/PvmChunkHeight)*grid_ppline;
2211+ /* blocks above the new start are already finished */
2212+ for(i=0; i < frame_stat[frame].block_to_assign; i++) {
2213+ frame_stat[frame].block_stat[i].status = PVM_GRID_POINT_WRITTEN;
2214+ }
2215+ if(opts.Options & VERBOSE)
2216+ Status_Info("Continuing with block %d in frame %d\n",
2217+ frame_stat[frame].block_to_assign, frame);
2218+
2219+ opts.First_Line = fl; /* set back the old value */
2220+
2221+
2222+ /* this should not be necessary */
2223+ if (opts.Last_Line > Frame.Screen_Height)
2224+ opts.Last_Line = Frame.Screen_Height;
2225+
2226+ if (opts.Last_Column > Frame.Screen_Width)
2227+ opts.Last_Column = Frame.Screen_Width;
2228+ }
2229+
2230+ /*
2231+ * make a copy of the Output_File_Handle
2232+ */
2233+ frame_stat[frame].output_file = Output_File_Handle;
2234+ if(Output_File_Handle->filename) {
2235+ char * n = POV_MALLOC(strlen(Output_File_Handle->filename)+1, "filename");
2236+ strcpy(n, Output_File_Handle->filename);
2237+ frame_stat[frame].output_file->filename = n;
2238+ }
2239+
2240+ if(opts.Options & VERBOSE)
2241+ Status_Info("\n");
2242+
2243+ return 0;
2244+}
2245+
2246+
2247+/*
2248+ * test, if the next frame in the sequence finished,
2249+ * do all the necessary stuff to close the frame (shellout, ...)
2250+ */
2251+static void PvmFinishFrame() {
2252+
2253+ /* check, if frame has really finished */
2254+ if( frame_stat[frame].row_to_write < opts.Last_Line)
2255+ return;
2256+
2257+ /* if not already closed */
2258+ if( frame_stat[frame].status < PVM_FRAME_DONE) {
2259+
2260+ if(opts.Options & VERBOSE)
2261+ Status_Info("\nFinishing frame %d...", opts.FrameSeq.InitialFrame + frame);
2262+ Status_Info("rtw. %d\n", frame_stat[frame].row_to_write);
2263+
2264+ frame_stat[frame].status = PVM_FRAME_DONE;
2265+
2266+ POV_FREE(frame_stat[frame].row_ptr);
2267+
2268+ /* Close output file */
2269+ if (frame_stat[frame].output_file) {
2270+ Output_File_Handle = frame_stat[frame].output_file;
2271+ Close_File(frame_stat[frame].output_file);
2272+ }
2273+
2274+ if( frame == frame_display) {
2275+ POV_DISPLAY_FINISHED
2276+
2277+ if ((opts.Options & DISPLAY) && Display_Started) {
2278+ POV_DISPLAY_CLOSE
2279+
2280+ Display_Started = FALSE;
2281+ }
2282+
2283+ frame_display = -1;
2284+ }
2285+
2286+ if (opts.histogram_on)
2287+ write_histogram (opts.Histogram_File_Name);
2288+ }
2289+
2290+ if( frame_stat[frame].status < PVM_FRAME_DONE_SHELLOUT) {
2291+ /* the shellouts are done in the correct order */
2292+ if( frame == next_frame_finish) {
2293+ int Frame_Result;
2294+
2295+ frame_stat[frame].status = PVM_FRAME_DONE_SHELLOUT;
2296+
2297+ opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame + frame;
2298+ setup_output_file_name();
2299+
2300+ Frame_Result = POV_SHELLOUT(POST_FRAME_SHL);
2301+
2302+ if ((Frame_Result==SKIP_ONCE_RET) || (Frame_Result==ALL_SKIP_RET)) {
2303+ next_frame_finish = frames;
2304+ return;
2305+ }
2306+ next_frame_finish ++; /* one more frame finished */
2307+
2308+ frame ++; /* check next frame (might have finished earlier) */
2309+ if( frame < frames)
2310+ PvmFinishFrame();
2311+ }
2312+ }
2313+ if(opts.Options & VERBOSE)
2314+ Status_Info("\n");
2315+}
2316+
2317+
2318+/*
2319+ * Assign Work
2320+ *
2321+ * A slaved requested work, now find free block (or a block to reassign)
2322+ */
2323+static void PvmAssignWork() {
2324+ int min_assigned;
2325+ int found;
2326+ int f;
2327+
2328+ /* The slave wants work, but has already been reassigned something,
2329+ * then tell it to ask again when it really wants work.
2330+ */
2331+ if( slave_stat[slave_num].block_reassigned != PVM_SLAVE_FREE) {
2332+#ifdef DEBUG
2333+ Status_Info("%s already assigned on %d. Not reassigning.\n",
2334+ slave_name,
2335+ slave_stat[slave_num].block_reassigned);
2336+#endif /* DEBUG */
2337+ pvm_initsend(PvmDataDefault);
2338+ pvm_send(rtid, PVM_INIT_SLAVE);
2339+
2340+ return;
2341+ }
2342+
2343+
2344+ /*
2345+ * search for a free block, take a frame with minimal
2346+ * number of assigned blocks
2347+ */
2348+ found = 0;
2349+ min_assigned = grid_points;
2350+
2351+ frame = slave_stat[slave_num].frame_assigned;
2352+ /* if slave was already assigned and that frame has still free blocks */
2353+ if ( (frame >= 0) &&
2354+ (frame_stat[frame].block_to_assign < grid_points) ) {
2355+
2356+ min_assigned = 0;
2357+ found = 1;
2358+ }
2359+
2360+ /* find free frame with minimal number of assigned frames */
2361+ for(f = 0; (f < frames) && (min_assigned > 0); f ++) {
2362+ if( (frame_stat[f].block_to_assign < min_assigned) &&
2363+ (frame_stat[f].block_to_assign < grid_points) ) {
2364+
2365+#ifdef DEBUG
2366+ Status_Info("\nfound: frame %d, ass: %d, min: %d\n",
2367+ f, frame_stat[f].block_to_assign,
2368+ min_assigned);
2369+#endif
2370+
2371+ min_assigned = frame_stat[f].block_to_assign;
2372+ frame = f;
2373+ found = 1;
2374+
2375+ }
2376+ }
2377+
2378+ if( found ) {
2379+ /* first block for that frame */
2380+ if( frame_stat[frame].block_to_assign == 0) {
2381+ /* Do the necessary preparations for a new frame */
2382+ if( PvmStartFrame() ) {
2383+ /* Shellout gave SKIP_ONCE_REt -> search next block */
2384+ PvmAssignWork();
2385+ return;
2386+ }
2387+ }
2388+
2389+ slave_stat[slave_num].frame_assigned = frame;
2390+ PvmSendWork(frame_stat[frame].block_to_assign);
2391+ return;
2392+ }
2393+
2394+
2395+ /*
2396+ * found no free block
2397+ * search for a block to reassign
2398+ */
2399+
2400+ /* if this slave was slow, and there are enough other slaves left,
2401+ don't use this anymore */
2402+ if ( (slave_stat[slave_num].pixels_done < npixels_done*9/10/PvmTasks) &&
2403+ (minions >= (PvmTasks + 3) / 4) ) {
2404+
2405+ Status_Info("Not using %s for reassignment (%d%%)\n", slave_name,
2406+ 100*slave_stat[slave_num].pixels_done*PvmTasks/npixels_done);
2407+
2408+ /* tell slave to finish work */
2409+ pvm_initsend(PvmDataDefault);
2410+ pvm_send(rtid, PVM_STOP_SLAVE);
2411+ }
2412+
2413+ found = 0;
2414+
2415+ frame = slave_stat[slave_num].frame_assigned;
2416+ /* if slave was already assigned and that frame has free blocks */
2417+ if ( (frame >= 0) &&
2418+ (frame_stat[frame].block_to_reassign < grid_points) ) {
2419+
2420+ min_assigned = 0;
2421+ found = 1;
2422+ }
2423+
2424+ /* find first frame with minimal number of reassigned frames */
2425+ min_assigned = grid_points + 1;
2426+ for(f = 0; (f < frames) && (min_assigned > 0); f ++) {
2427+ if( frame_stat[f].block_to_reassign < min_assigned) {
2428+
2429+ min_assigned = frame_stat[frame].block_to_reassign;
2430+ frame = f;
2431+ found = 1;
2432+ }
2433+ }
2434+
2435+ if( found ) {
2436+ /* find block in frame */
2437+ int block;
2438+ for(block = 0; block < grid_points; block ++) {
2439+ if( frame_stat[frame].block_stat[block].status < PVM_GRID_POINT_DONE) {
2440+ slave_stat[slave_num].frame_reassigned = frame;
2441+ PvmReassignWork(block);
2442+ return;
2443+ }
2444+ }
2445+ }
2446+
2447+ /*
2448+ * there is nothing left to reassign
2449+ */
2450+ Status_Info("All blocks are assigned. Stopping %s.\n", slave_name);
2451+
2452+ /* tell slave to finish work */
2453+ pvm_initsend(PvmDataDefault);
2454+ pvm_send(rtid, PVM_STOP_SLAVE);
2455+
2456+}
2457+
2458+/*
2459+ * display a part from one line
2460+ */
2461+static void PvmDisplayPlot(row_ptr, row, col, ncols)
2462+ COLOUR * row_ptr;
2463+ int row, col, ncols;
2464+{
2465+ unsigned char Red, Green, Blue, Alpha;
2466+ DBL grey;
2467+ int i;
2468+
2469+ /* draw line */
2470+ for (i = col; i < col+ncols; i++) {
2471+ extract_colors(row_ptr[i], &Red, &Green, &Blue, &Alpha, &grey);
2472+ POV_DISPLAY_PLOT(i, row, Red, Green, Blue, Alpha);
2473+ }
2474+ /* force draw of the whole line (with X11) */
2475+ i = opts.Last_Column - 1;
2476+ extract_colors(row_ptr[i], &Red, &Green, &Blue, &Alpha, &grey);
2477+ POV_DISPLAY_PLOT(i, row, Red, Green, Blue, Alpha);
2478+}
2479+
2480+
2481+/*
2482+ * one of the slaves sends a part of it's computed data
2483+ */
2484+static void PvmReceiveData() {
2485+ int ncols;
2486+ int i;
2487+ int block;
2488+
2489+ pvm_upkint(&frame, 1, 1);
2490+ pvm_upkint(&block, 1, 1);
2491+ pvm_upkint(&row_start, 1, 1);
2492+ pvm_upkint(&col_start, 1, 1);
2493+ pvm_upkint(&ncols, 1, 1);
2494+
2495+ row_end = row_start + (bytesin - 3*sizeof(int))/(5*ncols*sizeof(COLC));
2496+ col_end = col_start + ncols;
2497+
2498+#ifdef DEBUG
2499+ Status_Info("receiving frame: %d, row: %d-%d, col: %d-%d\n",
2500+ frame, row_start, row_end, col_start, col_end);
2501+#endif
2502+
2503+ /* Make some checks to see if the data is not corrupted or invalid */
2504+ if( (row_start < opts.First_Line) || (col_start < opts.First_Column) ||
2505+ (row_end > opts.Last_Line) || (col_end > opts.Last_Column) ||
2506+ (frame < 0) || (frame >= frames) ||
2507+ (ncols > PvmChunkWidth) || (row_end - row_start > PvmChunkHeight) ) {
2508+
2509+ Warning(0.0, "Bad block recieved from %s\n",slave_name);
2510+ Warning(0.0, "Frame %d, Row %d - %d, Column %d - %d.\n", frame, row_start, row_end,
2511+ col_start, col_end);
2512+
2513+ return;
2514+ }
2515+
2516+ /* get one row after the other */
2517+ for (i = row_start; i < row_end; i++) {
2518+ if (i >= frame_stat[frame].block_stat[block].wr_line) { /* Is incoming data current? */
2519+
2520+ /* allocate memory, to receive data */
2521+ if (frame_stat[frame].row_ptr[i] == NULL) { /* Starting a new row */
2522+
2523+ frame_stat[frame].row_ptr[i] = (COLOUR *)POV_MALLOC(opts.Last_Column*sizeof(COLOUR),
2524+ "row_ptr");
2525+
2526+ while(frame_stat[frame].row_ptr[frame_stat[frame].row_to_malloc] != NULL &&
2527+ frame_stat[frame].row_to_malloc < opts.Last_Line) {
2528+ frame_stat[frame].row_to_malloc++;
2529+ }
2530+ }
2531+
2532+ /* get color data */
2533+ pvm_upkCOL(&(frame_stat[frame].row_ptr[i][col_start][0]),5*ncols,1);
2534+
2535+ frame_stat[frame].block_stat[block].wr_line = i + 1;
2536+
2537+ if (frame == frame_display) {
2538+ PvmDisplayPlot(frame_stat[frame].row_ptr[i], i, col_start, ncols);
2539+ }
2540+
2541+ /* Statistics - Attribute this grid section */
2542+ grid_lines_done++;
2543+ slave_stat[slave_num].pixels_done += ncols;
2544+
2545+ npixels_done += ncols;
2546+ } else {
2547+ /* another slave already sent this data */
2548+
2549+ COLOUR *dummy = (COLOUR *)POV_MALLOC(ncols * sizeof(COLOUR), "dummy row");
2550+ pvm_upkCOL(&(dummy[0][0]),5*ncols,1);
2551+
2552+ /* Statistics - Attribute this grid section */
2553+ slave_stat[slave_num].pixels_late += ncols;
2554+ POV_FREE(dummy);
2555+ }
2556+ }
2557+ /* Has this entire block been rendered? */
2558+ if (frame_stat[frame].block_stat[block].wr_line >=
2559+ (block/grid_ppline + 1)*PvmChunkHeight + opts.First_Line - 1 ||
2560+ frame_stat[frame].block_stat[block].wr_line >= opts.Last_Line) {
2561+#ifdef DEBUG
2562+ Status_Info("Block completed by %s\n", slave_name);
2563+#endif /* DEBUG */
2564+ frame_stat[frame].block_stat[block].status = PVM_GRID_POINT_DONE;
2565+ if (slave_stat[slave_num].block_reassigned == block) {
2566+#ifdef DEBUG
2567+ Status_Info(" reassigned block cleared.\n");
2568+#endif /* DEBUG */
2569+ slave_stat[slave_num].block_reassigned = PVM_SLAVE_FREE;
2570+ }
2571+#ifdef DEBUG
2572+ else
2573+ {
2574+ Status_Info(" reassigned block is %d.\n",
2575+ slave_stat[slave_num].block_reassigned);
2576+ }
2577+#endif /* DEBUG */
2578+ }
2579+
2580+ if ((opts.Options & VERBOSE) && (grid_lines_done % PvmChunkHeight) == 0) {
2581+ Status_Info("\r%5.2f of blocks complete.",
2582+ (float)100*grid_lines_done/PvmChunkHeight/grid_points/frames);
2583+ }
2584+}
2585+
2586+/*
2587+ * Write out us many lines as possible
2588+ */
2589+static void PvmWrite() {
2590+ int i;
2591+
2592+ do {
2593+ /* check, if there is a complete line to write */
2594+ for (i = frame_stat[frame].block_to_write;
2595+ i < frame_stat[frame].block_to_write + grid_ppline; i++) {
2596+ if (frame_stat[frame].block_stat[i].wr_line <= frame_stat[frame].row_to_write) {
2597+#ifdef DEBUG
2598+ Status_Info("needing block %d in frame %d\n", i, frame);
2599+#endif
2600+ return;
2601+ }
2602+ }
2603+
2604+ /* OK, we can write a whole line */
2605+ if (opts.Options & DISKWRITE) {
2606+#ifdef DEBUG
2607+ Status_Info("write: %d %d\n", frame, frame_stat[frame].row_to_write);
2608+#endif
2609+ Write_Line(frame_stat[frame].output_file,
2610+ frame_stat[frame].row_ptr[frame_stat[frame].row_to_write],
2611+ frame_stat[frame].row_to_write);
2612+ }
2613+
2614+ /* Still lines to allocate so */
2615+ if (frame_stat[frame].row_to_malloc < opts.Last_Line) {
2616+ /* move this row buffer down, so we avaoid one malloc/free */
2617+ frame_stat[frame].row_ptr[frame_stat[frame].row_to_malloc] =
2618+ frame_stat[frame].row_ptr[frame_stat[frame].row_to_write];
2619+ frame_stat[frame].row_ptr[frame_stat[frame].row_to_write] = NULL;
2620+ frame_stat[frame].row_to_malloc++;
2621+ } else { /* Otherwise free the row buffer */
2622+ POV_FREE(frame_stat[frame].row_ptr[frame_stat[frame].row_to_write]);
2623+ frame_stat[frame].row_ptr[frame_stat[frame].row_to_write]= NULL;
2624+ }
2625+
2626+ frame_stat[frame].row_to_write++;
2627+
2628+#ifndef DEBUG
2629+ if ((opts.Options & VERBOSE) && (frame_stat[frame].row_to_write % 8) == 0) {
2630+ Status_Info("\r%5.2f of blocks complete.",
2631+ (float)100*grid_lines_done/PvmChunkHeight/grid_points/frames);
2632+ Status_Info(" %4d of %4d lines finished (in frame %d).",
2633+ frame_stat[frame].row_to_write - opts.First_Line,
2634+ opts.Last_Line - opts.First_Line, frame);
2635+ }
2636+#endif /* not DEBUG */
2637+
2638+ /* Finished a whole row of blocks */
2639+ if ((frame_stat[frame].row_to_write - opts.First_Line) % PvmChunkHeight == 0) {
2640+ for (i = frame_stat[frame].block_to_write;
2641+ i < frame_stat[frame].block_to_write + grid_ppline; i++) {
2642+ frame_stat[frame].block_stat[i].status = PVM_GRID_POINT_WRITTEN;
2643+ }
2644+ frame_stat[frame].block_to_write += grid_ppline;
2645+ }
2646+
2647+ } while(frame_stat[frame].block_to_write < grid_points);
2648+}
2649+
2650+/*
2651+ * Handle slave requests, distribute and collect work
2652+ */
2653+void Pvm_Master_Control() {
2654+
2655+ /* Wait five minutes at a time between messages */
2656+ wait_time.tv_sec = 300;
2657+
2658+ next_frame_finish = 0; /* next frame that finishes */
2659+
2660+ /* There are incomplete frames and/or incoming messages, and there are any slaves left*/
2661+ while ( (next_frame_finish < frames) ||
2662+ ((pvm_probe(-1, -1) > 0) && (minions > 0))) {
2663+
2664+ /* check for user abort */
2665+ TEST_ABORT;
2666+ if (Stop_Flag) {
2667+ Render_Info("\nAborting render...\n");
2668+
2669+ PvmMasterEnd();
2670+
2671+ if ((opts.Options & DISPLAY) && Display_Started) {
2672+ POV_DISPLAY_CLOSE;
2673+ }
2674+ if (opts.Do_Stats) {
2675+ PRINT_STATS(stats);
2676+ }
2677+ Error("User abort.\n");
2678+
2679+ return;
2680+ }
2681+
2682+ /* receive a request from a slave */
2683+ if(PvmMasterReceive())
2684+ continue;
2685+
2686+ PvmIdentifySlave();
2687+
2688+#ifdef DEBUG
2689+ Status_Info("Received msg %d from %s\n", msgtag, slave_name);
2690+#endif
2691+
2692+ /* a slaves requests work */
2693+ switch(msgtag) {
2694+ case PVM_INIT_SLAVE: /* Another slave started ok */
2695+ if (opts.Options & VERBOSE) {
2696+ Status_Info(" Slave %d at %s successfully started.\n", minions, slave_name);
2697+ }
2698+ minions++;
2699+ break;
2700+
2701+ case PVM_NEED_WORK: /* a slave wants work */
2702+ PvmAssignWork();
2703+ break;
2704+
2705+ case PVM_SLAVE_RESULTS: /* slaves sends us some data */
2706+ PvmReceiveData();
2707+ PvmWrite();
2708+ PvmFinishFrame();
2709+ break;
2710+
2711+ case PVM_SLAVE_STATS: /* Too many stats, eh? */
2712+#ifdef DEBUG
2713+ Status_Info("Getting stats from %s.\n", slave_name);
2714+#endif /* DEBUG */
2715+ PvmUnpackStats();
2716+ nstat++;
2717+ break;
2718+
2719+ case PVM_SLAVE_EXIT: /* Slave has exited. */
2720+ Status_Info("\nSlave at %s has exited.\n",slave_name);
2721+
2722+ if (--minions <= 0) {
2723+ Error_Line( "Error - All slave tasks have exited!\n");
2724+ pvm_exit();
2725+ return;
2726+ }
2727+ break;
2728+
2729+ default: /* something strange happend */
2730+ Warning(0.0, "Bad block recieved from %s - message type %4X.\n",
2731+ slave_name, msgtag);
2732+ }
2733+ } /* incomplete frames */
2734+
2735+ /* Finished calculating everything */
2736+ PvmMasterEnd();
2737+}
2738+
2739+/*
2740+ * Stop PvmMaster
2741+ */
2742+static void PvmMasterEnd() {
2743+ int i;
2744+
2745+ /* tell all slave to stop work */
2746+ for(i=0; i < PvmTasks; i++) {
2747+ pvm_initsend(PvmDataDefault);
2748+ pvm_send(tids[i], PVM_STOP_SLAVE);
2749+ }
2750+
2751+ /* Wait a few seconds for lingering stats */
2752+ wait_time.tv_sec = 4;
2753+ wait_time.tv_usec = 0;
2754+
2755+ if (opts.Options & VERBOSE)
2756+ Status_Info("\nWaiting for remaining slave stats.\n");
2757+
2758+ /* some incoming stats */
2759+ while ((bufid = pvm_trecv(-1, PVM_SLAVE_STATS, &wait_time)) > 0) {
2760+#ifdef DEBUG
2761+ int msgtag;
2762+ if (pvm_bufinfo(bufid, &bytesin, &msgtag, &rtid) < 0) {
2763+ Error_Line( "PVM Master cannot bufinfo.\n");
2764+ pvm_perror("");
2765+ pvm_exit();
2766+ return;
2767+ }
2768+
2769+ PvmIdentifySlave();
2770+
2771+ Status_Info("Getting stats from %s.\n", slave_name);
2772+#endif /* DEBUG */
2773+
2774+ PvmUnpackStats();
2775+ nstat++;
2776+ }
2777+
2778+ /* Dump stats for the tasks */
2779+ Statistics( "\n\nPVM Task Distribution Statistics:\n");
2780+ Statistics( "%20s [ done ] [ late ]","host name");
2781+ Statistics( "%20s [ done ] [ late ]\n","host name");
2782+
2783+ for (i = 0; i < PvmTasks; i++) {
2784+ int dtid;
2785+ int j;
2786+
2787+ dtid = pvm_tidtohost(tids[i]);
2788+
2789+ for (j = 0; j < PvmTasks; j++) {
2790+ if (dtid == hostinfo[j].hi_tid)
2791+ break;
2792+ }
2793+
2794+ Statistics("%20s [%5.2f%%] [%5.2f%%]", hostinfo[j].hi_name,
2795+ (DBL)slave_stat[i].pixels_done * 100 / npixels_done / frames,
2796+ (DBL)slave_stat[i].pixels_late * 100 / npixels_done / frames);
2797+
2798+ if (i % 2 == 1)
2799+ Statistics("\n");
2800+ }
2801+
2802+ pvm_exit();
2803+
2804+ Statistics("\n\nPOV-Ray statistics for finished frames:");
2805+ if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME) {
2806+ for(i=0; i < next_frame_finish; i++) {
2807+ Statistics("\nFrame %d:\n", opts.FrameSeq.InitialFrame + i);
2808+ PRINT_STATS(frame_stat[i].stats);
2809+ }
2810+ if (opts.Do_Stats) {
2811+ Statistics("\n\nTotal statistics:");
2812+ }
2813+ }
2814+
2815+}
2816+
2817+/*
2818+ * A slave sent some stats
2819+ */
2820+static void PvmUnpackStats() {
2821+ COUNTER tmpStat[MaxStat];
2822+
2823+ pvm_upkint(&frame, 1, 1);
2824+
2825+ if( pvm_upkSTAT((long*)tmpStat, MaxStat*sizeof(COUNTER)/sizeof(long), 1) >= 0) {
2826+ int i;
2827+ COUNTER tmp;
2828+
2829+ for(i=0; i < MaxStat; i++) {
2830+ /* stats per frame */
2831+ Add_Counter(tmp,tmpStat[i],frame_stat[frame].stats[i]);
2832+ frame_stat[frame].stats[i] = tmp;
2833+
2834+ /* total stats */
2835+ Add_Counter(tmp,tmpStat[i],totalstats[i]);
2836+ totalstats[i] = tmp;
2837+
2838+ if(opts.FrameSeq.FrameType != FT_MULTIPLE_FRAME) {
2839+ Add_Counter(tmp,tmpStat[i],stats[i]);
2840+ stats[i] = tmp;
2841+ }
2842+ }
2843+ } else {
2844+ Error_Line("Unpack Stats.\n");
2845+ pvm_perror("");
2846+ }
2847+}
2848+
2849+
2850+
2851+/********************************************************************************
2852+ * Slave Intialization
2853+ ********************************************************************************/
2854+
2855+int Pvm_Slave_Init() {
2856+ /* Get master TID */
2857+ PvmMTid = pvm_parent();
2858+
2859+ /* Have PVM notify us if the host POV process is killed
2860+ * or the local PVM daemon dies */
2861+ pvm_notify(PvmTaskExit, PVM_KILL_SLAVE, 1, &PvmMTid);
2862+ pvm_setopt(PvmAutoErr, 2);
2863+
2864+ /* Set direct routing */
2865+ pvm_setopt(PvmRoute, PvmRouteDirect);
2866+
2867+ /* Tell the master we started successfully */
2868+ pvm_initsend(PvmDataDefault);
2869+ pvm_send(PvmMTid, PVM_INIT_SLAVE);
2870+
2871+ /* Send an initial work request to the master, so that there is always
2872+ * an outstanding block assignment, and we don't have to wait for the
2873+ * master to respond to our request.
2874+ */
2875+ pvm_initsend(PvmDataDefault);
2876+ pvm_send(PvmMTid, PVM_NEED_WORK);
2877+
2878+ NICE(PvmNice);
2879+
2880+ return 0;
2881+}
2882+
2883+
2884+/********************************************************************************
2885+ * Slave Control
2886+ ********************************************************************************/
2887+
2888+static void PvmSendStats() {
2889+ pvm_initsend(PvmDataDefault);
2890+ pvm_pkint( &frame, 1, 1);
2891+ pvm_pkSTAT( (long*)stats, MaxStat*sizeof(COUNTER)/sizeof(long), 1);
2892+ pvm_send(PvmMTid, PVM_SLAVE_STATS);
2893+}
2894+
2895+/*
2896+ * Request a new block from the master,
2897+ * handle all messages sent by the master
2898+ * ret: 0 .. continue with new frame (or exit)
2899+ * 1 .. continue with this frame (but new region)
2900+ */
2901+int Pvm_Slave_Control() {
2902+
2903+ struct timeval wait_time;
2904+ int bufid;
2905+ unsigned int msgtag;
2906+ int f;
2907+ static int first = 1;
2908+
2909+ /* Wait up to 5 minutes for a message, otherwise exit */
2910+ wait_time.tv_sec = 300;
2911+ wait_time.tv_usec = 0;
2912+
2913+ if((bufid = pvm_trecv(PvmMTid, -1, &wait_time)) == 0) {
2914+ Error_Line( "Slave timed out waiting for master\n");
2915+ pvm_exit();
2916+ exit(1);
2917+ } else if (bufid < 0) {
2918+ Error_Line( "Cannot receive message from master.");
2919+ pvm_perror("");
2920+ pvm_exit();
2921+ exit(1);
2922+ }
2923+
2924+ /* We have a block assignment from the master - IGOR SERVES! */
2925+ if(pvm_bufinfo(bufid, (int *)0, &msgtag, &PvmMTid) < 0) {
2926+ Error_Line("Cannot get PVM bufinfo\n");
2927+ pvm_perror("");
2928+ pvm_exit();
2929+ exit(1);
2930+ }
2931+
2932+ switch( msgtag) {
2933+ case PVM_INIT_SLAVE:
2934+ pvm_initsend(PvmDataDefault);
2935+ pvm_send(PvmMTid, PVM_NEED_WORK);
2936+ break;
2937+
2938+ case PVM_WORK:
2939+ /* Ask master for some more block assignments in advance
2940+ * to avoid waiting for them to be sent later
2941+ */
2942+ pvm_initsend(PvmDataDefault);
2943+ pvm_send(PvmMTid, PVM_NEED_WORK);
2944+
2945+ /* Unpack the message */
2946+ pvm_upkint(&f, 1, 1);
2947+ pvm_upkint(&PvmBlockNum, 1, 1);
2948+ pvm_upkint(&opts.First_Line, 1, 1);
2949+ pvm_upkint(&opts.Last_Line, 1, 1);
2950+ pvm_upkint(&opts.First_Column, 1, 1);
2951+ pvm_upkint(&opts.Last_Column, 1, 1);
2952+
2953+ /* Last_Line is really "number of lines to do" */
2954+ opts.Last_Line++;
2955+
2956+ /* Send the data every 1/4 of a block */
2957+ PvmRowsToSend = (opts.Last_Line - opts.First_Line + 3) / 4;
2958+
2959+ /* Last_Column is really "number of columns to do" */
2960+ opts.Last_Column++;
2961+
2962+ /* check, if a new frame starts */
2963+ if(frame != f) {
2964+ if(!first)
2965+ PvmSendStats();
2966+ first = 0;
2967+ PvmNextFrame = opts.FrameSeq.InitialFrame + f;
2968+ frame = f;
2969+ return 0; /* stop with this frame */
2970+ }
2971+
2972+ /* We need to do this for every block */
2973+ Initialize_Renderer();
2974+
2975+ return 1; /* still the same frame */
2976+
2977+ case PVM_STOP_SLAVE: /* Everything is done, send stats and exit */
2978+ PvmSendStats();
2979+ PvmNextFrame = opts.FrameSeq.FinalFrame + 1;
2980+ return 0;
2981+
2982+ case PVM_KILL_SLAVE:
2983+ Error_Line("\nSlave killed because of dead master.\n");
2984+ pvm_exit();
2985+ exit(1);
2986+
2987+ default: /* Unknown message */
2988+ Error_Line("\nUnknown control message from master - %X\n",msgtag);
2989+ pvm_initsend(PvmDataDefault);
2990+ pvm_send(PvmMTid,PVM_NEED_WORK); /* Request work again */
2991+ }
2992+ return 0;
2993+}
2994+
2995+void Pvm_Slave_Exit() {
2996+ pvm_initsend(PvmDataDefault);
2997+ pvm_send(PvmMTid, PVM_SLAVE_EXIT);
2998+ pvm_exit();
2999+}
3000+
3001+void Pvm_Write_Line(handle, line_data, line_number)
3002+ FILE_HANDLE *handle;
3003+ COLOUR *line_data;
3004+ int line_number;
3005+{
3006+ static int in_buffer = 0;
3007+ static int ncols;
3008+
3009+ if (in_buffer == 0) /* No lines written yet. Initialize buffer */
3010+ {
3011+ ncols = opts.Last_Column - opts.First_Column;
3012+ pvm_initsend(PvmDataDefault);
3013+
3014+ /* Insert block info into message */
3015+ pvm_pkint(&frame, 1, 1);
3016+ pvm_pkint(&PvmBlockNum, 1, 1);
3017+ pvm_pkint(&line_number, 1, 1);
3018+ pvm_pkint(&opts.First_Column, 1, 1);
3019+ pvm_pkint(&ncols, 1, 1);
3020+ }
3021+
3022+ if (pvm_pkCOL(&(line_data[opts.First_Column][0]),5*ncols, 1) < 0) {
3023+ Error_Line( "Cannot pack in Pvm_Write_Line\n");
3024+ pvm_perror("");
3025+ if (in_buffer > 0) {
3026+ pvm_send(PvmMTid, PvmBlockNum); /* Send any lines we have done. */
3027+ }
3028+ pvm_initsend(PvmDataDefault);
3029+ pvm_send(PvmMTid, PVM_SLAVE_EXIT); /* Tell the master we're dying */
3030+ pvm_exit();
3031+ return;
3032+ }
3033+
3034+ in_buffer++;
3035+
3036+ if (in_buffer >= PvmRowsToSend || line_number >= opts.Last_Line - 1) {
3037+ if (pvm_send(PvmMTid, PVM_SLAVE_RESULTS) < 0) {
3038+ Error_Line( "Cannot send block in Pvm_Write_Line\n");
3039+ pvm_perror("");
3040+ pvm_exit();
3041+ return;
3042+ }
3043+
3044+ in_buffer = 0;
3045+ }
3046+}
3047+
3048+
3049+
3050+
3051+
3052+
3053+
3054+
3055+
3056+
3057+
3058+
3059+
3060+
3061+
3062+
3063+
3064+
3065+
3066diff -Naur source.ori/pvm.h source/pvm.h
3067--- source.ori/pvm.h Thu Jan 1 01:00:00 1970
3068+++ source/pvm.h Sun Sep 12 00:25:35 1999
3069@@ -0,0 +1,164 @@
3070+/****************************************************************************
3071+* pvm.h
3072+*
3073+* This include module is used by PVM control routines in the PVM'd PovRAY.
3074+*
3075+* This file was written by Brad Kline. April 1994.
3076+* modified by Andreas Dilger, Feb 1995.
3077+* modified by Harald Deischinger, 1996 - April 1997
3078+* modified by Jakob Flierl, May 1999
3079+*
3080+* All the defines that need modification are at the top.
3081+*
3082+* The author disclaims all warranties with regard to this software,
3083+* including all implied warranties of merchant-ability and fitness.
3084+* The code is simply distributed as it is.
3085+*
3086+*
3087+*****************************************************************************/
3088+
3089+/* If setpriority() doesn't exist on your system, you should change
3090+ * "your_pvm_arch" on the following line to whatever your actual PVM_ARCH
3091+ * is (ie ALPHA or SCO), and please email me to tell me about it, so I can
3092+ * add it in permanently.
3093+ */
3094+
3095+#include <features.h>
3096+
3097+#if defined(SUN4SOL2) || defined(your_pvm_arch)
3098+
3099+#define NICE(x) nice(x)
3100+extern int nice PARAMS((int prio));
3101+
3102+#else
3103+
3104+/* This should work for the majority of systems */
3105+
3106+#define NICE(x) setpriority(PRIO_PROCESS,0,getpriority(PRIO_PROCESS,0)+(x))
3107+
3108+#if !(defined __GLIBC__ && __GLIBC__ >= 2)
3109+extern int setpriority PARAMS((int which, int who, int prio));
3110+extern int getpriority PARAMS((int which, int who));
3111+#endif
3112+#endif
3113+
3114+/* How nice to be by default. 0 is the regular job priority, while is 20 very
3115+ * nice. The nice value can be changed on the command line, so there is
3116+ * probably little reason to change it here.
3117+ */
3118+#define PVM_DEFAULT_NICE 5
3119+
3120+/* On BSD systems, use getwd instead of getcwd. Change "your_pvm_arch" on
3121+ * the following line to whatever your actual PVM_ARCH is (ie MIPS or CRAY),
3122+ * and please email me to tell me about it, so I can add it in permanently.
3123+ */
3124+#if defined(NEXT) || defined(your_pvm_arch)
3125+
3126+#define GETCWD(path) getwd(path)
3127+extern char *getwd PARAMS((char *));
3128+
3129+#else
3130+
3131+#define GETCWD(path) getcwd(path,PATH_MAX+1)
3132+extern char *getcwd PARAMS((char *, size_t ));
3133+
3134+#endif
3135+
3136+extern int chdir PARAMS((const char *path));
3137+
3138+/* Grid decomposition defaults */
3139+#define PVM_DEFAULT_GRID_HEIGHT 32
3140+#define PVM_DEFAULT_GRID_WIDTH 32
3141+
3142+/* what type of encoding to use whan sending pixels */
3143+#define pvm_upkCOL pvm_upkfloat
3144+#define pvm_pkCOL pvm_pkfloat
3145+#define pvm_upkSTAT pvm_upklong
3146+#define pvm_pkSTAT pvm_pklong
3147+
3148+
3149+/* The maximum path length. _POSIX_PATH_MAX_ = 255 in my limits.h file, but
3150+ * not all systems have this defined, and my base SUN4 install didn't have
3151+ * PATH_MAX in <limits.h>.*/
3152+#ifndef PATH_MAX
3153+#ifdef _POSIX_PATH_MAX
3154+#define PATH_MAX _POSIX_PATH_MAX
3155+#else /* _POSIX_PATH_MAX doesn't exist. A safe guess. */
3156+#define PATH_MAX 1024
3157+#endif /* _POSIX_PATH_MAX */
3158+#endif /* PATH_MAX */
3159+
3160+/* Structure to hold info about each slave process */
3161+typedef struct {
3162+ char *name;
3163+ int pixels_done; /* Number of pixels completed */
3164+ int pixels_late; /* Number of pixels finished after another slave did it */
3165+ int block_reassigned; /* Block number reassigned to this slave */
3166+ int frame_assigned; /* assigned to that frame */
3167+ int frame_reassigned; /* reassigned to that frame */
3168+} pvm_slave_stat;
3169+#define PVM_SLAVE_FREE -1
3170+
3171+/* Structure to hold info about each grid section */
3172+typedef struct {
3173+ int status; /* Current status of block */
3174+ int wr_line; /* Line to be written next */
3175+ int assigned_tid; /* Tid of the machine assigned to this block */
3176+ int reassigned_tid; /* Tid of the machine reassigned to this block */
3177+} pvm_block_stat;
3178+/* Status indicators */
3179+#define PVM_GRID_POINT_FREE 0
3180+#define PVM_GRID_POINT_ASSIGNED 1
3181+#define PVM_GRID_POINT_REASSIGNED 2
3182+#define PVM_GRID_POINT_DONE 3
3183+#define PVM_GRID_POINT_WRITTEN 4
3184+
3185+
3186+/* Structure to hold info about each frame */
3187+typedef struct {
3188+ int status;
3189+ COLOUR ** row_ptr;
3190+ int row_to_write;
3191+ int row_to_malloc;
3192+ int block_to_assign;
3193+ int block_to_reassign;
3194+ int block_to_write;
3195+ COUNTER stats[MaxStat]; /* PovRay Status */
3196+ pvm_block_stat * block_stat;
3197+ FILE_HANDLE* output_file;
3198+} pvm_frame_stat;
3199+#define PVM_FRAME_FREE 0
3200+#define PVM_FRAME_WORKING 1
3201+#define PVM_FRAME_DONE 2
3202+#define PVM_FRAME_DONE_SHELLOUT 3
3203+
3204+/* Define some message IDs to be used */
3205+#define PVM_INIT_SLAVE 1
3206+#define PVM_STOP_SLAVE 2
3207+#define PVM_KILL_SLAVE 3
3208+#define PVM_NEED_WORK 4
3209+#define PVM_SLAVE_EXIT 5
3210+#define PVM_SLAVE_STATS 6
3211+#define PVM_SLAVE_RESULTS 7
3212+#define PVM_WORK 8
3213+
3214+/* Prototypes for public functions defined in pvm.c */
3215+void Pvm_Master_Init PARAMS((int argc, char **argv));
3216+void Pvm_Master_Control PARAMS((void));
3217+void Pvm_Write_Line PARAMS((FILE_HANDLE *handle, COLOUR *line, int row));
3218+int Pvm_Slave_Init PARAMS((void));
3219+int Pvm_Slave_Control PARAMS((void));
3220+void Pvm_Slave_Exit PARAMS((void));
3221+
3222+extern char PvmArch[];
3223+extern int PvmChunkWidth;
3224+extern int PvmChunkHeight;
3225+extern int PvmSlave;
3226+extern int PvmTasks;
3227+extern int PvmNice;
3228+extern char * PvmSlavename;
3229+extern int PvmNextFrame;
3230+extern int PvmBlockNum;
3231+extern char PvmWorkingDir[];
3232+extern char ** PvmHosts;
3233+extern int PvmHostsN;
3234diff -Naur source.ori/render.c source/render.c
3235--- source.ori/render.c Sat Jun 30 01:49:21 2001
3236+++ source/render.c Sat Jun 30 10:08:01 2001
3237@@ -46,7 +46,9 @@
3238 #include "texture.h"
3239 #include "vbuffer.h"
3240 #include "userio.h"
3241-
3242+#ifdef USE_PVM
3243+#include "pvm.h"
3244+#endif
3245
3246 /*****************************************************************************
3247 * Local preprocessor defines
3248@@ -65,6 +67,10 @@
3249
3250 #define SUB_PIXEL_GRID_SIZE 16
3251
3252+#ifdef USE_PVM
3253+DBL maxclr;
3254+#endif
3255+
3256 /*****************************************************************************
3257 * Local typedefs
3258 ******************************************************************************/
3259@@ -104,7 +110,9 @@
3260
3261 static int SuperSampleCount, RadiosityCount;
3262
3263+#ifndef USE_PVM
3264 static DBL maxclr;
3265+#endif
3266
3267 /* Jitter values are taken from [-0.5*JitterScale, 0.5*JitterScale]. */
3268
3269@@ -314,7 +322,9 @@
3270 static int create_ray (RAY *ray, DBL x, DBL y, int ray_number);
3271 static void supersample (COLOUR result, int x, int y);
3272 static void gamma_correct (COLOUR Colour);
3273+#ifndef USE_PVM
3274 static void extract_colors (COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey);
3275+#endif
3276 static void trace_pixel (int x, int y, COLOUR Colour);
3277 static void initialise_histogram (void) ;
3278 static void accumulate_histogram (int x, int y, int on);
3279@@ -349,7 +359,8 @@
3280 *
3281 * CHANGES
3282 *
3283-* -
3284+* Oct 1996: Added support for PVM [Deischi]
3285+* Jun 2001: Added conditional build for PVM Support [Agaran]
3286 *
3287 ******************************************************************************/
3288
3289@@ -368,6 +379,12 @@
3290
3291 size = (Frame.Screen_Width + 1) * sizeof(COLOUR);
3292
3293+#ifdef USE_PVM
3294+ /* looks like normal mem leak, maybe that should be always enabled? */
3295+ if (Previous_Line!=NULL) POV_FREE(Previous_Line);
3296+ if (Current_Line!=NULL) POV_FREE(Current_Line);
3297+#endif
3298+
3299 Previous_Line = (COLOUR *)POV_MALLOC(size, "previous line buffer");
3300 Current_Line = (COLOUR *)POV_MALLOC(size, "current line buffer");
3301
3302@@ -381,6 +398,12 @@
3303 {
3304 size = (Frame.Screen_Width + 1) * sizeof(char);
3305
3306+#ifdef USE_PVM
3307+ /* again looks like memleak fixup... */
3308+ if (Previous_Line_Antialiased_Flags!=NULL) POV_FREE(Previous_Line_Antialiased_Flags);
3309+ if (Current_Line_Antialiased_Flags!=NULL) POV_FREE(Current_Line_Antialiased_Flags);
3310+#endif
3311+
3312 Previous_Line_Antialiased_Flags = (char *)POV_MALLOC(size, "previous line flags");
3313 Current_Line_Antialiased_Flags = (char *)POV_MALLOC(size, "current line flags");
3314
3315@@ -390,6 +413,11 @@
3316 Current_Line_Antialiased_Flags[i] = 0;
3317 }
3318 }
3319+#ifdef USE_PVM
3320+ /* If PVM, this is already enough */
3321+ if(PvmTasks && !PvmSlave)
3322+ return;
3323+#endif
3324
3325 Assign_Vector(Camera_Ray.Initial, Frame.Camera->Location);
3326
3327@@ -3154,8 +3182,11 @@
3328 * Jun 1995 : Alpha channel support -CEY
3329 *
3330 ******************************************************************************/
3331-
3332+#ifdef USE_PVM
3333+void extract_colors(COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey)
3334+#else
3335 static void extract_colors(COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey)
3336+#endif
3337 {
3338 if (opts.PaletteOption == GREY)
3339 {
3340diff -Naur source.ori/render.h source/render.h
3341--- source.ori/render.h Sat Jun 30 01:49:21 2001
3342+++ source/render.h Sat Jun 30 03:18:56 2001
3343@@ -59,6 +59,9 @@
3344 extern unsigned long *histogram_grid ;
3345 extern unsigned long max_histogram_value ;
3346 extern FILE_HANDLE *Histogram_File_Handle ;
3347+#ifdef USE_PVM
3348+extern DBL maxclr;
3349+#endif
3350
3351 /*****************************************************************************
3352 * Global functions
3353@@ -74,6 +77,10 @@
3354 DBL Trace (RAY *Ray, COLOUR Colour, DBL Weight);
3355 void Check_User_Abort (int Do_Stats);
3356 void write_histogram (char *filename);
3357+#ifdef USE_PVM
3358+void extract_colors (COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey);
3359+#endif
3360+
3361 void destroy_histogram (void);
3362
3363 #endif
3364diff -Naur source.ori/unix/makefile source/unix/makefile
3365--- source.ori/unix/makefile Sat Jun 30 03:02:03 2001
3366+++ source/unix/makefile Sat Jun 30 11:54:57 2001
3367@@ -53,7 +53,7 @@
3368 #CFLAGS = -O6 -finline-functions -ffast-math -c -ansi -m386 -DCPU=586 -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC) $(LIBPNGINC) $(ZLIBINC)
3369
3370 # Linux compiler flags, Pentium II optimized
3371-CFLAGS = $(OPT_FLAGS) -finline-functions -ffast-math -c -ansi -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC)
3372+CFLAGS = $(OPT_FLAGS) $(PVMFLAGS) -finline-functions -ffast-math -c -ansi -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC)
3373
3374 # HPUX compiler flags
3375 #CFLAGS = +O2 -finline-functions -c -Aa -D_HPUX_SOURCE -DCOMPILER_VER=\".`uname`.$(CC)\" $(SRCINC) $(LIBPNGINC) $(ZLIBINC)
3376@@ -149,12 +149,15 @@
3377
3378 # UTARGET is the name of the text-only UNIX version
3379 UTARGET=povray
3380+UTARGET_PVM=pvmpov
3381
3382 # XTARGET is the name of the X-Windows executable.
3383 XTARGET=x-povray
3384+XTARGET_PVM=x-pvmpov
3385
3386 # STARGET is the name of the SVGA executable.
3387 STARGET=s-povray
3388+STARGET_PVM=s-pvmpov
3389
3390 # This is the suffix for object files.
3391 OBJ = .o
3392@@ -167,6 +170,13 @@
3393
3394 SRCINC = -I. -I$(SRCDIR)
3395
3396+# not needed
3397+#PVMINC = -I$(PVM_ROOT)/include
3398+#PVMLIB = /usr/lib/libpvm3.a /usr/lib/libgpvm3.a
3399+PVMLIB = -lpvm3
3400+# dunno for what that is used
3401+XDIR = $(HOME)/pvm3/bin/$(PVM_ARCH)
3402+
3403 #
3404 # End of user specific options
3405 #
3406@@ -1526,6 +1536,12 @@
3407 xpovmask.xbm \
3408 $(SRCDIR)/povproto.h
3409
3410+pvmDEP = $(SRCDIR)/pvm.c \
3411+ config.h \
3412+ $(SRCDIR)/pvm.h
3413+# $(UNIXDIR)/unixconf.h
3414+
3415+
3416 config.h:
3417 @echo
3418 @echo 'You need to select which executable version you want'
3419@@ -1549,46 +1565,89 @@
3420 unix: $(UTARGET)
3421 @echo
3422
3423+unix_pvm: $(UTARGET_PVM)
3424+ @echo
3425+
3426 $(UTARGET): $(POVOBJS) $(ODIR)/unix$(OBJ)
3427 $(CC) $(POVOBJS) $(ODIR)/unix$(OBJ) $(LFLAGS) -o $(UTARGET)
3428
3429+$(UTARGET_PVM): $(POVOBJS) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3430+ $(CC) $(POVOBJS) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) -o $(UTARGET_PVM)
3431+
3432 svga: $(STARGET)
3433 @echo
3434
3435+svga_pvm: $(STARGET_PVM)
3436+ @echo
3437+
3438+
3439 $(STARGET): $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ)
3440 $(CC) $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ) $(LFLAGS) $(SLIBLIB) -o $(STARGET)
3441
3442+$(STARGET_PVM): $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3443+ $(CC) $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) $(SLIBLIB) -o $(STARGET_PVM)
3444+
3445 xwin: $(XTARGET)
3446 @echo
3447
3448+xwin_pvm: $(XTARGET_PVM)
3449+ @echo
3450+
3451 $(XTARGET): $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ)
3452 $(CC) $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ) $(LFLAGS) $(XLIBLIB) -o $(XTARGET)
3453
3454+$(XTARGET_PVM): $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3455+ $(CC) $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) $(XLIBLIB) -o $(XTARGET_PVM)
3456+
3457+
3458 # Only these files need to be rebuilt if the display type was changed
3459 DISPOBJS = $(ODIR)/povray$(OBJ) $(ODIR)/render$(OBJ) \
3460 $(ODIR)/userio$(OBJ) $(ODIR)/vbuffer$(OBJ)
3461
3462+PVMOBJ = $(ODIR)/optin$(OBJ) $(ODIR)/optout$(OBJ) $(ODIR)/povray$(OBJ) $(ODIR)render$(OBJ)
3463+
3464 newunix:
3465- -@$(RM) $(DISPOBJS)
3466+ -@$(RM) $(DISPOBJS) $(PVMOBJ)
3467 -@cp unixconf.h config.h
3468 -@touch -c $(ODIR)/*$(OBJ)
3469 -@$(MAKE) unix
3470
3471+newunix_pvm:
3472+ -@$(RM) $(DISPOBJS) $(PVMOBJ)
3473+ -@cp unixconf.h config.h
3474+ -@touch -c $(ODIR)/*$(OBJ)
3475+ -@$(MAKE) PVMFLAGS="-DUSE_PVM" unix_pvm
3476+
3477+
3478 newsvga:
3479- -@$(RM) $(DISPOBJS)
3480+ -@$(RM) $(DISPOBJS) $(PVMOBJ)
3481 -@cp svgaconf.h config.h
3482 -@touch -c $(ODIR)/*$(OBJ)
3483 -@$(MAKE) svga
3484
3485+newsvga_pvm:
3486+ -@$(RM) $(DISPOBJS) $(PVMOBJ)
3487+ -@cp svgaconf.h config.h
3488+ -@touch -c $(ODIR)/*$(OBJ)
3489+ -@$(MAKE) PVMFLAGS="-DUSE_PVM" svga_pvm
3490+
3491 newxwin:
3492- -@$(RM) $(DISPOBJS)
3493+ -@$(RM) $(DISPOBJS) $(PVMOBJ)
3494 -@cp xwinconf.h config.h
3495 -@touch -c $(ODIR)/*$(OBJ)
3496 -@$(MAKE) xwin
3497
3498+newxwin_pvm:
3499+ -@$(RM) $(DISPOBJS) $(PVMOBJ)
3500+ -@cp xwinconf.h config.h
3501+ -@touch -c $(ODIR)/*$(OBJ)
3502+ -@$(MAKE) PVMFLAGS="-DUSE_PVM" xwin_pvm
3503+
3504+
3505 clean:
3506- -@$(RM) $(POVOBJS) $(ODIR)/unix$(OBJ) $(ODIR)/xwindows$(OBJ)
3507- -@$(RM) $(ODIR)/svga$(OBJ) $(UTARGET) $(XTARGET) $(STARGET)
3508+ -@$(RM) $(POVOBJS) pvm$(OBJ) $(ODIR)/unix$(OBJ) $(ODIR)/xwindows$(OBJ)
3509+ -@$(RM) $(ODIR)/svga$(OBJ) $(UTARGET) $(XTARGET) $(STARGET) $(UTARGET_PVM)
3510+ -@$(RM) $(XTARGET_PVM) $(STARGET_PVM)
3511
3512 install:
3513 -@cp povray.1 $(POVPATH)/man/man1
3514@@ -1821,17 +1880,7 @@
3515 $(ODIR)/xwindows$(OBJ) : $(xwindowsDEP)
3516 $(CC) $(CFLAGS) $(XLIBINC) xwindows.c
3517
3518-
3519-
3520-
3521-
3522-
3523-
3524-
3525-
3526-
3527-
3528-
3529-
3530+$(ODIR)/pvm$(OBJ) : $(pvmDEP)
3531+ $(CC) $(CFLAGS) $(SRCDIR)/pvm.c
3532
3533
This page took 0.636378 seconds and 4 git commands to generate.