1 /**
2 * Mandelbulber v2, a 3D fractal generator ,=#MKNmMMKmmßMNWy,
3 * ,B" ]L,,p%%%,,,§;, "K
4 * Copyright (C) 2015-21 Mandelbulber Team §R-==%w["'~5]m%=L.=~5N
5 * ,=mm=§M ]=4 yJKA"/-Nsaj "Bw,==,,
6 * This file is part of Mandelbulber. §R.r= jw",M Km .mM FW ",§=ß., ,TN
7 * ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8 * Mandelbulber is free software: §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9 * you can redistribute it and/or §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10 * modify it under the terms of the "§M=M =D=4"N #"%==A%p M§ M6 R' #"=~.4M
11 * GNU General Public License as §W =, ][T"]C § § '§ e===~ U !§[Z ]N
12 * published by the 4M",,Jm=,"=e~ § § j]]""N BmM"py=ßM
13 * Free Software Foundation, ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14 * either version 3 of the License, TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15 * or (at your option) TW=,-#"%=;[ =Q:["V"" ],,M.m == ]N
16 * any later version. J§"mr"] ,=,," =="""J]= M"M"]==ß"
17 * §= "=C=4 §"eM "=B:m|4"]#F,§~
18 * Mandelbulber is distributed in "9w=,,]w em%wJ '"~" ,=,,ß"
19 * the hope that it will be useful, . "K= ,=RMMMßM"""
20 * but WITHOUT ANY WARRANTY; .'''
21 * without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 * See the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27 *
28 * ###########################################################################
29 *
30 * Authors: Krzysztof Marczak (buddhi1980@gmail.com), Sebastian Jennen (jenzebas@gmail.com),
31 * Robert Pancoast (RobertPancoast77@gmail.com)
32 *
33 * cCommandLineInterface - CLI Input handler
34 */
35
36 #include "command_line_interface.hpp"
37
38 #include <ctime>
39
40 #include <QList>
41
42 #include "animation_frames.hpp"
43 #include "error_message.hpp"
44 #include "file_image.hpp"
45 #include "fractal_container.hpp"
46 #include "global_data.hpp"
47 #include "headless.h"
48 #include "initparameters.hpp"
49 #include "interface.hpp"
50 #include "keyframes.hpp"
51 #include "netrender.hpp"
52 #include "old_settings.hpp"
53 #include "opencl_global.h"
54 #include "opencl_hardware.h"
55 #include "queue.hpp"
56 #include "settings.hpp"
57 #include "system_data.hpp"
58 #include "system_directories.hpp"
59 #include "test.hpp"
60 #include "write_log.hpp"
61
cCommandLineInterface(QCoreApplication * _qApplication)62 cCommandLineInterface::cCommandLineInterface(QCoreApplication *_qApplication)
63 : settingsSpecified(false)
64 {
65 qApplication = _qApplication;
66 // text from http://sourceforge.net/projects/mandelbulber/
67 parser.setApplicationDescription(QCoreApplication::translate("main",
68 "Mandelbulber is an easy to use, "
69 "handy application designed to help you render 3D Mandelbrot fractals called Mandelbulb "
70 "and some other kind of 3D fractals like Mandelbox, Bulbbox, Juliabulb, Menger Sponge"));
71
72 parser.addHelpOption();
73 parser.addVersionOption();
74
75 const QCommandLineOption noguiOption(QStringList({"n", "nogui"}),
76 QCoreApplication::translate("main", "Starts the program without a GUI."));
77
78 const QCommandLineOption keyframeOption(QStringList({"K", "keyframe"}),
79 QCoreApplication::translate("main", "Renders keyframe animation."));
80
81 const QCommandLineOption flightOption(
82 QStringList({"F", "flight"}), QCoreApplication::translate("main", "Renders flight animation."));
83
84 const QCommandLineOption silentOption(QStringList({"X", "never-delete"}),
85 QCoreApplication::translate("main", "Never delete data, instead Exit CLI application."));
86
87 const QCommandLineOption startOption(QStringList({"s", "start"}),
88 QCoreApplication::translate("main", "Starts rendering from frame number <N>."),
89 QCoreApplication::translate("main", "N"));
90
91 const QCommandLineOption endOption(QStringList({"e", "end"}),
92 QCoreApplication::translate("main", "Stops rendering on frame number <N>."),
93 QCoreApplication::translate("main", "N"));
94
95 const QCommandLineOption overrideOption(QStringList({"O", "override"}),
96 QCoreApplication::translate("main",
97 "<KEY=VALUE> overrides item '<KEY>' from settings file with new value '<VALUE>'.\n"
98 "Specify multiple KEY=VALUE pairs by separating with a '#': <KEY1=VALUE1#KEY2=VALUE2>. Quote "
99 "whole expression to avoid whitespace parsing issues\n"
100 "Override fractal parameter in the form 'fractal<N>_KEY=VALUE' with <N> being index of "
101 "fractal"),
102 QCoreApplication::translate("main", "..."));
103
104 const QCommandLineOption listOption(QStringList({"L", "list"}),
105 QCoreApplication::translate(
106 "main", "Lists all possible parameters '<KEY>' with corresponding default value '<VALUE>'."));
107
108 const QCommandLineOption formatOption(QStringList({"f", "format"}),
109 QCoreApplication::translate("main",
110 "Image output format:\n"
111 " jpg - JPEG format (default)\n"
112 " png - PNG format\n"
113 " exr - EXR format\n"
114 " tiff - TIFF format\n"
115 " Legacy formats for still frames:\n"
116 " png16 - 16-bit PNG format\n"
117 " png16alpha - 16-bit PNG with alpha channel format"),
118 QCoreApplication::translate("main", "FORMAT"));
119
120 const QCommandLineOption resOption(QStringList({"r", "res"}),
121 QCoreApplication::translate(
122 "main", "Overrides image resolution. Specify as width and height separated by 'x'"),
123 QCoreApplication::translate("main", "WxH"));
124
125 const QCommandLineOption fpkOption("fpk",
126 QCoreApplication::translate("main", "Overrides frames per key parameter."),
127 QCoreApplication::translate("main", "N"));
128
129 const QCommandLineOption serverOption(QStringList({"S", "server"}),
130 QCoreApplication::translate("main", "Sets application as a server listening for clients."));
131
132 const QCommandLineOption hostOption(QStringList({"H", "host"}),
133 QCoreApplication::translate("main",
134 "Sets application as a client connected to server of given host address"
135 " (Host can be of type IPv4, IPv6 and Domain name address)."),
136 QCoreApplication::translate("main", "N.N.N.N"));
137
138 const QCommandLineOption portOption(QStringList({"p", "port"}),
139 QCoreApplication::translate("main", "Sets network port number for netrender (default 5555)."),
140 QCoreApplication::translate("main", "N"));
141
142 const QCommandLineOption noColorOption(QStringList({"C", "no-cli-color"}),
143 QCoreApplication::translate(
144 "main", "Starts program without ANSI colors, when execution on CLI."));
145
146 const QCommandLineOption outputOption(QStringList({"o", "output"}),
147 QCoreApplication::translate("main", "Saves rendered image(s) to this file / folder."),
148 QCoreApplication::translate("main", "N"));
149
150 const QCommandLineOption logFilepathOption(QStringList({"logfilepath"}),
151 QCoreApplication::translate(
152 "main", "Specify custom system log filepath (default is: ~/.mandelbulber_log.txt)."),
153 QCoreApplication::translate("main", "N"));
154
155 const QCommandLineOption queueOption(QStringList({"q", "queue"}),
156 QCoreApplication::translate("main", "Renders all images from common queue."));
157
158 const QCommandLineOption testOption(QStringList({"t", "test"}),
159 QCoreApplication::translate("main", "Runs testcases on the mandelbulber instance"));
160
161 const QCommandLineOption benchmarkOption(QStringList({"b", "benchmark"}),
162 QCoreApplication::translate("main",
163 "Runs benchmarks on the mandelbulber instance, specify optional"
164 " parameter difficulty (1 -> very easy, > 20 -> very hard, 10 -> default)."
165 " When [output] option is set to a folder, the example-test images will be stored there."));
166
167 const QCommandLineOption gpuOption(QStringList({"g", "gpu"}),
168 QCoreApplication::translate(
169 "main", "Runs the program in opencl mode and selects first available gpu device."));
170
171 const QCommandLineOption gpuAllOption(QStringList({"G", "gpuall"}),
172 QCoreApplication::translate(
173 "main", "Runs the program in opencl mode and selects all available gpu devices."));
174
175 const QCommandLineOption touchOption(QStringList({"T", "touch"}),
176 QCoreApplication::translate(
177 "main", "Resaves a settings file (can be used to update a settings file)"));
178
179 const QCommandLineOption voxelOption(QStringList({"V", "voxel"}),
180 QCoreApplication::translate("main",
181 "Renders the voxel volume. Output formats are:\n"
182 " slice - stack of PNG images into one folder (default)\n"
183 " ply - Polygon File Format (single 3d file)\n"),
184 QCoreApplication::translate("main", "FORMAT"));
185
186 const QCommandLineOption statsOption(QStringList({"stats"}),
187 QCoreApplication::translate("main", "Shows statistics while rendering in CLI mode."));
188
189 const QCommandLineOption helpInputOption(
190 QStringList({"help-input"}), QCoreApplication::translate("main", "Shows help about input."));
191 const QCommandLineOption helpExamplesOption(
192 QStringList({"help-examples"}), QCoreApplication::translate("main", "Shows example commands."));
193 const QCommandLineOption helpOpenClOption(QStringList({"help-opencl"}),
194 QCoreApplication::translate("main", "Shows commands regarding OpenCL."));
195
196 parser.addPositionalArgument("settings_file",
197 QCoreApplication::translate("main",
198 "file with fractal settings (program also tries\nto find file in ./mandelbulber/settings "
199 "directory)\n"
200 "When settings_file is put as a command line argument then program will start in noGUI mode"
201 "<settings_file> can also be specified as a list, see all options with --help-input"));
202
203 parser.addOption(noguiOption);
204 parser.addOption(outputOption);
205 parser.addOption(logFilepathOption);
206 parser.addOption(keyframeOption);
207 parser.addOption(flightOption);
208 parser.addOption(silentOption);
209 parser.addOption(startOption);
210 parser.addOption(endOption);
211 parser.addOption(listOption);
212 parser.addOption(formatOption);
213 parser.addOption(resOption);
214 parser.addOption(fpkOption);
215 parser.addOption(serverOption);
216 parser.addOption(hostOption);
217 parser.addOption(portOption);
218 parser.addOption(noColorOption);
219 parser.addOption(queueOption);
220 parser.addOption(testOption);
221 parser.addOption(benchmarkOption);
222 parser.addOption(touchOption);
223 parser.addOption(voxelOption);
224 parser.addOption(overrideOption);
225 parser.addOption(statsOption);
226 parser.addOption(gpuOption);
227 parser.addOption(gpuAllOption);
228 parser.addOption(helpInputOption);
229 parser.addOption(helpExamplesOption);
230 parser.addOption(helpOpenClOption);
231
232 // Process the actual command line arguments given by the user
233 parser.process(*qApplication);
234 args = parser.positionalArguments();
235 if (!args.empty() && args[0] == "-")
236 {
237 // "-" marks stdin to be used as the input for the program (filename or content)
238 // use the input as first argument
239 QTextStream qin(stdin);
240 args[0] = qin.readAll();
241 }
242
243 cliData.nogui = parser.isSet(noguiOption);
244 cliData.keyframe = parser.isSet(keyframeOption);
245 cliData.flight = parser.isSet(flightOption);
246 cliData.silent = parser.isSet(silentOption);
247 cliData.startFrameText = parser.value(startOption);
248 cliData.endFrameText = parser.value(endOption);
249 cliData.overrideParametersText = parser.value(overrideOption);
250 cliData.imageFileFormat = parser.value(formatOption);
251 cliData.resolution = parser.value(resOption);
252 cliData.fpkText = parser.value(fpkOption);
253 cliData.server = parser.isSet(serverOption);
254 cliData.host = parser.value(hostOption);
255 cliData.portText = parser.value(portOption);
256 cliData.outputText = parser.value(outputOption);
257 cliData.logFilepathText = parser.value(logFilepathOption);
258 cliData.listParameters = parser.isSet(listOption);
259 cliData.queue = parser.isSet(queueOption);
260 cliData.voxel = parser.isSet(voxelOption);
261 cliData.voxelFormat = parser.value(voxelOption);
262 cliData.test = parser.isSet(testOption);
263 cliData.benchmark = parser.isSet(benchmarkOption);
264 cliData.touch = parser.isSet(touchOption);
265 cliData.gpu = parser.isSet(gpuOption);
266 cliData.gpuAll = parser.isSet(gpuAllOption);
267 cliData.showInputHelp = parser.isSet(helpInputOption);
268 cliData.showExampleHelp = parser.isSet(helpExamplesOption);
269 cliData.showOpenCLHelp = parser.isSet(helpOpenClOption);
270
271 systemData.statsOnCLI = parser.isSet(statsOption);
272
273 #ifdef _WIN32 /* WINDOWS */
274 systemData.useColor = false;
275 #else
276 systemData.useColor = !parser.isSet(noColorOption);
277 #endif /* WINDOWS */
278
279 if (cliData.listParameters) cliData.nogui = true;
280 if (cliData.queue) cliData.nogui = true;
281 if (cliData.test) cliData.nogui = true;
282 if (cliData.benchmark) cliData.nogui = true;
283 cliOperationalMode = modeBootOnly;
284 }
285
286 cCommandLineInterface::~cCommandLineInterface() = default;
287
ReadCLI()288 void cCommandLineInterface::ReadCLI()
289 {
290 settingsSpecified = false;
291
292 // show example help only
293 if (cliData.showExampleHelp) printExampleHelpAndExit();
294 // show input help only
295 if (cliData.showInputHelp) printInputHelpAndExit();
296 // list parameters only
297 if (cliData.listParameters) printParametersAndExit();
298
299 // log filepath if it is specified
300 if (cliData.logFilepathText != "")
301 {
302 systemData.SetLogfileName(cliData.logFilepathText);
303 }
304
305 // run test cases
306 if (cliData.test) runTestCasesAndExit();
307 // run benchmarks
308 if (cliData.benchmark) runBenchmarksAndExit();
309
310 // check netrender server / client
311 if (cliData.server)
312 handleServer();
313 else if (cliData.host != "")
314 {
315 handleClient();
316 return;
317 }
318
319 if (cliData.queue)
320 handleQueue();
321 else
322 handleArgs();
323
324 // overwriting parameters
325 if (cliData.overrideParametersText != "") handleOverrideParameters();
326
327 // specified resolution
328 if (cliData.resolution != "") handleResolution();
329
330 // specified frames per keyframe
331 if (cliData.fpkText != "") handleFpk();
332
333 // specified image file format
334 if (cliData.imageFileFormat != "")
335 handleImageFileFormat();
336 else
337 cliData.imageFileFormat = "jpg";
338
339 // silent mode
340 if (cliData.silent) systemData.silent = true;
341
342 // flight animation
343 if (cliData.flight) handleFlight();
344
345 // keyframe animation
346 if (cliData.keyframe) handleKeyframe();
347
348 // start frame of animation
349 if (cliData.startFrameText != "") handleStartFrame();
350
351 // end frame of animation
352 if (cliData.endFrameText != "") handleEndFrame();
353
354 // voxel export
355 if (cliData.voxel) handleVoxel();
356
357 // folder for animation frames
358 if (cliData.outputText != "" && cliOperationalMode == modeFlight)
359 {
360 gPar->Set("anim_flight_dir", cliData.outputText);
361 }
362 if (cliData.outputText != "" && cliOperationalMode == modeKeyframe)
363 {
364 gPar->Set("anim_keyframe_dir", cliData.outputText);
365 }
366
367 // gpu
368 if (cliData.gpu) handleGpu();
369
370 // gpuAll
371 if (cliData.gpuAll) handleGpuAll();
372
373 // show opencl help only (requires previous handling of override parameters)
374 if (cliData.showOpenCLHelp) printOpenCLHelpAndExit();
375
376 if (!settingsSpecified && cliData.nogui && cliOperationalMode != modeNetrender)
377 {
378 cErrorMessage::showMessage(
379 QObject::tr("You have to specify a settings file, for this configuration!"),
380 cErrorMessage::errorMessage);
381 parser.showHelp(cliErrorSettingsFileNotSpecified);
382 }
383
384 if (cliData.nogui && cliOperationalMode != modeKeyframe && cliOperationalMode != modeFlight
385 && cliOperationalMode != modeQueue && cliOperationalMode != modeVoxel)
386 {
387 // creating output filename if it's not specified
388 if (cliData.outputText == "")
389 {
390 cliData.outputText = gPar->Get<QString>("default_image_path") + QDir::separator();
391 cliData.outputText += QFileInfo(systemData.lastSettingsFile).completeBaseName();
392 }
393 cliOperationalMode = modeStill;
394 return;
395 }
396 }
397
ProcessCLI() const398 void cCommandLineInterface::ProcessCLI() const
399 {
400 switch (cliOperationalMode)
401 {
402 case modeNetrender:
403 {
404 gNetRender->SetClient(gPar->Get<QString>("netrender_client_remote_address"),
405 gPar->Get<int>("netrender_client_remote_port"));
406 gApplication->exec();
407 break;
408 }
409 case modeFlight:
410 {
411 gMainInterface->headless = new cHeadless(gMainInterface);
412 gMainInterface->headless->RenderFlightAnimation();
413 break;
414 }
415 case modeKeyframe:
416 {
417 gMainInterface->headless = new cHeadless(gMainInterface);
418 gMainInterface->headless->RenderKeyframeAnimation();
419 break;
420 }
421 case modeStill:
422 {
423 gMainInterface->headless = new cHeadless(gMainInterface);
424 gMainInterface->headless->RenderStillImage(cliData.outputText, cliData.imageFileFormat);
425 break;
426 }
427 case modeQueue:
428 {
429 gMainInterface->headless = new cHeadless(gMainInterface);
430 gMainInterface->headless->RenderQueue();
431 break;
432 }
433 case modeVoxel:
434 {
435 gMainInterface->headless = new cHeadless(gMainInterface);
436 gMainInterface->headless->RenderVoxel(cliData.voxelFormat);
437 break;
438 }
439 case modeBootOnly:
440 {
441 // nothing to be done
442 break;
443 }
444 }
445 }
446
printExampleHelpAndExit()447 void cCommandLineInterface::printExampleHelpAndExit()
448 {
449 QTextStream out(stdout);
450 out << cHeadless::colorize(QObject::tr("Some useful example commands:"), cHeadless::ansiRed)
451 << "\n\n";
452
453 out << cHeadless::colorize(QObject::tr("Simple render"), cHeadless::ansiBlue) << "\n";
454 out << cHeadless::colorize("mandelbulber2 -n path/to/fractal.fract", cHeadless::ansiYellow)
455 << "\n";
456 out << QObject::tr("Renders the file on the cli (no window required).") << "\n\n";
457
458 out << cHeadless::colorize(QObject::tr("Animation render"), cHeadless::ansiBlue) << "\n";
459 out << cHeadless::colorize(
460 "mandelbulber2 -n -K -s 200 -e 300 path/to/keyframe_fractal.fract", cHeadless::ansiYellow)
461 << "\n";
462 out << QObject::tr(
463 "Renders the keyframe animation of the file keyframe_fractal.fract "
464 "within frames 200 till 300.")
465 << "\n\n";
466
467 out << cHeadless::colorize(QObject::tr("Network render"), cHeadless::ansiBlue) << "\n";
468 out << cHeadless::colorize("mandelbulber2 -n --host 192.168.100.1", cHeadless::ansiYellow)
469 << cHeadless::colorize(" # (1) client", cHeadless::ansiGreen) << "\n";
470 out << cHeadless::colorize(
471 "mandelbulber2 -n --server path/to/fractal.fract", cHeadless::ansiYellow)
472 << cHeadless::colorize(" # (2) server", cHeadless::ansiGreen) << "\n";
473 out << QObject::tr(
474 "In a network you can render on multiple machines. One is a server (2) and multiple "
475 "clients (1) can connect to help rendering.\n"
476 "On each client run (1), 192.168.100.1 should be substituted with the IP address of "
477 "the server.\nOn the server run (2) with the settings required for the render and "
478 "additionally '--server'.\nThe server will start and wait a short time for the "
479 "clients to connect. Then the whole system will start rendering.")
480 << "\n\n";
481
482 out << cHeadless::colorize(QObject::tr("Voxel volume render"), cHeadless::ansiBlue) << "\n";
483 out << cHeadless::colorize(
484 "mandelbulber2 --voxel ply -n path/to/voxel_fractal.fract"
485 " -O 'voxel_custom_limit_enabled=1#voxel_limit_min=-1 -1 -1#voxel_limit_max=1 1 "
486 "1#voxel_samples_x=200'",
487 cHeadless::ansiYellow)
488 << "\n";
489 out << QObject::tr(
490 "Renders the voxel volume in the bounding box of [x(-1 - 1); y(-1 - 1); z(-1 - 1)] "
491 "with a resolution of 200x200x200 in the ply format "
492 "and saves as working folder/slices/output.ply.")
493 << "\n\n";
494
495 out << cHeadless::colorize(QObject::tr("Queue render"), cHeadless::ansiBlue) << "\n";
496 out << cHeadless::colorize(
497 "nohup mandelbulber2 -q > /tmp/queue.log 2>&1 &", cHeadless::ansiYellow)
498 << "\n";
499 out << QObject::tr(
500 "Runs the mandelbulber instance in queue mode and daemonizes it.\n"
501 "Mandelbulber runs in background and waits for jobs.\n"
502 "The output will be written to /tmp/queue.log.\n"
503 "(will not work under Windows)")
504 << "\n\n";
505
506 out.flush();
507 exit(0);
508 }
509
printInputHelpAndExit()510 void cCommandLineInterface::printInputHelpAndExit()
511 {
512 QTextStream out(stdout);
513 out << QObject::tr(
514 "Mandelbulber also accepts an arbitrary number of input files\n"
515 "These files can be of type:\n"
516 " .fract File - An ordinary fractal file\n"
517 " .fractlist File - A queue file, all entries inside the queue file will be added to the "
518 "current queue\n"
519 " Folder - if the specified argument is a folder all .fract files inside the folder will be "
520 "added to the queue\n"
521 "You can also use \"-\" as a special argument to indicate that the filename, or the whole "
522 "file contents are specified in stdin, example: cat example.fract | mandelbulber2 -\n");
523 out.flush();
524 exit(0);
525 }
526
printOpenCLHelpAndExit()527 void cCommandLineInterface::printOpenCLHelpAndExit()
528 {
529 QTextStream out(stdout);
530 #ifdef USE_OPENCL
531 gOpenCl = new cGlobalOpenCl(qApplication);
532 gOpenCl->InitPlatfromAndDevices();
533
534 out << QObject::tr(
535 "Mandelbulber can utilize OpenCL to accelerate rendering.\n"
536 "When Mandelbulber is already configured to use OpenCL, it will also run OpenCL from "
537 "commandline by default.\nThe configuration can also be done directly from this "
538 "commandline by setting the optional settings directly.\nThese can be given by the "
539 "default --override option, available opencl specific options are:")
540 << "\n";
541 out << " * opencl_enabled - " << QObject::tr("boolean to enable OpenCL") << "\n";
542 out << " * opencl_platform - "
543 << QObject::tr("platform index to use, see available platforms below") << "\n";
544 out << " * opencl_device_type - " << QObject::tr("Possible device types of the platform to use")
545 << QString("\n `- %1\n")
546 .arg(QObject::tr("possible values: [%1]")
547 .arg(gPar->GetAsOneParameter("opencl_device_type").GetEnumLookup().join(", ")));
548 out << " * opencl_device_list - "
549 << QObject::tr("right now only one device at a time is supported.") << "\n"
550 << " Specify the device hash of the device to use, see available devices below\n";
551 out << " * opencl_mode - "
552 << QObject::tr(
553 "Mode of the render engine, 'fast' has no effects, 'limited' has "
554 "basic effects, 'full' contains all shaders.")
555 << QString("\n `- %1\n")
556 .arg(QObject::tr("possible values: [%1]")
557 .arg(gPar->GetAsOneParameter("opencl_mode").GetEnumLookup().join(", ")));
558 out << " * opencl_precision - "
559 << QObject::tr(
560 "Floating point precision of Render (single is faster, but "
561 "less accurate)")
562 << QString("\n `- %1\n")
563 .arg(QObject::tr("possible values: [%1]")
564 .arg(gPar->GetAsOneParameter("opencl_precision").GetEnumLookup().join(", ")));
565 out << " * opencl_memory_limit - " << QObject::tr("Memory limit in MB") << "\n";
566
567 // print available platforms
568 out << "\n"
569 << cHeadless::colorize(QObject::tr("Available platforms are:"), cHeadless::ansiBlue) << "\n";
570 const QList<cOpenClHardware::sPlatformInformation> platforms =
571 gOpenCl->openClHardware->getPlatformsInformation();
572 for (int i = 0; i < platforms.size(); i++)
573 {
574 const cOpenClHardware::sPlatformInformation platform = platforms[i];
575 out << (gOpenCl->openClHardware->getSelectedPlatformIndex() == i ? "> " : " ");
576 out << "index: " << i << " | name: " << platform.name << "\n";
577 }
578
579 // print available devices
580 out << "\n"
581 << cHeadless::colorize(QObject::tr("Available devices for the selected platform (%1) are:")
582 .arg(gOpenCl->openClHardware->getSelectedPlatformIndex()),
583 cHeadless::ansiBlue)
584 << "\n";
585 const QList<cOpenClDevice::sDeviceInformation> devices =
586 gOpenCl->openClHardware->getDevicesInformation();
587 for (int i = 0; i < devices.size(); i++)
588 {
589 cOpenClDevice::sDeviceInformation device = devices[i];
590 if (gOpenCl->openClHardware->getSelectedDevicesIndices().contains(i))
591 out << "> ";
592 else
593 out << " ";
594 out << "index: " << i << " | hash: " << device.hash.toHex() << " | name: " << device.deviceName
595 << "\n";
596 }
597
598 out << "\n"
599 << cHeadless::colorize(QObject::tr("Example invocation:"), cHeadless::ansiBlue) << "\n";
600 out << cHeadless::colorize(
601 "mandelbulber2 -n path/to/fractal.fract"
602 " -O 'opencl_enabled=1#opencl_platform=1#opencl_device_list=14be3d'",
603 cHeadless::ansiYellow)
604 << "\n";
605 #else
606 out << "not supported, this version is not compiled with OpenCL support.";
607 #endif
608
609 out.flush();
610 exit(0);
611 }
612
printParametersAndExit()613 void cCommandLineInterface::printParametersAndExit()
614 {
615 QTextStream out(stdout);
616 InitMaterialParams(1, gPar);
617 QList<QString> listOfParameters = gPar->GetListOfParameters();
618 out << cHeadless::colorize(
619 "\nList of main parameters:\n", cHeadless::ansiYellow, cHeadless::noExplicitColor, true);
620 out << "KEY=VALUE\n";
621 for (auto ¶meterName : listOfParameters)
622 {
623 const QString defaultValue = gPar->GetDefault<QString>(parameterName);
624 out << parameterName + "=" + defaultValue + "\n";
625 }
626
627 QList<QString> listOfFractalParameters = gParFractal->at(0)->GetListOfParameters();
628 out << cHeadless::colorize(QObject::tr("\nList of fractal parameters:\n"), cHeadless::ansiYellow,
629 cHeadless::noExplicitColor, true);
630
631 for (auto ¶meterName : listOfFractalParameters)
632 {
633 const QString defaultValue = gParFractal->at(0)->GetDefault<QString>(parameterName);
634 out << parameterName + "=" + defaultValue + "\n";
635 }
636
637 out.flush();
638 exit(0);
639 }
640
runTestCasesAndExit()641 void cCommandLineInterface::runTestCasesAndExit()
642 {
643 systemData.noGui = true;
644 QStringList arguments = gApplication->arguments();
645 arguments.removeOne(QString("--test"));
646 arguments.removeOne(QString("-t"));
647
648 QStringList outputStrings({"-o", "--output", "--logfilepath"});
649 for (int i = 0; i < outputStrings.size(); i++)
650 {
651 const int index = arguments.indexOf(outputStrings[i]);
652 if (index >= 0)
653 {
654 arguments.removeAt(index);
655 arguments.removeAt(index);
656 }
657 }
658
659 int status = 0;
660 Test test(Test::simpleTestMode);
661 status |= QTest::qExec(&test, arguments);
662 exit(status);
663 }
664
runBenchmarksAndExit()665 void cCommandLineInterface::runBenchmarksAndExit()
666 {
667 // Set 24 hour test timeout
668 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray("86400000"));
669
670 systemData.noGui = true;
671 QStringList arguments = gApplication->arguments();
672 arguments.removeOne(QString("--benchmark"));
673 arguments.removeOne(QString("-b"));
674 int difficulty = 10;
675 QString exampleOutputPath = "";
676
677 if (args.size() > 0)
678 {
679 if (args[0] != "")
680 {
681 bool checkParse = false;
682 const int difficultyTemp = args[0].toInt(&checkParse);
683 if (checkParse && difficultyTemp > 0)
684 {
685 difficulty = difficultyTemp;
686 }
687 arguments.removeOne(args[0]);
688 }
689 }
690
691 if (cliData.outputText != "")
692 {
693 // Invalid output path specified on CLI
694 exampleOutputPath = cliData.outputText;
695 if (!QDir(exampleOutputPath).exists())
696 {
697 cErrorMessage::showMessage(
698 QObject::tr("Example output path invalid\n"), cErrorMessage::errorMessage);
699 parser.showHelp(cliErrorBenchmarkOutputFolderInvalid);
700 }
701
702 // Add Timestamp to exampleOutputPath directory path
703 time_t rawTime;
704 char timeBuffer[80];
705 time(&rawTime);
706 struct tm *timeInfo = localtime(&rawTime);
707 strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d-%H-%M-%S", timeInfo);
708 QString timestamp(timeBuffer);
709 exampleOutputPath += "/" + timestamp;
710
711 // Create the timestamped folder for rendering the examples
712 if (!QDir(exampleOutputPath).exists())
713 {
714 CreateFolder(exampleOutputPath);
715 }
716
717 // Create the text log in exampleOutputPath
718 if (cliData.logFilepathText == "")
719 {
720 systemData.SetLogfileName(exampleOutputPath + "/" + "_bulb_log_" + timestamp + ".txt");
721 }
722 }
723
724 QStringList outputStrings({"-o", "--output", "--logfilepath"});
725 for (int i = 0; i < outputStrings.size(); i++)
726 {
727 const int index = arguments.indexOf(outputStrings[i]);
728 if (index >= 0)
729 {
730 arguments.removeAt(index);
731 arguments.removeAt(index);
732 }
733 }
734
735 int status = 0;
736 WriteLogCout(QString("Starting benchmark with difficulty [%1] and example output path [%2]")
737 .arg(difficulty)
738 .arg(exampleOutputPath)
739 + "\n",
740 1);
741
742 #ifdef USE_OPENCL
743 if (gPar->Get<bool>("opencl_enabled"))
744 {
745 WriteLogCout(QString("opencl enabled: GPU Benchmark\n"), 1);
746 }
747 else
748 {
749 WriteLogCout(QString("opencl disabled: CPU benchmark\n"), 1);
750 }
751 #else
752 WriteLogCout(QString("this version is not compiled with OpenCL support.\n"), 1);
753 #endif
754 Test test(Test::benchmarkTestMode, difficulty, exampleOutputPath);
755 status |= QTest::qExec(&test, arguments);
756 exit(status);
757 }
758
handleServer()759 void cCommandLineInterface::handleServer()
760 {
761 QTextStream out(stdout);
762 bool checkParse = true;
763 if (cliData.portText != "")
764 {
765 const int port = cliData.portText.toInt(&checkParse);
766 if (!checkParse || port <= 0)
767 {
768 cErrorMessage::showMessage(
769 QObject::tr("Specified server port is invalid\n"), cErrorMessage::errorMessage);
770 parser.showHelp(cliErrorServerInvalidPort);
771 }
772 gPar->Set("netrender_server_local_port", port);
773 }
774 cliData.nogui = true;
775 systemData.noGui = true;
776 gNetRender->SetServer(gPar->Get<int>("netrender_server_local_port"));
777 QElapsedTimer timer;
778 timer.start();
779
780 if (systemData.noGui)
781 {
782 out << QObject::tr("NetRender - Waiting for clients\n");
783 out.flush();
784 }
785
786 while (timer.elapsed() < 5000)
787 {
788 gApplication->processEvents();
789 }
790 }
791
handleClient()792 void cCommandLineInterface::handleClient()
793 {
794 bool checkParse = true;
795 gPar->Set("netrender_client_remote_address", cliData.host);
796 if (cliData.portText != "")
797 {
798 const int port = cliData.portText.toInt(&checkParse);
799 if (!checkParse || port <= 0)
800 {
801 cErrorMessage::showMessage(
802 QObject::tr("Specified client port is invalid\n"), cErrorMessage::errorMessage);
803 parser.showHelp(cliErrorClientInvalidPort);
804 }
805 gPar->Set("netrender_client_remote_port", port);
806 }
807 cliData.nogui = true;
808 systemData.noGui = true;
809 cliOperationalMode = modeNetrender;
810 }
811
handleQueue()812 void cCommandLineInterface::handleQueue()
813 {
814 cliOperationalMode = modeQueue;
815 settingsSpecified = true;
816 cliData.nogui = true;
817 systemData.noGui = true;
818 try
819 {
820 gQueue = new cQueue(gMainInterface, systemDirectories.GetQueueFractlistFile(),
821 systemDirectories.GetQueueFolder(), gMainInterface);
822 }
823 catch (QString &ex)
824 {
825 cErrorMessage::showMessage(
826 QObject::tr("Cannot init queue: ") + ex, cErrorMessage::errorMessage);
827 parser.showHelp(cliErrorQueueInit);
828 }
829 }
830
handleArgs()831 void cCommandLineInterface::handleArgs()
832 {
833 if (args.size() > 0)
834 {
835 // file specified -> load it
836 if (args.size() == 1 && QFileInfo(args[0]).suffix() != QString("fractlist")
837 && !QDir(args[0]).exists())
838 {
839 QString filename = args[0];
840 cSettings parSettings(cSettings::formatFullText);
841 if (!QFile::exists(filename))
842 {
843 // try to find settings in default settings path
844 filename = systemDirectories.GetSettingsFolder() + QDir::separator() + filename;
845 }
846 if (QFile::exists(filename))
847 {
848 // hint: do not use auto loading of v1 files in batch mode
849 parSettings.LoadFromFile(filename);
850 parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
851 settingsSpecified = true;
852 systemData.lastSettingsFile = filename;
853 systemData.settingsLoadedFromCLI = true;
854 if (cliData.touch)
855 {
856 parSettings.CreateText(gPar, gParFractal, gAnimFrames, gKeyframes);
857 parSettings.SaveToFile(filename);
858 WriteLogString("cCommandLineInterface::handleArgs(): touched file", filename, 3);
859 exit(0);
860 }
861 }
862 else if (parSettings.LoadFromString(args[0]))
863 {
864 // the whole settings file is specified as an argument from stdin
865 parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
866 settingsSpecified = true;
867 systemData.lastSettingsFile = "from stdin";
868 systemData.settingsLoadedFromCLI = true;
869 }
870 else
871 {
872 cErrorMessage::showMessage(QObject::tr("Cannot load file!\n"), cErrorMessage::errorMessage);
873 qCritical() << "\nSetting file " << filename << " not found\n";
874 parser.showHelp(cliErrorLoadSettingsFile);
875 }
876 }
877 else
878 {
879 // queue render
880 cliOperationalMode = modeQueue;
881 cliData.nogui = true;
882 systemData.noGui = true;
883 try
884 {
885 gQueue = new cQueue(gMainInterface, systemDirectories.GetQueueFractlistFile(),
886 systemDirectories.GetQueueFolder(), gMainInterface);
887 }
888 catch (QString &ex)
889 {
890 cErrorMessage::showMessage(
891 QObject::tr("Cannot init queue: ") + ex, cErrorMessage::errorMessage);
892 parser.showHelp(cliErrorQueueInit);
893 }
894 for (int i = 0; i < args.size(); i++)
895 {
896 const QString filename = args[i];
897 if (QDir(args[i]).exists())
898 {
899 // specified input is a folder, load all fractal files contained in this folder
900 gQueue->AppendFolder(filename);
901 settingsSpecified = true;
902 }
903 else if (QFileInfo(filename).suffix() == QString("fractlist"))
904 {
905 // specified input is a queue list file, append all entries to the current queue
906 gQueue->AppendList(filename);
907 settingsSpecified = true;
908 }
909 else
910 {
911 // specified input can only be an ordinary fract file, try to append to queuelist
912 gQueue->Append(filename);
913 settingsSpecified = true;
914 }
915 }
916 }
917 }
918 }
919
handleOverrideParameters() const920 void cCommandLineInterface::handleOverrideParameters() const
921 {
922 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
923 QStringList overrideParameters =
924 cliData.overrideParametersText.split("#", QString::SkipEmptyParts);
925 #else
926 QStringList overrideParameters = cliData.overrideParametersText.split("#", Qt::SkipEmptyParts);
927 #endif
928
929 for (int i = 0; i < overrideParameters.size(); i++)
930 {
931 int fractalIndex = -1;
932 QRegularExpression reType("^fractal([0-9]+)_(.*)$");
933 QRegularExpressionMatch matchType = reType.match(overrideParameters[i]);
934 if (matchType.hasMatch())
935 {
936 fractalIndex = matchType.captured(1).toInt() - 1;
937 overrideParameters[i] = matchType.captured(2);
938 }
939 QStringList overrideParameter = overrideParameters[i].split(QRegExp("\\="));
940 if (overrideParameter.size() == 2)
941 {
942 if (fractalIndex >= 0 && fractalIndex < NUMBER_OF_FRACTALS)
943 {
944 gParFractal->at(fractalIndex)
945 ->Set(overrideParameter[0].trimmed(), overrideParameter[1].trimmed());
946 }
947 else
948 {
949 gPar->Set(overrideParameter[0].trimmed(), overrideParameter[1].trimmed());
950 }
951 }
952 }
953 }
954
handleResolution()955 void cCommandLineInterface::handleResolution()
956 {
957 bool checkParse = true;
958 QStringList resolutionParameters = cliData.resolution.split(QRegExp("x"));
959 if (resolutionParameters.size() == 2)
960 {
961 const int xRes = resolutionParameters[0].toInt(&checkParse);
962 const int yRes = resolutionParameters[1].toInt(&checkParse);
963 if (!checkParse || xRes <= 0 || yRes <= 0)
964 {
965 cErrorMessage::showMessage(QObject::tr("Specified resolution not valid\n"
966 "both dimensions need to be > 0"),
967 cErrorMessage::errorMessage);
968 parser.showHelp(cliErrorResolutionInvalid);
969 }
970 gPar->Set("image_width", xRes);
971 gPar->Set("image_height", yRes);
972 }
973 else
974 {
975 cErrorMessage::showMessage(QObject::tr("Specified resolution not valid\n"
976 "resolution has to be in the form WIDTHxHEIGHT"),
977 cErrorMessage::errorMessage);
978 parser.showHelp(cliErrorResolutionInvalid);
979 }
980 }
981
handleFpk()982 void cCommandLineInterface::handleFpk()
983 {
984 bool checkParse = true;
985 const int fpk = cliData.fpkText.toInt(&checkParse);
986 if (!checkParse || fpk <= 0)
987 {
988 cErrorMessage::showMessage(QObject::tr("Specified frames per key not valid\n"
989 "need to be > 0"),
990 cErrorMessage::errorMessage);
991 parser.showHelp(cliErrorFPKInvalid);
992 }
993 gPar->Set("frames_per_keyframe", fpk);
994 }
995
handleImageFileFormat()996 void cCommandLineInterface::handleImageFileFormat()
997 {
998 QStringList allowedImageFileFormat({"jpg", "png", "png16", "png16alpha", "exr", "tiff"});
999 if (!allowedImageFileFormat.contains(cliData.imageFileFormat))
1000 {
1001 cErrorMessage::showMessage(QObject::tr("Specified imageFileFormat is not valid\n"
1002 "allowed formats are: ")
1003 + allowedImageFileFormat.join(", "),
1004 cErrorMessage::errorMessage);
1005 parser.showHelp(cliErrorImageFileFormatInvalid);
1006 }
1007 else
1008 {
1009 const ImageFileSave::enumImageFileType fileType =
1010 ImageFileSave::ImageFileType(cliData.imageFileFormat);
1011 gPar->Set("keyframe_animation_image_type", int(fileType));
1012 gPar->Set("flight_animation_image_type", int(fileType));
1013 }
1014 }
1015
handleFlight()1016 void cCommandLineInterface::handleFlight()
1017 {
1018 if (gAnimFrames->GetNumberOfFrames() > 0)
1019 {
1020 cliOperationalMode = modeFlight;
1021 cliData.nogui = true;
1022 systemData.noGui = true;
1023 }
1024 else
1025 {
1026 cErrorMessage::showMessage(
1027 QObject::tr("There are no flight animation frames in specified settings file"),
1028 cErrorMessage::errorMessage);
1029 parser.showHelp(cliErrorFlightNoFrames);
1030 }
1031 }
1032
handleKeyframe()1033 void cCommandLineInterface::handleKeyframe()
1034 {
1035 if (cliOperationalMode == modeFlight)
1036 {
1037 cErrorMessage::showMessage(
1038 QObject::tr("You cannot render keyframe animation at the same time as flight animation"),
1039 cErrorMessage::errorMessage);
1040 }
1041 else
1042 {
1043 if (gKeyframes->GetNumberOfFrames() > 0)
1044 {
1045 cliOperationalMode = modeKeyframe;
1046 cliData.nogui = true;
1047 systemData.noGui = true;
1048 }
1049 else
1050 {
1051 cErrorMessage::showMessage(QObject::tr("There are no keyframes in specified settings file"),
1052 cErrorMessage::errorMessage);
1053 parser.showHelp(cliErrorKeyframeNoFrames);
1054 }
1055 }
1056 }
1057
handleStartFrame()1058 void cCommandLineInterface::handleStartFrame()
1059 {
1060 bool checkParse = true;
1061 const int startFrame = cliData.startFrameText.toInt(&checkParse);
1062 if (cliOperationalMode == modeFlight)
1063 {
1064 if (startFrame <= gAnimFrames->GetNumberOfFrames())
1065 {
1066 gPar->Set("flight_first_to_render", startFrame);
1067 }
1068 else
1069 {
1070 cErrorMessage::showMessage(
1071 QObject::tr("Animation has only %1 frames").arg(gAnimFrames->GetNumberOfFrames()),
1072 cErrorMessage::errorMessage);
1073 parser.showHelp(cliErrorFlightStartFrameOutOfRange);
1074 }
1075 }
1076
1077 if (cliOperationalMode == modeKeyframe)
1078 {
1079 int numberOfFrames =
1080 (gKeyframes->GetNumberOfFrames() - 1) * gPar->Get<int>("frames_per_keyframe");
1081 if (numberOfFrames < 0) numberOfFrames = 0;
1082
1083 if (startFrame <= numberOfFrames)
1084 {
1085 gPar->Set("keyframe_first_to_render", startFrame);
1086 }
1087 else
1088 {
1089 cErrorMessage::showMessage(QObject::tr("Animation has only %1 frames").arg(numberOfFrames),
1090 cErrorMessage::errorMessage);
1091 parser.showHelp(cliErrorKeyframeStartFrameOutOfRange);
1092 }
1093 }
1094 }
1095
handleEndFrame()1096 void cCommandLineInterface::handleEndFrame()
1097 {
1098 bool checkParse = true;
1099 const int endFrame = cliData.endFrameText.toInt(&checkParse);
1100 if (cliOperationalMode == modeFlight)
1101 {
1102 if (endFrame <= gAnimFrames->GetNumberOfFrames())
1103 {
1104 if (endFrame > gPar->Get<int>("flight_first_to_render"))
1105 {
1106 gPar->Set("flight_last_to_render", endFrame);
1107 }
1108 else
1109 {
1110 cErrorMessage::showMessage(
1111 QObject::tr("End frame has to be greater than start frame which is %1")
1112 .arg(gPar->Get<int>("flight_first_to_render")),
1113 cErrorMessage::errorMessage);
1114 parser.showHelp(cliErrorFlightEndFrameSmallerStartFrame);
1115 }
1116 }
1117 else
1118 {
1119 cErrorMessage::showMessage(
1120 QObject::tr("Animation has only %1 frames").arg(gAnimFrames->GetNumberOfFrames()),
1121 cErrorMessage::errorMessage);
1122 parser.showHelp(cliErrorFlightEndFrameOutOfRange);
1123 }
1124 }
1125
1126 if (cliOperationalMode == modeKeyframe)
1127 {
1128 int numberOfFrames =
1129 (gKeyframes->GetNumberOfFrames() - 1) * gPar->Get<int>("frames_per_keyframe");
1130 if (numberOfFrames < 0) numberOfFrames = 0;
1131
1132 if (endFrame <= numberOfFrames)
1133 {
1134 if (endFrame > gPar->Get<int>("keyframe_first_to_render"))
1135 {
1136 gPar->Set("keyframe_last_to_render", endFrame);
1137 }
1138 else
1139 {
1140 cErrorMessage::showMessage(
1141 QObject::tr("End frame has to be greater than start frame which is %1")
1142 .arg(gPar->Get<int>("keyframe_first_to_render")),
1143 cErrorMessage::errorMessage);
1144 parser.showHelp(cliErrorKeyframeEndFrameSmallerStartFrame);
1145 }
1146 }
1147 else
1148 {
1149 cErrorMessage::showMessage(QObject::tr("Animation has only %1 frames").arg(numberOfFrames),
1150 cErrorMessage::errorMessage);
1151 parser.showHelp(cliErrorKeyframeEndFrameOutOfRange);
1152 }
1153 }
1154 }
1155
handleVoxel()1156 void cCommandLineInterface::handleVoxel()
1157 {
1158 QStringList allowedVoxelFormat({"ply", "slice"});
1159 WriteLogString(
1160 "CommandLineInterface::handleVoxel(): cliData.voxelFormat", cliData.voxelFormat, 3);
1161 if (!allowedVoxelFormat.contains(cliData.voxelFormat))
1162 {
1163 cErrorMessage::showMessage(QObject::tr("Specified voxel format is not valid\n"
1164 "allowed formats are: ")
1165 + allowedVoxelFormat.join(", "),
1166 cErrorMessage::errorMessage);
1167 parser.showHelp(cliErrorVoxelOutputFormatInvalid);
1168 }
1169
1170 const QString folderString = gPar->Get<QString>("voxel_image_path");
1171 QDir folder(folderString);
1172 if (!folder.exists())
1173 {
1174 cErrorMessage::showMessage(
1175 QObject::tr("Cannot start voxel export. Specified folder (%1) does not exist.")
1176 .arg(folderString),
1177 cErrorMessage::errorMessage);
1178 parser.showHelp(cliErrorVoxelOutputFolderDoesNotExists);
1179 }
1180 cliOperationalMode = modeVoxel;
1181 cliData.nogui = true;
1182 systemData.noGui = true;
1183 }
1184
handleGpu()1185 void cCommandLineInterface::handleGpu()
1186 {
1187 #ifdef USE_OPENCL
1188 QTextStream out(stdout);
1189 gOpenCl->Reset();
1190 gOpenCl->InitPlatfromAndDevices();
1191
1192 gPar->Set("opencl_enabled", true);
1193
1194 // print available platforms
1195 const QList<cOpenClHardware::sPlatformInformation> platforms =
1196 gOpenCl->openClHardware->getPlatformsInformation();
1197 if (platforms.size() == 0)
1198 {
1199 cErrorMessage::showMessage(
1200 QObject::tr("No opencl platforms found"), cErrorMessage::errorMessage);
1201 parser.showHelp(cliErrorOpenClNoPlatform);
1202 }
1203 gPar->Set("opencl_platform", 0);
1204
1205 const QList<cOpenClDevice::sDeviceInformation> devices =
1206 gOpenCl->openClHardware->getDevicesInformation();
1207 if (devices.size() == 0)
1208 {
1209 cErrorMessage::showMessage(QObject::tr("No opencl devices found"), cErrorMessage::errorMessage);
1210 parser.showHelp(cliErrorOpenClNoDevice);
1211 }
1212 else
1213 {
1214 gPar->Set("opencl_device_list", QString(devices[0].hash.toHex()));
1215 out << "Use " << devices[0].deviceName << " for OpenCL rendering\n";
1216 }
1217 #else
1218 cErrorMessage::showMessage(QObject::tr("Not compiled for opencl"), cErrorMessage::errorMessage);
1219 parser.showHelp(cliErrorOpenClNotCompiled);
1220 #endif
1221 }
1222
handleGpuAll()1223 void cCommandLineInterface::handleGpuAll()
1224 {
1225 #ifdef USE_OPENCL
1226 QTextStream out(stdout);
1227 gOpenCl->Reset();
1228 gOpenCl->InitPlatfromAndDevices();
1229
1230 gPar->Set("opencl_enabled", true);
1231
1232 // print available platforms
1233 const QList<cOpenClHardware::sPlatformInformation> platforms =
1234 gOpenCl->openClHardware->getPlatformsInformation();
1235 if (platforms.size() == 0)
1236 {
1237 cErrorMessage::showMessage(
1238 QObject::tr("No opencl platforms found"), cErrorMessage::errorMessage);
1239 parser.showHelp(cliErrorOpenClNoPlatform);
1240 }
1241 gPar->Set("opencl_platform", 0);
1242
1243 const QList<cOpenClDevice::sDeviceInformation> devices =
1244 gOpenCl->openClHardware->getDevicesInformation();
1245 if (devices.size() == 0)
1246 {
1247 cErrorMessage::showMessage(QObject::tr("No opencl devices found"), cErrorMessage::errorMessage);
1248 parser.showHelp(cliErrorOpenClNoDevice);
1249 }
1250 else
1251 {
1252 QString listHashCodes;
1253 for (int i = 0; i < devices.size(); i++)
1254 {
1255 if (i > 0) listHashCodes += "|";
1256 listHashCodes += QString(devices[i].hash.toHex());
1257 out << "Use " << devices[i].deviceName << " for OpenCL rendering\n";
1258 }
1259 gPar->Set("opencl_device_list", listHashCodes);
1260 }
1261 #else
1262 cErrorMessage::showMessage(QObject::tr("Not compiled for opencl"), cErrorMessage::errorMessage);
1263 parser.showHelp(cliErrorOpenClNotCompiled);
1264 #endif
1265 }
1266