1 diff -Naur source.ori/optin.c source/optin.c
2 --- source.ori/optin.c Sat Jun 30 01:49:21 2001
3 +++ source/optin.c Sat Jun 30 10:01:28 2001
6 * Written by CEY 4/94 based on existing code and INI code from CDW.
9 +* Modified Oct. 96 by Deischi for PVM
10 +* Modified Jun 2001 by Agaran for conditional PVM build
12 * Modification by Thomas Willhalm, March 1999, used with permission.
24 /*****************************************************************************
27 { BITS_PER_COLOR_OP, "Bits_Per_Color" },
28 { BITS_PER_COLOUR_OP, "Bits_Per_Colour" },
30 + { INCLUDE_INI_OP, "Include_Ini" },
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" }
44 { INCLUDE_INI_OP, "Include_Ini" }
48 static char temp_string[3]="\0\0";
54 +* Oct. 1996: Added options for PVMPOV [Deischi]
55 +* jun 2001: conditional pvm
57 ******************************************************************************/
68 + sprintf(value, "%d", PvmTasks);
71 + sprintf(value, "%d", PvmChunkWidth);
74 + sprintf(value, "%d", PvmChunkHeight);
77 + strncpy(value, PvmSlavename ? PvmSlavename : "", 128);
80 + sprintf(value, "%s", PvmArch);
83 + sprintf(value, "%d", PvmNice);
86 + strncpy(value, PvmWorkingDir, PATH_MAX);
91 + for(i=0; i < PvmHostsN; i++) {
92 + strncat(value, PvmHosts[i], 128);
93 + strncat(value, ",", 128);
98 + sprintf(value, "%s", (PvmTasks || PvmSlave) ? "On" : "Off");
103 Error("Unknown INI option in Write_INI.");
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
111 ******************************************************************************/
113 @@ -1024,13 +1084,67 @@
116 /* "N" option flag is used by networking (multi-processor) options.
129 + case 'N': /* switches used for PVMPOV */
131 + switch( Option_String[1]) {
132 + case '\0': /* Start one slave/available PVM host */
133 + process_variable(PVM_USE_OP, Add_Option ? "On" : "Off");
135 + case 'a': /* Select a particular architecture to run the slaves on */
137 + process_variable(PVM_ARCH_OP, Option_String+2);
139 + case 'n': /* Sets the niceness (priority) level */
141 + process_variable(PVM_NICE_OP, Option_String+2);
143 + case 't': /* Sets the number of tasks to run. Default is 1 per host */
145 + process_variable(PVM_TASKS_OP, Option_String+2);
147 + case 'h': /* The height of a single grid block, in pixels */
149 + process_variable(PVM_HEIGHT_OP, Option_String+2);
151 + case 'w': /* The width of a single grid block, in pixels */
153 + process_variable(PVM_WIDTH_OP, Option_String+2);
155 + case 's': /* specify the name of the slave */
157 + process_variable(PVM_SLAVE_OP, Option_String+2);
159 + case 'd': /* specify working directory for the slaves */
161 + process_variable(PVM_WD_OP, Option_String+2);
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. */
171 + if (chdir(&Option_String[2]) < 0) {
172 + fprintf(stderr, "Slave cannot cd to %s.\n", &Option_String[2]);
178 + fprintf(stderr, "Illegal +N%c switch setting\n", Option_String[1]);
187 @@ -1262,7 +1376,8 @@
192 +* Oct 1996 : Added options for PVMPOV [Deischi]
193 +* jun 2001 : conditional build for pvm
195 ******************************************************************************/
197 @@ -1445,21 +1560,36 @@
203 + if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF) {
206 if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF)
208 if(floatval > 0.0 && floatval <= 1.0)
210 opts.Last_Column = -1;
211 opts.Last_Column_Percent = floatval;
215 + opts.Last_Column = (int) floatval; }
218 opts.Last_Column = (int) floatval;
226 + if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF) {
229 if (sscanf (value, DBL_FORMAT_STRING, &floatval) != SCANF_EOF)
231 if(floatval > 0.0 && floatval <= 1.0)
234 @@ -1831,6 +1961,86 @@
235 Error ("Could not open Include_Ini='%s'.\n", value);
241 + * Options for PVMPOV
244 + if (sscanf(value, "%d", &PvmTasks) != 1 || PvmTasks < 1) {
245 + PvmTasks = 9999; /* Try to start one slave/available PVM host */
250 + if (sscanf(value, "%d", &PvmChunkWidth) != 1 || PvmChunkWidth < 4)
251 + PvmChunkWidth = PVM_DEFAULT_GRID_WIDTH;
254 + case PVM_HEIGHT_OP:
255 + if (sscanf(value, "%d", &PvmChunkHeight) != 1 || PvmChunkHeight < 4)
256 + PvmChunkHeight = PVM_DEFAULT_GRID_HEIGHT;
260 + PvmSlavename = POV_MALLOC( sizeof(char)*(strlen(value)+1),
262 + strcpy(PvmSlavename, value);
266 + strncpy(PvmArch,value,19);
267 + PvmArch[19] = '\0';
270 + PvmTasks = 9999; /* Try to start one slave/available PVM host */
274 + if (sscanf(value, "%d", &PvmNice) != 1 || PvmNice < 0) {
275 + PvmNice = PVM_DEFAULT_NICE;
280 + strncpy(PvmWorkingDir, value, PATH_MAX);
283 + case PVM_HOSTS_OP: {
288 + PvmHostsN = 1; /* count number of names */
289 + while((c = strchr(c, ',')) != NULL) {
293 + PvmHosts = (char**)POV_MALLOC( sizeof(char*) * PvmHostsN, "PvmHosts");
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';
304 + c2 = strchr(c, ',');
307 + PvmTasks = PvmHostsN;
313 + PvmTasks = istrue(value) ? 9999 : 0;
320 Warning(0.0,"Unimplemented INI '%s'.\n",Option_Variable[variable].Token_Name);
321 diff -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
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.
329 +* Oct 1996 : Added options for PVMPOV [Deischi]
330 +* Jun 2001 : Added conditional build for PVM Support [Agaran]
332 *****************************************************************************/
341 + /* new options for PVMPOV */
355 diff -Naur source.ori/optout.c source/optout.c
356 --- source.ori/optout.c Sat Jun 30 01:49:21 2001
357 +++ source/optout.c Sat Jun 30 09:25:02 2001
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.
362 +* Oct 1996 : Added options for PVMPOV [Deischi]
363 +* jun 2001 : added conditional build for pvm
365 *****************************************************************************/
378 /*****************************************************************************
379 * Local preprocessor defines
381 * Dec 1994 : Changed to show options depending on parameter n. [DB]
383 * Feb 1995 : Changed to terminate only if f != 0. [DB]
385 +* Oct 1996 : Added options from PVMPOV [Deischi]
386 +* Jun 2001 : conditional build for pvm
388 ******************************************************************************/
391 Banner(" 4 Output Options - file related\n");
392 Banner(" 5 Tracing Options\n");
393 Banner(" 6 Animation Options\n");
395 + Banner(" 7 PVM Options\n");
396 + Banner(" 8 Redirecting Options\n");
398 Banner(" 7 Redirecting Options\n");
413 + Banner("PVM options\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");
426 + /* Redirecting options. */
429 + Banner("Redirecting options\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");
441 /* Redirecting options. */
445 Banner(" GR - Render stream\n");
446 Banner(" GS - Statistics stream\n");
447 Banner(" GW - Warning stream\n");
457 +* Oct 1996 : Added options from PVMPOV [Deischi]
458 +* Jun 2001 : Added conditional build for PVM Support [Agaran]
460 ******************************************************************************/
462 @@ -1089,6 +1137,26 @@
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);
478 + Render_Info(" Pvm Hosts......");
479 + for(i=0; i < PvmHostsN; i++) {
480 + Render_Info(" %s", PvmHosts[i]);
487 /* Print redirecting options. */
489 diff -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
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.
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]
500 *****************************************************************************/
504 #define POV_RAY_VERSION "3.1g"
506 #define DISTRIBUTION_MESSAGE_1 "This is an unofficial version compiled by:"
508 +#define DISTRIBUTION_MESSAGE_2 "Jakob Flierl <flierl@luga.de> - PVMPOV Version 3.1e.2"
510 #define DISTRIBUTION_MESSAGE_2 "FILL IN NAME HERE........................."
512 #define DISTRIBUTION_MESSAGE_3 "The POV-Ray Team(tm) is not responsible for supporting this version."
514 /* Number of help pages (numbered 0 to MAX_HELP_PAGE). */
517 +#define MAX_HELP_PAGE 8
519 #define MAX_HELP_PAGE 7
524 diff -Naur source.ori/povray.c source/povray.c
525 --- source.ori/povray.c Sat Jun 30 01:49:21 2001
526 +++ source/povray.c Sat Jun 30 09:55:32 2001
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.
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]
535 *****************************************************************************/
539 #include "userio.h" /*Error,Warning,Init_Text_Streams*/
547 /*****************************************************************************
548 * Local preprocessor defines
550 static void fix_up_rendering_window (void);
551 static void fix_up_animation_values (void);
552 static void fix_up_scene_name (void);
554 +void set_output_file_handle (void);
555 +void setup_output_file_name (void);
556 +void open_output_file (void);
558 static void set_output_file_handle (void);
559 static void setup_output_file_name (void);
560 static void open_output_file (void);
562 static void FrameRender (void);
563 static void init_statistics (COUNTER *);
564 static void sum_statistics (COUNTER *, COUNTER *);
570 +* Oct 1996 : Added PVM Support [Deischi]
571 +* Jun 2001 : Added conditional build for PVM Support [Agaran]
573 ******************************************************************************/
575 @@ -262,17 +275,31 @@
580 + /* If slave, turn off certain optiongs */
582 + opts.Options &= ~(DISPLAY | VERBOSE);
585 /* Strip path and extension off input name to create scene name */
586 fix_up_scene_name ();
588 /* Redirect text streams [SCD 2/95] */
593 + /* Write .INI file [SCD 2/95] */
599 /* Write .INI file [SCD 2/95] */
605 /* Make sure clock is okay, validate animation parameters */
606 fix_up_animation_values();
609 /* Set output file handle for options screen. */
610 set_output_file_handle();
613 + /* Initialize PVM master */
614 + if ( !PvmSlave && PvmTasks)
615 + Pvm_Master_Init(argc, argv);
617 + /* Print options used. */
621 /* Print options used. */
626 /* VARIOUS INITIALIZATION THAT ONLY NEEDS TO BE DONE 1/EXECUTION */
635 + if( Pvm_Slave_Init() < 0)
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)) *
654 + MAIN_RETURN_STATEMENT
658 /* Execute the first shell-out command */
659 Pre_Scene_Result=(POV_SHELLOUT_CAST)POV_SHELLOUT(PRE_SCENE_SHL);
662 if (Pre_Scene_Result != ALL_SKIP_RET)
664 if (Pre_Scene_Result != SKIP_ONCE_RET)
666 + if(!PvmSlave && PvmTasks) {
668 + Pvm_Master_Control(); /* distribute work,
669 + and collect results,
670 + call shellout commands */
672 + trender = TIME_ELAPSED
674 + PRINT_STATS(totalstats);
676 + for (opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame,
677 + opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock;
679 + opts.FrameSeq.FrameNumber <= opts.FrameSeq.FinalFrame;
681 + opts.FrameSeq.FrameNumber++,
682 + opts.FrameSeq.Clock_Value += Clock_Delta)
686 for (opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame,
687 opts.FrameSeq.Clock_Value = opts.FrameSeq.InitialClock;
689 opts.FrameSeq.FrameNumber++,
690 opts.FrameSeq.Clock_Value += Clock_Delta)
693 setup_output_file_name();
695 /* Execute a shell-out command before tracing */
701 /* Print total stats ... */
703 if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME)
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]
711 ******************************************************************************/
714 /* Save variable values. */
715 variable_store(STORE);
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]
725 + open_output_file();
727 + /* Start the display. */
728 + if (opts.Options & DISPLAY)
730 + Status_Info ("\nDisplaying...");
732 + POV_DISPLAY_INIT(Frame.Screen_Width, Frame.Screen_Height);
734 + Display_Started = TRUE;
736 + /* Display vista tree. */
737 + Draw_Vista_Buffer();
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
744 @@ -502,15 +610,45 @@
745 /* Display vista tree. */
750 /* Get things ready for ray tracing (misc init, mem alloc) */
751 Initialize_Renderer();
753 + /* If a PVM slave, re-assign Write_Line to PVM */
755 + Output_File_Handle->Write_Line_p = Pvm_Write_Line;
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]
766 + if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE))
768 + Read_Rendered_Part(Actual_Output_Name);
770 + if (opts.Last_Line > Frame.Screen_Height)
771 + opts.Last_Line = Frame.Screen_Height;
773 + if (opts.Last_Column > Frame.Screen_Width)
774 + opts.Last_Column = Frame.Screen_Width;
777 + if(PvmSlave || !PvmTasks) {
778 + /* Get parsing time. */
780 + tparse = TIME_ELAPSED
782 + /* Get total parsing time. */
783 + tparse_total += tparse;
785 + } /* PvmSlave || !PvmTasks */
788 if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE))
790 Read_Rendered_Part(Actual_Output_Name);
793 /* Get total parsing time. */
794 tparse_total += tparse;
797 /* Store start time for trace. */
803 Status_Info ("\nRendering...\r");
807 + /* Macro for setting up any special FP options */
810 + /* Ok, go for it - trace the picture. */
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.
817 + if ( !opts.Radiosity_Preview_Done )
819 + if ( opts.Options & RADIOSITY )
821 + /* Note that radiosity REQUIRES a mosaic preview prior to main scan */
823 + Start_Tracing_Mosaic_Smooth(opts.PreviewGridSize_Start, opts.PreviewGridSize_End);
827 + if (opts.Options & PREVIEW && opts.Options & DISPLAY)
829 + Start_Tracing_Mosaic_Preview(opts.PreviewGridSize_Start, opts.PreviewGridSize_End);
834 + switch (opts.Tracing_Method)
838 + Start_Adaptive_Tracing();
845 + Start_Non_Adaptive_Tracing();
847 + } while(PvmSlave ? Pvm_Slave_Control() : 0); /* ask for more work */
851 + /* Record time so well spent before file close so it can be in comments */
853 + trender = TIME_ELAPSED
856 + /* Close out our file */
857 + if (Output_File_Handle)
859 + Close_File(Output_File_Handle);
863 /* Macro for setting up any special FP options */
868 Close_File(Output_File_Handle);
872 Stage = STAGE_SHUTDOWN;
876 /* Get total render time. */
877 trender_total += trender;
881 + POV_DISPLAY_FINISHED
883 + if ((opts.Options & DISPLAY) && Display_Started)
887 + Display_Started = FALSE;
890 + if (opts.histogram_on)
891 + write_histogram (opts.Histogram_File_Name) ;
893 + Status_Info("\nDone Tracing");
895 + /* Print stats ... */
897 + PRINT_STATS(stats);
902 if ((opts.Options & DISPLAY) && Display_Started)
905 /* Print stats ... */
909 if(opts.FrameSeq.FrameType==FT_MULTIPLE_FRAME)
912 @@ -1030,8 +1247,11 @@
913 * NULL function pointer.
915 ******************************************************************************/
918 +void set_output_file_handle()
920 static void set_output_file_handle()
923 char *def_ext = NULL;
924 char temp[FILE_NAME_LENGTH];
925 @@ -1110,7 +1330,11 @@
926 * function appends a path separator on output.
928 ******************************************************************************/
930 +void setup_output_file_name()
932 static void setup_output_file_name()
935 char number_string[10];
936 char separator_string[2] = {FILENAME_SEPARATOR, 0} ;
937 @@ -1219,8 +1443,11 @@
940 ******************************************************************************/
943 +void open_output_file()
945 static void open_output_file()
950 @@ -1378,12 +1605,18 @@
951 opts.Radiosity_Nearest_Count = 6;
952 opts.Radiosity_Recursion_Limit = 1;
953 opts.Radiosity_Quality = 6; /* Q-flag value for light gathering */
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;
960 opts.Radiosity_File_ReadOnContinue = 1;
961 opts.Radiosity_File_SaveWhileRendering = 1;
962 opts.Radiosity_File_AlwaysReadAtStart = 0;
963 opts.Radiosity_File_KeepOnAbort = 1;
965 opts.Radiosity_File_KeepAlways = 0;
968 init_statistics(stats);
969 init_statistics(totalstats);
970 diff -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
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.]
991 diff -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
995 +Surf to http://www.haveland.com/povbench/ to look at some render statistics.
996 diff -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
1000 +This file describes the command line options of PVMPOV, as well as the general
1001 +theory behind how it operates.
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.
1012 +Valid POV-Ray command-line options relating to PVM are:
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.
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.
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
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
1039 + Starting multiple tasks on a single processor will always be less
1040 + efficient than a single task because of context switching and extra
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
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.
1058 + +NWxx Change the width of the blocks to xx pixels. The default width
1062 + +NHxx Change the height of the blocks to xx pixels. The default height
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.
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.
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.
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.
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.
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!
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.
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.
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.
1121 +% pvmpov +nt8 +w1024 +h768 +iskyvase.pov +oskyvase.tga
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.
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.
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.
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.
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.
1160 +The command line arguments for specifying hosts is not cumulative, so
1162 +% pvmpov +naSUNMP +nt24 +n +iskyvase.pov +oskyvase.tga
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.
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.
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)
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.
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:
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
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.
1205 +The following command launches the PVM daemons.
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
1221 +pvmd still running.
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:
1227 +% pvmpov -Iskyvase.pov -Oskyvase.tga +nt24 +nw64 +nh64 +v
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
1236 +Waiting for slave stats.
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%]
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
1273 +NB: Note that for comparison purposes with other skyvase benchmarks that this
1274 + is rendered at 1024x768 instead of the usual 640x480!
1279 +adilger@enel.ucalgary.ca
1282 +k3096e5@c210.edvz.uni-linz.ac.at
1283 diff -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
1288 + - PVMPOV - written by Andreas Dilger, June 1 1995
1289 + and Harald Deischinger, 1997
1290 + modified by Jakob Flierl, 1999
1293 +***** NOTE - This is an UNOFFICIAL modification to POV-Ray 3.1e *****
1295 +** DO NOT SEND PROBLEM REPORTS TO THE POV TEAM REGARDING THESE MODIFICATIONS. **
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.
1302 +General information
1303 +-------------------
1305 +"I only ask that credit (or blame) is attributed to me for the original work."
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.
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.
1319 +Please send me a mail, if you're using PVMPOV Version 3.1e.2.
1323 +email : flierl@luga.de
1325 +Important information/Problems
1326 +------------------------------
1328 +* This version is not tested very vell, so it is very likely, that you
1329 + find some errors - please tell me about them.
1331 + Especially the very time consuming new features (radiosity) are not
1334 +* Shellout commands are always done by the master process.
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
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!
1345 + Field Rendering (+UF) is not working yet.
1347 +* The X11 display now displays everything.
1348 + There are no longer "forgotten blocks".
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
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.
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.
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.
1374 +* For more information see "PVMPOV.1st_scene"
1378 + optin.c Accept new options for PVMPOV
1380 + optout.c Print new options and help texts for PVMPOV
1382 + povray.c Major changes
1383 + render.c Minor changes
1385 diff -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
1389 +How to compile and install PVMPOV.
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
1397 +After that you can compile and install PVMPOV:
1399 + tar xvfz pvmpov-3.1e.?.tgz <- unpack the PVMPOV distfiles
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.]
1404 + ./inst-pvm <- apply the PVMPOV patch
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.]
1410 + cd pvmpov3_1e_?/povray31/source/pvm
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
1417 +This should create the executables 'pvmpov', 's-pvmpov' or 'x-pvmpov'.
1421 +If your are running PVMPOV on a homogenous cluster, you can copy the
1422 +executables to "/usr/bin" and "/usr/X11R6/bin".
1424 +Read "PVMPOV.example" to get started.
1426 +Jakob Flierl, flierl@luga.de
1428 diff -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
1432 +[...] PVMPOV and radiosity:
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:
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.
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.
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.
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.
1471 diff -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
1475 +/****************************************************************************
1478 +* This module implements the PVM control routines for PVM'd POVRAY.
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
1484 +* NOTE - PVM is not supplied here.
1486 +* You need the PVM 3.x libraries, include files, and PVMD daemons.
1488 +* PVM is available from the University of Tennessee, Knoxville, TN.
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.
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]
1499 +* 9704.. - changed to to animations, lots of changes
1500 +* simplifications to the whole thing [Deischi]
1502 +* 96.... - Changed code to work with POVRAY 3.0 [Deischi]
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.
1508 +* 940511 - Remove code that tried to fit grid sections into whole parts. The
1509 +* code now supports odd sized images.
1511 +*****************************************************************************/
1512 +#include <sys/time.h>
1513 +#include <sys/resource.h>
1515 +#include "vector.h"
1516 +#include "povproto.h"
1518 +#include "povray.h"
1519 +#include "render.h"
1520 +#include "optout.h"
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.).
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
1541 + * Global variables
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;
1548 +int PvmTasks = 9999;
1549 +int PvmNice = PVM_DEFAULT_NICE;
1552 +char * PvmSlavename = NULL;
1553 +int PvmNextFrame = 0;
1554 +char PvmWorkingDir[PATH_MAX+1] = ""; /* PVM Working Directory */
1555 +char ** PvmHosts = NULL;
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));
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));
1579 +static void PvmUnpackStats PARAMS((void));
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 */
1589 +static int grid_lines_done = 0; /* num. of PvmCthunkWidth lines done (only statistics) */
1591 +static int npixels_done = 0; /* Number of pixels done, by all processors */
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 */
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 */
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 */
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();
1626 +/********************************************************************************
1627 + * Initialize Master Process
1628 + *******************************************************************************/
1632 + * Spawn the slaves, and check for errors
1635 +/* handle an error from pvm_spawn */
1636 +static void PvmSpawnError(m)
1639 + /* Only quit if we can't start many tasks, or an error condition. */
1640 + Error_Line( "...error spawning tasks because \n");
1643 + Error_Line("of bad parameter.\n");
1646 + Error_Line("host not in PVM.\n");
1649 + Error_Line("executable not found.\n");
1652 + Error_Line("no memory on host.\n");
1655 + Error_Line("pvmd not responding.\n");
1658 + Error_Line("lack of resources.\n");
1661 + Error_Line("of unknown error.\n");
1669 +static void PvmSpawnTidError(tid)
1673 + Warning(0.0, "...spawn failure because ");
1676 + Warning(0.0, "of bad parameter.\n");
1679 + Warning(0.0, "host not in PVM.\n");
1682 + Warning(0.0, "executable not found.\n");
1685 + Warning(0.0, "no memory on host.\n");
1688 + Warning(0.0, "pvmd not responding.\n");
1691 + Warning(0.0, "lack of resources.\n");
1694 + Warning(0.0, "of unknown error.\n");
1698 +static void PvmSpawn() {
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);
1706 + Status_Info(" Spawning %s with %d PVM tasks on %d hosts...\n",
1707 + PvmSlavename, PvmTasks,nhost);
1710 + if(PvmHosts) { /* start at specified hosts */
1713 + for(i=0; i < PvmTasks; i++) { /* start one by one */
1714 + m = pvm_spawn(PvmSlavename, sargs, PvmTaskHost, PvmHosts[i % PvmHostsN],
1716 + if( m < 0) { /* spawn failed */
1718 + } else if (m==0) { /* failed a little bit */
1719 + PvmSpawnTidError(tids[minions]);
1724 + } else { /* start all at once somwhere */
1725 + minions = pvm_spawn(PvmSlavename, sargs, bitmask, PvmArch, PvmTasks, tids);
1727 + if(minions < 0) /* check for total failure */
1728 + PvmSpawnError(minions);
1729 + for (i = minions; i < PvmTasks; i++) /* errors/process */
1730 + PvmSpawnTidError(tids[i]);
1733 + /* Check if "few" tasks could be started */
1734 + if (minions < (PvmTasks + 1) / 2) {
1736 + Error_Line("...No tasks");
1738 + Error_Line("...only %d of %d tasks", minions, PvmTasks);
1740 + Error_Line(" spawned! Quitting.\n");
1745 + Status_Info(" ...%d PVM tasks successfully spawned.\n", minions);
1748 + PvmTasks = minions;
1753 + * Wait up to 120 seconds for the first to check in
1755 +static void PvmCheckFirst() {
1756 + wait_time.tv_sec = 120;
1757 + wait_time.tv_usec = 0;
1759 + Status_Info(" Waiting up to %lds for first slave to start...\n",
1760 + wait_time.tv_sec);
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");
1775 + if (opts.Options & VERBOSE) {
1776 + Status_Info(" Slave 0 successfully started.\n");
1782 + * Get a status struct for each slave
1784 +static void PvmInitSlaveStat() {
1786 + slave_stat = (pvm_slave_stat *)POV_CALLOC(PvmTasks, sizeof(pvm_slave_stat), "slave_stat");
1788 + /* Set up pointers to all the host names and the slave status */
1789 + for (slave_num = 0; slave_num < PvmTasks; slave_num++) {
1793 + dtid = pvm_tidtohost(tids[slave_num]);
1794 + slave_stat[slave_num].name = "unknown";
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);
1804 + slave_stat[slave_num].frame_assigned = PVM_SLAVE_FREE;
1805 + slave_stat[slave_num].block_reassigned = PVM_SLAVE_FREE;
1810 + * Get a status struct for each frame
1812 +static void PvmInitFrameStat() {
1815 + frames = (opts.FrameSeq.FrameType == FT_MULTIPLE_FRAME) ?
1816 + opts.FrameSeq.FinalFrame - opts.FrameSeq.InitialFrame + 1 :
1818 + frame_stat = (pvm_frame_stat *)POV_CALLOC(frames, sizeof(pvm_frame_stat), "frame_stat");
1819 + frame_display = -1;
1821 + for(i=0; i < frames; i++) {
1822 + frame_stat[i].block_to_assign = 0;
1823 + frame_stat[i].block_to_reassign = 0;
1825 + frame_stat[i].block_to_write = 0;
1827 + frame_stat[i].row_to_write = opts.First_Line;
1828 + frame_stat[i].row_to_malloc = opts.First_Line;
1830 + frame_stat[i].block_stat =
1831 + (pvm_block_stat *)POV_CALLOC(grid_points, sizeof(pvm_block_stat), "block_stat");
1833 + for(j=0; j < MaxStat; j++)
1834 + Init_Counter(frame_stat[i].stats[j]);
1839 + * Initialize PVM Master
1842 +Pvm_Master_Init(argc, argv)
1848 + Status_Info("Initializing PVMPOV\n");
1850 + /* Get a table for the TIDs */
1851 + tids = (int *)POV_CALLOC(PvmTasks, sizeof(int), "tids");
1853 + /* Build a new arg list for the sub-tasks - add -ni in front */
1854 + sargs = (char **)POV_CALLOC(argc + 1, sizeof(char *), "sargs");
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];
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");
1868 + /* Add slave flag */
1869 + sprintf(slave_option, "-nI%s", PvmWorkingDir);
1870 + sargs[0] = slave_option;
1872 + /* Enroll in PVM */
1873 + if (pvm_mytid() < 0) {
1874 + Error("Error starting master task.\n");
1877 + if (pvm_config(&nhost, (int *)NULL, &hostinfo) < 0) {
1879 + Error("Error getting PVM machine status.\n");
1882 + bitmask = PvmTaskDefault;
1884 + /* If PvmArch is specified, use that architecture */
1885 + if (PvmArch[0] != '\0') {
1886 + bitmask = PvmTaskArch;
1888 + /* If arch is psecified, but not the number of tasks, go and
1889 + * count how many hosts of that type there are.
1891 + if (PvmTasks >= 9999) {
1894 + for (i = 0; i < nhost; i++) {
1895 + if (strcmp(PvmArch,hostinfo[i].hi_arch) == 0)
1901 + /* If PvmTasks is specified, use that many tasks, otherwise use
1902 + * as many hosts as possible.
1904 + if (PvmTasks >= 9999) {
1908 + /* if no slavename was given, use name of current executable */
1909 + if(PvmSlavename == NULL)
1910 + PvmSlavename = argv[0];
1912 + PvmSpawn(); /* spawn the slaves */
1913 + PvmCheckFirst(); /* wait for first slave */
1915 + pvm_setopt(PvmRoute, PvmRouteDirect);
1917 + /* Max # of pixels in a grid row */
1918 + PvmChunkWidth = min(PvmChunkWidth, opts.Last_Column - opts.First_Column);
1920 + /* Grid points per line - rounded up */
1921 + grid_ppline = (opts.Last_Column - opts.First_Column + PvmChunkWidth - 1) / PvmChunkWidth;
1923 + /* Establish grid section height */
1924 + PvmChunkHeight = min(PvmChunkHeight, opts.Last_Line - opts.First_Line);
1926 + /* Total grid points in the image - round up PvmChunkHeight */
1927 + grid_points = ((opts.Last_Line - opts.First_Line + PvmChunkHeight - 1) / PvmChunkHeight) *
1930 + PvmInitSlaveStat();
1931 + PvmInitFrameStat();
1933 + /* initialize total stats */
1934 + for(i=0; i < MaxStat; i++) {
1935 + Init_Counter(totalstats[i]);
1943 +/********************************************************************************
1945 + ********************************************************************************/
1948 + * Receive a message
1950 +static int PvmMasterReceive() {
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");
1960 + /* We timed out waiting for any messages */
1972 + * Find name and number of slave, of current message
1974 +static void PvmIdentifySlave() {
1976 + /* get info about this msg. */
1977 + if (pvm_bufinfo(bufid, &bytesin, &msgtag, &rtid) < 0) {
1978 + Error_Line( "PVM Master cannot bufinfo.\n");
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;
1995 + * Send a PVM_WORK message
1996 + * Set block to PVM_GRID_POINT_ASSIGNED
1998 +static void PvmSendWork(block)
2001 + int row_start, row_end, col_start, col_end;
2003 + Status_Info("Assigning block: %d, frame: %d of %d to %s.\n", block, frame, frames, slave_name);
2006 + frame_stat[frame].block_stat[block].status = PVM_GRID_POINT_ASSIGNED;
2007 + frame_stat[frame].block_stat[block].assigned_tid = rtid;
2009 + row_start = (block/grid_ppline) * PvmChunkHeight + opts.First_Line;
2010 + row_end = (row_start + PvmChunkHeight) - 1;
2012 + if (row_end >= opts.Last_Line)
2013 + row_end = opts.Last_Line - 1;
2015 + col_start = (block%grid_ppline) * PvmChunkWidth + opts.First_Column;
2016 + col_end = (col_start + PvmChunkWidth) - 1;
2018 + if (col_end >= opts.Last_Column)
2019 + col_end = opts.Last_Column - 1;
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);
2035 + frame_stat[frame].block_to_assign ++;
2039 + * Send a PVM_WORK message
2040 + * Set block to PVM_GRID_POINT_REASSIGNED
2042 +static void PvmReassignWork(block)
2046 + Status_Info("Reassigning %d to %s.\n", block,
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;
2054 + if (frame_stat[frame].block_stat[block].wr_line == 0) {
2055 + row_start = (block / grid_ppline)*PvmChunkHeight + opts.First_Line;
2057 + row_start = frame_stat[frame].block_stat[block].wr_line;
2059 + row_end = (block/grid_ppline + 1) * PvmChunkHeight - 1;
2061 + if (row_end >= opts.Last_Line)
2062 + row_end = opts.Last_Line - 1;
2064 + col_start = (block % grid_ppline) * PvmChunkWidth +
2065 + opts.First_Column;
2066 + col_end = (col_start + PvmChunkWidth) - 1;
2068 + if (col_end >= opts.Last_Column)
2069 + col_end = opts.Last_Column - 1;
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);
2085 + frame_stat[frame].block_to_reassign++;
2090 + * Do all the stuff, that is necessary for a new frame
2091 + * This is called before the PVM_WORK is sent
2093 + * A lot of this is taken from 'FrameRender'
2095 + * ret: 0 .. OK send the PVMWOR
2096 + * 1 .. Shellout gave SKIP_ONCE_RET -> this frame is done
2098 +static int PvmStartFrame() {
2101 + if(frame_stat[frame].status != PVM_FRAME_FREE) {
2102 + Warning(0.0, "Frame %d already started.\n", frame);
2106 + if(opts.Options & VERBOSE)
2107 + Status_Info("\nStarting frame %d...", opts.FrameSeq.InitialFrame + frame);
2109 + frame_stat[frame].status = PVM_FRAME_WORKING;
2111 + /* allocate row pointers */
2112 + frame_stat[frame].row_ptr = (COLOUR **)POV_CALLOC(opts.Last_Line, sizeof(COLOUR *), "row_ptr");
2114 + opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame + frame;
2115 + setup_output_file_name();
2117 + /* Execute a shell-out command before tracing */
2118 + Frame_Result = POV_SHELLOUT(PRE_FRAME_SHL);
2120 + if (Frame_Result == ALL_SKIP_RET) {
2121 + /* stop completely */
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;
2128 + /* continue searching, frames before this one, should be finished */
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;
2138 + /* continue searching */
2143 + * open output file
2145 + set_output_file_handle();
2146 + open_output_file();
2148 + Initialize_Renderer();
2151 + * Start displaying
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");
2163 + * read already rendered parts
2165 + if ((opts.Options & DISKWRITE) && (opts.Options & CONTINUE_TRACE)) {
2167 + int fl = opts.First_Line; /* remember start of image */
2169 + Read_Rendered_Part(Actual_Output_Name); /* read -> changes opts.First_line */
2171 + frame_stat[frame].row_to_write =
2172 + frame_stat[frame].row_to_malloc = opts.First_Line;
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;
2180 + if(opts.Options & VERBOSE)
2181 + Status_Info("Continuing with block %d in frame %d\n",
2182 + frame_stat[frame].block_to_assign, frame);
2184 + opts.First_Line = fl; /* set back the old value */
2187 + /* this should not be necessary */
2188 + if (opts.Last_Line > Frame.Screen_Height)
2189 + opts.Last_Line = Frame.Screen_Height;
2191 + if (opts.Last_Column > Frame.Screen_Width)
2192 + opts.Last_Column = Frame.Screen_Width;
2196 + * make a copy of the Output_File_Handle
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;
2205 + if(opts.Options & VERBOSE)
2206 + Status_Info("\n");
2213 + * test, if the next frame in the sequence finished,
2214 + * do all the necessary stuff to close the frame (shellout, ...)
2216 +static void PvmFinishFrame() {
2218 + /* check, if frame has really finished */
2219 + if( frame_stat[frame].row_to_write < opts.Last_Line)
2222 + /* if not already closed */
2223 + if( frame_stat[frame].status < PVM_FRAME_DONE) {
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);
2229 + frame_stat[frame].status = PVM_FRAME_DONE;
2231 + POV_FREE(frame_stat[frame].row_ptr);
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);
2239 + if( frame == frame_display) {
2240 + POV_DISPLAY_FINISHED
2242 + if ((opts.Options & DISPLAY) && Display_Started) {
2245 + Display_Started = FALSE;
2248 + frame_display = -1;
2251 + if (opts.histogram_on)
2252 + write_histogram (opts.Histogram_File_Name);
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) {
2260 + frame_stat[frame].status = PVM_FRAME_DONE_SHELLOUT;
2262 + opts.FrameSeq.FrameNumber = opts.FrameSeq.InitialFrame + frame;
2263 + setup_output_file_name();
2265 + Frame_Result = POV_SHELLOUT(POST_FRAME_SHL);
2267 + if ((Frame_Result==SKIP_ONCE_RET) || (Frame_Result==ALL_SKIP_RET)) {
2268 + next_frame_finish = frames;
2271 + next_frame_finish ++; /* one more frame finished */
2273 + frame ++; /* check next frame (might have finished earlier) */
2274 + if( frame < frames)
2278 + if(opts.Options & VERBOSE)
2279 + Status_Info("\n");
2286 + * A slaved requested work, now find free block (or a block to reassign)
2288 +static void PvmAssignWork() {
2293 + /* The slave wants work, but has already been reassigned something,
2294 + * then tell it to ask again when it really wants work.
2296 + if( slave_stat[slave_num].block_reassigned != PVM_SLAVE_FREE) {
2298 + Status_Info("%s already assigned on %d. Not reassigning.\n",
2300 + slave_stat[slave_num].block_reassigned);
2302 + pvm_initsend(PvmDataDefault);
2303 + pvm_send(rtid, PVM_INIT_SLAVE);
2310 + * search for a free block, take a frame with minimal
2311 + * number of assigned blocks
2314 + min_assigned = grid_points;
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) ) {
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) ) {
2331 + Status_Info("\nfound: frame %d, ass: %d, min: %d\n",
2332 + f, frame_stat[f].block_to_assign,
2336 + min_assigned = frame_stat[f].block_to_assign;
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 */
2354 + slave_stat[slave_num].frame_assigned = frame;
2355 + PvmSendWork(frame_stat[frame].block_to_assign);
2361 + * found no free block
2362 + * search for a block to reassign
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) ) {
2370 + Status_Info("Not using %s for reassignment (%d%%)\n", slave_name,
2371 + 100*slave_stat[slave_num].pixels_done*PvmTasks/npixels_done);
2373 + /* tell slave to finish work */
2374 + pvm_initsend(PvmDataDefault);
2375 + pvm_send(rtid, PVM_STOP_SLAVE);
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) ) {
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) {
2394 + min_assigned = frame_stat[frame].block_to_reassign;
2401 + /* find block in frame */
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);
2413 + * there is nothing left to reassign
2415 + Status_Info("All blocks are assigned. Stopping %s.\n", slave_name);
2417 + /* tell slave to finish work */
2418 + pvm_initsend(PvmDataDefault);
2419 + pvm_send(rtid, PVM_STOP_SLAVE);
2424 + * display a part from one line
2426 +static void PvmDisplayPlot(row_ptr, row, col, ncols)
2428 + int row, col, ncols;
2430 + unsigned char Red, Green, Blue, Alpha;
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);
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);
2447 + * one of the slaves sends a part of it's computed data
2449 +static void PvmReceiveData() {
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);
2460 + row_end = row_start + (bytesin - 3*sizeof(int))/(5*ncols*sizeof(COLC));
2461 + col_end = col_start + ncols;
2464 + Status_Info("receiving frame: %d, row: %d-%d, col: %d-%d\n",
2465 + frame, row_start, row_end, col_start, col_end);
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) ) {
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);
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? */
2485 + /* allocate memory, to receive data */
2486 + if (frame_stat[frame].row_ptr[i] == NULL) { /* Starting a new row */
2488 + frame_stat[frame].row_ptr[i] = (COLOUR *)POV_MALLOC(opts.Last_Column*sizeof(COLOUR),
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++;
2497 + /* get color data */
2498 + pvm_upkCOL(&(frame_stat[frame].row_ptr[i][col_start][0]),5*ncols,1);
2500 + frame_stat[frame].block_stat[block].wr_line = i + 1;
2502 + if (frame == frame_display) {
2503 + PvmDisplayPlot(frame_stat[frame].row_ptr[i], i, col_start, ncols);
2506 + /* Statistics - Attribute this grid section */
2507 + grid_lines_done++;
2508 + slave_stat[slave_num].pixels_done += ncols;
2510 + npixels_done += ncols;
2512 + /* another slave already sent this data */
2514 + COLOUR *dummy = (COLOUR *)POV_MALLOC(ncols * sizeof(COLOUR), "dummy row");
2515 + pvm_upkCOL(&(dummy[0][0]),5*ncols,1);
2517 + /* Statistics - Attribute this grid section */
2518 + slave_stat[slave_num].pixels_late += ncols;
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) {
2527 + Status_Info("Block completed by %s\n", slave_name);
2529 + frame_stat[frame].block_stat[block].status = PVM_GRID_POINT_DONE;
2530 + if (slave_stat[slave_num].block_reassigned == block) {
2532 + Status_Info(" reassigned block cleared.\n");
2534 + slave_stat[slave_num].block_reassigned = PVM_SLAVE_FREE;
2539 + Status_Info(" reassigned block is %d.\n",
2540 + slave_stat[slave_num].block_reassigned);
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);
2552 + * Write out us many lines as possible
2554 +static void PvmWrite() {
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) {
2563 + Status_Info("needing block %d in frame %d\n", i, frame);
2569 + /* OK, we can write a whole line */
2570 + if (opts.Options & DISKWRITE) {
2572 + Status_Info("write: %d %d\n", frame, frame_stat[frame].row_to_write);
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);
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;
2591 + frame_stat[frame].row_to_write++;
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);
2601 +#endif /* not DEBUG */
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;
2609 + frame_stat[frame].block_to_write += grid_ppline;
2612 + } while(frame_stat[frame].block_to_write < grid_points);
2616 + * Handle slave requests, distribute and collect work
2618 +void Pvm_Master_Control() {
2620 + /* Wait five minutes at a time between messages */
2621 + wait_time.tv_sec = 300;
2623 + next_frame_finish = 0; /* next frame that finishes */
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))) {
2629 + /* check for user abort */
2632 + Render_Info("\nAborting render...\n");
2636 + if ((opts.Options & DISPLAY) && Display_Started) {
2637 + POV_DISPLAY_CLOSE;
2639 + if (opts.Do_Stats) {
2640 + PRINT_STATS(stats);
2642 + Error("User abort.\n");
2647 + /* receive a request from a slave */
2648 + if(PvmMasterReceive())
2651 + PvmIdentifySlave();
2654 + Status_Info("Received msg %d from %s\n", msgtag, slave_name);
2657 + /* a slaves requests work */
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);
2666 + case PVM_NEED_WORK: /* a slave wants work */
2670 + case PVM_SLAVE_RESULTS: /* slaves sends us some data */
2676 + case PVM_SLAVE_STATS: /* Too many stats, eh? */
2678 + Status_Info("Getting stats from %s.\n", slave_name);
2684 + case PVM_SLAVE_EXIT: /* Slave has exited. */
2685 + Status_Info("\nSlave at %s has exited.\n",slave_name);
2687 + if (--minions <= 0) {
2688 + Error_Line( "Error - All slave tasks have exited!\n");
2694 + default: /* something strange happend */
2695 + Warning(0.0, "Bad block recieved from %s - message type %4X.\n",
2696 + slave_name, msgtag);
2698 + } /* incomplete frames */
2700 + /* Finished calculating everything */
2707 +static void PvmMasterEnd() {
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);
2716 + /* Wait a few seconds for lingering stats */
2717 + wait_time.tv_sec = 4;
2718 + wait_time.tv_usec = 0;
2720 + if (opts.Options & VERBOSE)
2721 + Status_Info("\nWaiting for remaining slave stats.\n");
2723 + /* some incoming stats */
2724 + while ((bufid = pvm_trecv(-1, PVM_SLAVE_STATS, &wait_time)) > 0) {
2727 + if (pvm_bufinfo(bufid, &bytesin, &msgtag, &rtid) < 0) {
2728 + Error_Line( "PVM Master cannot bufinfo.\n");
2734 + PvmIdentifySlave();
2736 + Status_Info("Getting stats from %s.\n", slave_name);
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");
2748 + for (i = 0; i < PvmTasks; i++) {
2752 + dtid = pvm_tidtohost(tids[i]);
2754 + for (j = 0; j < PvmTasks; j++) {
2755 + if (dtid == hostinfo[j].hi_tid)
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);
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);
2775 + if (opts.Do_Stats) {
2776 + Statistics("\n\nTotal statistics:");
2783 + * A slave sent some stats
2785 +static void PvmUnpackStats() {
2786 + COUNTER tmpStat[MaxStat];
2788 + pvm_upkint(&frame, 1, 1);
2790 + if( pvm_upkSTAT((long*)tmpStat, MaxStat*sizeof(COUNTER)/sizeof(long), 1) >= 0) {
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;
2800 + Add_Counter(tmp,tmpStat[i],totalstats[i]);
2801 + totalstats[i] = tmp;
2803 + if(opts.FrameSeq.FrameType != FT_MULTIPLE_FRAME) {
2804 + Add_Counter(tmp,tmpStat[i],stats[i]);
2809 + Error_Line("Unpack Stats.\n");
2816 +/********************************************************************************
2817 + * Slave Intialization
2818 + ********************************************************************************/
2820 +int Pvm_Slave_Init() {
2821 + /* Get master TID */
2822 + PvmMTid = pvm_parent();
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);
2829 + /* Set direct routing */
2830 + pvm_setopt(PvmRoute, PvmRouteDirect);
2832 + /* Tell the master we started successfully */
2833 + pvm_initsend(PvmDataDefault);
2834 + pvm_send(PvmMTid, PVM_INIT_SLAVE);
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.
2840 + pvm_initsend(PvmDataDefault);
2841 + pvm_send(PvmMTid, PVM_NEED_WORK);
2849 +/********************************************************************************
2851 + ********************************************************************************/
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);
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)
2866 +int Pvm_Slave_Control() {
2868 + struct timeval wait_time;
2870 + unsigned int msgtag;
2872 + static int first = 1;
2874 + /* Wait up to 5 minutes for a message, otherwise exit */
2875 + wait_time.tv_sec = 300;
2876 + wait_time.tv_usec = 0;
2878 + if((bufid = pvm_trecv(PvmMTid, -1, &wait_time)) == 0) {
2879 + Error_Line( "Slave timed out waiting for master\n");
2882 + } else if (bufid < 0) {
2883 + Error_Line( "Cannot receive message from master.");
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");
2898 + case PVM_INIT_SLAVE:
2899 + pvm_initsend(PvmDataDefault);
2900 + pvm_send(PvmMTid, PVM_NEED_WORK);
2904 + /* Ask master for some more block assignments in advance
2905 + * to avoid waiting for them to be sent later
2907 + pvm_initsend(PvmDataDefault);
2908 + pvm_send(PvmMTid, PVM_NEED_WORK);
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);
2918 + /* Last_Line is really "number of lines to do" */
2921 + /* Send the data every 1/4 of a block */
2922 + PvmRowsToSend = (opts.Last_Line - opts.First_Line + 3) / 4;
2924 + /* Last_Column is really "number of columns to do" */
2925 + opts.Last_Column++;
2927 + /* check, if a new frame starts */
2932 + PvmNextFrame = opts.FrameSeq.InitialFrame + f;
2934 + return 0; /* stop with this frame */
2937 + /* We need to do this for every block */
2938 + Initialize_Renderer();
2940 + return 1; /* still the same frame */
2942 + case PVM_STOP_SLAVE: /* Everything is done, send stats and exit */
2944 + PvmNextFrame = opts.FrameSeq.FinalFrame + 1;
2947 + case PVM_KILL_SLAVE:
2948 + Error_Line("\nSlave killed because of dead master.\n");
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 */
2960 +void Pvm_Slave_Exit() {
2961 + pvm_initsend(PvmDataDefault);
2962 + pvm_send(PvmMTid, PVM_SLAVE_EXIT);
2966 +void Pvm_Write_Line(handle, line_data, line_number)
2967 + FILE_HANDLE *handle;
2968 + COLOUR *line_data;
2971 + static int in_buffer = 0;
2974 + if (in_buffer == 0) /* No lines written yet. Initialize buffer */
2976 + ncols = opts.Last_Column - opts.First_Column;
2977 + pvm_initsend(PvmDataDefault);
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);
2987 + if (pvm_pkCOL(&(line_data[opts.First_Column][0]),5*ncols, 1) < 0) {
2988 + Error_Line( "Cannot pack in Pvm_Write_Line\n");
2990 + if (in_buffer > 0) {
2991 + pvm_send(PvmMTid, PvmBlockNum); /* Send any lines we have done. */
2993 + pvm_initsend(PvmDataDefault);
2994 + pvm_send(PvmMTid, PVM_SLAVE_EXIT); /* Tell the master we're dying */
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");
3031 diff -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
3035 +/****************************************************************************
3038 +* This include module is used by PVM control routines in the PVM'd PovRAY.
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
3045 +* All the defines that need modification are at the top.
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.
3052 +*****************************************************************************/
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.
3060 +#include <features.h>
3062 +#if defined(SUN4SOL2) || defined(your_pvm_arch)
3064 +#define NICE(x) nice(x)
3065 +extern int nice PARAMS((int prio));
3069 +/* This should work for the majority of systems */
3071 +#define NICE(x) setpriority(PRIO_PROCESS,0,getpriority(PRIO_PROCESS,0)+(x))
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));
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.
3083 +#define PVM_DEFAULT_NICE 5
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.
3089 +#if defined(NEXT) || defined(your_pvm_arch)
3091 +#define GETCWD(path) getwd(path)
3092 +extern char *getwd PARAMS((char *));
3096 +#define GETCWD(path) getcwd(path,PATH_MAX+1)
3097 +extern char *getcwd PARAMS((char *, size_t ));
3101 +extern int chdir PARAMS((const char *path));
3103 +/* Grid decomposition defaults */
3104 +#define PVM_DEFAULT_GRID_HEIGHT 32
3105 +#define PVM_DEFAULT_GRID_WIDTH 32
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
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>.*/
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 */
3125 +/* Structure to hold info about each slave process */
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 */
3134 +#define PVM_SLAVE_FREE -1
3136 +/* Structure to hold info about each grid section */
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 */
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
3151 +/* Structure to hold info about each frame */
3154 + COLOUR ** row_ptr;
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;
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
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
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));
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;
3199 diff -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
3203 #include "texture.h"
3204 #include "vbuffer.h"
3211 /*****************************************************************************
3212 * Local preprocessor defines
3215 #define SUB_PIXEL_GRID_SIZE 16
3221 /*****************************************************************************
3223 ******************************************************************************/
3226 static int SuperSampleCount, RadiosityCount;
3232 /* Jitter values are taken from [-0.5*JitterScale, 0.5*JitterScale]. */
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);
3239 static void extract_colors (COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey);
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);
3249 +* Oct 1996: Added support for PVM [Deischi]
3250 +* Jun 2001: Added conditional build for PVM Support [Agaran]
3252 ******************************************************************************/
3254 @@ -368,6 +379,12 @@
3256 size = (Frame.Screen_Width + 1) * sizeof(COLOUR);
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);
3264 Previous_Line = (COLOUR *)POV_MALLOC(size, "previous line buffer");
3265 Current_Line = (COLOUR *)POV_MALLOC(size, "current line buffer");
3267 @@ -381,6 +398,12 @@
3269 size = (Frame.Screen_Width + 1) * sizeof(char);
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);
3277 Previous_Line_Antialiased_Flags = (char *)POV_MALLOC(size, "previous line flags");
3278 Current_Line_Antialiased_Flags = (char *)POV_MALLOC(size, "current line flags");
3280 @@ -390,6 +413,11 @@
3281 Current_Line_Antialiased_Flags[i] = 0;
3285 + /* If PVM, this is already enough */
3286 + if(PvmTasks && !PvmSlave)
3290 Assign_Vector(Camera_Ray.Initial, Frame.Camera->Location);
3292 @@ -3154,8 +3182,11 @@
3293 * Jun 1995 : Alpha channel support -CEY
3295 ******************************************************************************/
3298 +void extract_colors(COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey)
3300 static void extract_colors(COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey)
3303 if (opts.PaletteOption == GREY)
3305 diff -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
3309 extern unsigned long *histogram_grid ;
3310 extern unsigned long max_histogram_value ;
3311 extern FILE_HANDLE *Histogram_File_Handle ;
3316 /*****************************************************************************
3319 DBL Trace (RAY *Ray, COLOUR Colour, DBL Weight);
3320 void Check_User_Abort (int Do_Stats);
3321 void write_histogram (char *filename);
3323 +void extract_colors (COLOUR Colour, unsigned char *Red, unsigned char *Green, unsigned char *Blue, unsigned char *Alpha, DBL *grey);
3326 void destroy_histogram (void);
3329 diff -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
3333 #CFLAGS = -O6 -finline-functions -ffast-math -c -ansi -m386 -DCPU=586 -DCOMPILER_VER=\".`uname`.$(CC)\" -DPOV_LIB_DIR=\"$(POVLIBDIR)\" $(SRCINC) $(LIBPNGINC) $(ZLIBINC)
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)
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 @@
3343 # UTARGET is the name of the text-only UNIX version
3347 # XTARGET is the name of the X-Windows executable.
3349 +XTARGET_PVM=x-pvmpov
3351 # STARGET is the name of the SVGA executable.
3353 +STARGET_PVM=s-pvmpov
3355 # This is the suffix for object files.
3357 @@ -167,6 +170,13 @@
3359 SRCINC = -I. -I$(SRCDIR)
3362 +#PVMINC = -I$(PVM_ROOT)/include
3363 +#PVMLIB = /usr/lib/libpvm3.a /usr/lib/libgpvm3.a
3365 +# dunno for what that is used
3366 +XDIR = $(HOME)/pvm3/bin/$(PVM_ARCH)
3369 # End of user specific options
3371 @@ -1526,6 +1536,12 @@
3373 $(SRCDIR)/povproto.h
3375 +pvmDEP = $(SRCDIR)/pvm.c \
3378 +# $(UNIXDIR)/unixconf.h
3383 @echo 'You need to select which executable version you want'
3384 @@ -1549,46 +1565,89 @@
3388 +unix_pvm: $(UTARGET_PVM)
3391 $(UTARGET): $(POVOBJS) $(ODIR)/unix$(OBJ)
3392 $(CC) $(POVOBJS) $(ODIR)/unix$(OBJ) $(LFLAGS) -o $(UTARGET)
3394 +$(UTARGET_PVM): $(POVOBJS) $(ODIR)/pvm$(OBJ) $(ODIR)/unix$(OBJ)
3395 + $(CC) $(POVOBJS) $(ODIR)/unix$(OBJ) $(ODIR)/pvm$(OBJ) $(PVMLIB) $(LFLAGS) -o $(UTARGET_PVM)
3400 +svga_pvm: $(STARGET_PVM)
3404 $(STARGET): $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ)
3405 $(CC) $(POVOBJS) $(ODIR)/svga$(OBJ) $(ODIR)/unix$(OBJ) $(LFLAGS) $(SLIBLIB) -o $(STARGET)
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)
3413 +xwin_pvm: $(XTARGET_PVM)
3416 $(XTARGET): $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ)
3417 $(CC) $(POVOBJS) $(ODIR)/xwindows$(OBJ) $(ODIR)/unix$(OBJ) $(LFLAGS) $(XLIBLIB) -o $(XTARGET)
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)
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)
3427 +PVMOBJ = $(ODIR)/optin$(OBJ) $(ODIR)/optout$(OBJ) $(ODIR)/povray$(OBJ) $(ODIR)render$(OBJ)
3430 - -@$(RM) $(DISPOBJS)
3431 + -@$(RM) $(DISPOBJS) $(PVMOBJ)
3432 -@cp unixconf.h config.h
3433 -@touch -c $(ODIR)/*$(OBJ)
3437 + -@$(RM) $(DISPOBJS) $(PVMOBJ)
3438 + -@cp unixconf.h config.h
3439 + -@touch -c $(ODIR)/*$(OBJ)
3440 + -@$(MAKE) PVMFLAGS="-DUSE_PVM" unix_pvm
3444 - -@$(RM) $(DISPOBJS)
3445 + -@$(RM) $(DISPOBJS) $(PVMOBJ)
3446 -@cp svgaconf.h config.h
3447 -@touch -c $(ODIR)/*$(OBJ)
3451 + -@$(RM) $(DISPOBJS) $(PVMOBJ)
3452 + -@cp svgaconf.h config.h
3453 + -@touch -c $(ODIR)/*$(OBJ)
3454 + -@$(MAKE) PVMFLAGS="-DUSE_PVM" svga_pvm
3457 - -@$(RM) $(DISPOBJS)
3458 + -@$(RM) $(DISPOBJS) $(PVMOBJ)
3459 -@cp xwinconf.h config.h
3460 -@touch -c $(ODIR)/*$(OBJ)
3464 + -@$(RM) $(DISPOBJS) $(PVMOBJ)
3465 + -@cp xwinconf.h config.h
3466 + -@touch -c $(ODIR)/*$(OBJ)
3467 + -@$(MAKE) PVMFLAGS="-DUSE_PVM" xwin_pvm
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)
3478 -@cp povray.1 $(POVPATH)/man/man1
3479 @@ -1821,17 +1880,7 @@
3480 $(ODIR)/xwindows$(OBJ) : $(xwindowsDEP)
3481 $(CC) $(CFLAGS) $(XLIBINC) xwindows.c
3495 +$(ODIR)/pvm$(OBJ) : $(pvmDEP)
3496 + $(CC) $(CFLAGS) $(SRCDIR)/pvm.c