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