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