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