Files
test2/intern/cycles/app/cycles_standalone.cpp
Brecht Van Lommel 0803119725 Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.

Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.

Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles

Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)

For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.

Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-21 14:55:54 +02:00

567 lines
15 KiB
C++

/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "device/device.h"
#include "render/buffers.h"
#include "render/camera.h"
#include "render/integrator.h"
#include "render/scene.h"
#include "render/session.h"
#include "util/util_args.h"
#include "util/util_foreach.h"
#include "util/util_function.h"
#include "util/util_image.h"
#include "util/util_logging.h"
#include "util/util_path.h"
#include "util/util_progress.h"
#include "util/util_string.h"
#include "util/util_time.h"
#include "util/util_transform.h"
#include "util/util_unique_ptr.h"
#include "util/util_version.h"
#ifdef WITH_CYCLES_STANDALONE_GUI
# include "util/util_view.h"
#endif
#include "app/cycles_xml.h"
CCL_NAMESPACE_BEGIN
struct Options {
Session *session;
Scene *scene;
string filepath;
int width, height;
SceneParams scene_params;
SessionParams session_params;
bool quiet;
bool show_help, interactive, pause;
string output_path;
} options;
static void session_print(const string &str)
{
/* print with carriage return to overwrite previous */
printf("\r%s", str.c_str());
/* add spaces to overwrite longer previous print */
static int maxlen = 0;
int len = str.size();
maxlen = max(len, maxlen);
for (int i = len; i < maxlen; i++)
printf(" ");
/* flush because we don't write an end of line */
fflush(stdout);
}
static void session_print_status()
{
string status, substatus;
/* get status */
float progress = options.session->progress.get_progress();
options.session->progress.get_status(status, substatus);
if (substatus != "")
status += ": " + substatus;
/* print status */
status = string_printf("Progress %05.2f %s", (double)progress * 100, status.c_str());
session_print(status);
}
static bool write_render(const uchar *pixels, int w, int h, int channels)
{
string msg = string_printf("Writing image %s", options.output_path.c_str());
session_print(msg);
unique_ptr<ImageOutput> out = unique_ptr<ImageOutput>(ImageOutput::create(options.output_path));
if (!out) {
return false;
}
ImageSpec spec(w, h, channels, TypeDesc::UINT8);
if (!out->open(options.output_path, spec)) {
return false;
}
/* conversion for different top/bottom convention */
out->write_image(
TypeDesc::UINT8, pixels + (h - 1) * w * channels, AutoStride, -w * channels, AutoStride);
out->close();
return true;
}
static BufferParams &session_buffer_params()
{
static BufferParams buffer_params;
buffer_params.width = options.width;
buffer_params.height = options.height;
buffer_params.full_width = options.width;
buffer_params.full_height = options.height;
return buffer_params;
}
static void scene_init()
{
options.scene = options.session->scene;
/* Read XML */
xml_read_file(options.scene, options.filepath.c_str());
/* Camera width/height override? */
if (!(options.width == 0 || options.height == 0)) {
options.scene->camera->set_full_width(options.width);
options.scene->camera->set_full_height(options.height);
}
else {
options.width = options.scene->camera->get_full_width();
options.height = options.scene->camera->get_full_height();
}
/* Calculate Viewplane */
options.scene->camera->compute_auto_viewplane();
}
static void session_init()
{
options.session_params.write_render_cb = write_render;
options.session = new Session(options.session_params, options.scene_params);
if (options.session_params.background && !options.quiet)
options.session->progress.set_update_callback(function_bind(&session_print_status));
#ifdef WITH_CYCLES_STANDALONE_GUI
else
options.session->progress.set_update_callback(function_bind(&view_redraw));
#endif
/* load scene */
scene_init();
options.session->reset(session_buffer_params(), options.session_params.samples);
options.session->start();
}
static void session_exit()
{
if (options.session) {
delete options.session;
options.session = NULL;
}
if (options.session_params.background && !options.quiet) {
session_print("Finished Rendering.");
printf("\n");
}
}
#ifdef WITH_CYCLES_STANDALONE_GUI
static void display_info(Progress &progress)
{
static double latency = 0.0;
static double last = 0;
double elapsed = time_dt();
string str, interactive;
latency = (elapsed - last);
last = elapsed;
double total_time, sample_time;
string status, substatus;
progress.get_time(total_time, sample_time);
progress.get_status(status, substatus);
float progress_val = progress.get_progress();
if (substatus != "")
status += ": " + substatus;
interactive = options.interactive ? "On" : "Off";
str = string_printf(
"%s"
" Time: %.2f"
" Latency: %.4f"
" Progress: %05.2f"
" Average: %.4f"
" Interactive: %s",
status.c_str(),
total_time,
latency,
(double)progress_val * 100,
sample_time,
interactive.c_str());
view_display_info(str.c_str());
if (options.show_help)
view_display_help();
}
static void display()
{
static DeviceDrawParams draw_params = DeviceDrawParams();
options.session->draw(session_buffer_params(), draw_params);
display_info(options.session->progress);
}
static void motion(int x, int y, int button)
{
if (options.interactive) {
Transform matrix = options.session->scene->camera->get_matrix();
/* Translate */
if (button == 0) {
float3 translate = make_float3(x * 0.01f, -(y * 0.01f), 0.0f);
matrix = matrix * transform_translate(translate);
}
/* Rotate */
else if (button == 2) {
float4 r1 = make_float4((float)x * 0.1f, 0.0f, 1.0f, 0.0f);
matrix = matrix * transform_rotate(DEG2RADF(r1.x), make_float3(r1.y, r1.z, r1.w));
float4 r2 = make_float4(y * 0.1f, 1.0f, 0.0f, 0.0f);
matrix = matrix * transform_rotate(DEG2RADF(r2.x), make_float3(r2.y, r2.z, r2.w));
}
/* Update and Reset */
options.session->scene->camera->set_matrix(matrix);
options.session->scene->camera->need_flags_update = true;
options.session->scene->camera->need_device_update = true;
options.session->reset(session_buffer_params(), options.session_params.samples);
}
}
static void resize(int width, int height)
{
options.width = width;
options.height = height;
if (options.session) {
/* Update camera */
options.session->scene->camera->set_full_width(options.width);
options.session->scene->camera->set_full_height(options.height);
options.session->scene->camera->compute_auto_viewplane();
options.session->scene->camera->need_flags_update = true;
options.session->scene->camera->need_device_update = true;
options.session->reset(session_buffer_params(), options.session_params.samples);
}
}
static void keyboard(unsigned char key)
{
/* Toggle help */
if (key == 'h')
options.show_help = !(options.show_help);
/* Reset */
else if (key == 'r')
options.session->reset(session_buffer_params(), options.session_params.samples);
/* Cancel */
else if (key == 27) // escape
options.session->progress.set_cancel("Canceled");
/* Pause */
else if (key == 'p') {
options.pause = !options.pause;
options.session->set_pause(options.pause);
}
/* Interactive Mode */
else if (key == 'i')
options.interactive = !(options.interactive);
/* Navigation */
else if (options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) {
Transform matrix = options.session->scene->camera->get_matrix();
float3 translate;
if (key == 'w')
translate = make_float3(0.0f, 0.0f, 0.1f);
else if (key == 's')
translate = make_float3(0.0f, 0.0f, -0.1f);
else if (key == 'a')
translate = make_float3(-0.1f, 0.0f, 0.0f);
else if (key == 'd')
translate = make_float3(0.1f, 0.0f, 0.0f);
matrix = matrix * transform_translate(translate);
/* Update and Reset */
options.session->scene->camera->set_matrix(matrix);
options.session->scene->camera->need_flags_update = true;
options.session->scene->camera->need_device_update = true;
options.session->reset(session_buffer_params(), options.session_params.samples);
}
/* Set Max Bounces */
else if (options.interactive && (key == '0' || key == '1' || key == '2' || key == '3')) {
int bounce;
switch (key) {
case '0':
bounce = 0;
break;
case '1':
bounce = 1;
break;
case '2':
bounce = 2;
break;
case '3':
bounce = 3;
break;
default:
bounce = 0;
break;
}
options.session->scene->integrator->set_max_bounce(bounce);
options.session->reset(session_buffer_params(), options.session_params.samples);
}
}
#endif
static int files_parse(int argc, const char *argv[])
{
if (argc > 0)
options.filepath = argv[0];
return 0;
}
static void options_parse(int argc, const char **argv)
{
options.width = 0;
options.height = 0;
options.filepath = "";
options.session = NULL;
options.quiet = false;
/* device names */
string device_names = "";
string devicename = "CPU";
bool list = false;
/* List devices for which support is compiled in. */
vector<DeviceType> types = Device::available_types();
foreach (DeviceType type, types) {
if (device_names != "")
device_names += ", ";
device_names += Device::string_from_type(type);
}
/* shading system */
string ssname = "svm";
/* parse options */
ArgParse ap;
bool help = false, debug = false, version = false;
int verbosity = 1;
ap.options("Usage: cycles [options] file.xml",
"%*",
files_parse,
"",
"--device %s",
&devicename,
("Devices to use: " + device_names).c_str(),
#ifdef WITH_OSL
"--shadingsys %s",
&ssname,
"Shading system to use: svm, osl",
#endif
"--background",
&options.session_params.background,
"Render in background, without user interface",
"--quiet",
&options.quiet,
"In background mode, don't print progress messages",
"--samples %d",
&options.session_params.samples,
"Number of samples to render",
"--output %s",
&options.output_path,
"File path to write output image",
"--threads %d",
&options.session_params.threads,
"CPU Rendering Threads",
"--width %d",
&options.width,
"Window width in pixel",
"--height %d",
&options.height,
"Window height in pixel",
"--tile-width %d",
&options.session_params.tile_size.x,
"Tile width in pixels",
"--tile-height %d",
&options.session_params.tile_size.y,
"Tile height in pixels",
"--list-devices",
&list,
"List information about all available devices",
#ifdef WITH_CYCLES_LOGGING
"--debug",
&debug,
"Enable debug logging",
"--verbose %d",
&verbosity,
"Set verbosity of the logger",
#endif
"--help",
&help,
"Print help message",
"--version",
&version,
"Print version number",
NULL);
if (ap.parse(argc, argv) < 0) {
fprintf(stderr, "%s\n", ap.geterror().c_str());
ap.usage();
exit(EXIT_FAILURE);
}
if (debug) {
util_logging_start();
util_logging_verbosity_set(verbosity);
}
if (list) {
vector<DeviceInfo> devices = Device::available_devices();
printf("Devices:\n");
foreach (DeviceInfo &info, devices) {
printf(" %-10s%s%s\n",
Device::string_from_type(info.type).c_str(),
info.description.c_str(),
(info.display_device) ? " (display)" : "");
}
exit(EXIT_SUCCESS);
}
else if (version) {
printf("%s\n", CYCLES_VERSION_STRING);
exit(EXIT_SUCCESS);
}
else if (help || options.filepath == "") {
ap.usage();
exit(EXIT_SUCCESS);
}
if (ssname == "osl")
options.scene_params.shadingsystem = SHADINGSYSTEM_OSL;
else if (ssname == "svm")
options.scene_params.shadingsystem = SHADINGSYSTEM_SVM;
#ifndef WITH_CYCLES_STANDALONE_GUI
options.session_params.background = true;
#endif
/* Use progressive rendering */
options.session_params.progressive = true;
/* find matching device */
DeviceType device_type = Device::type_from_string(devicename.c_str());
vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK(device_type));
bool device_available = false;
if (!devices.empty()) {
options.session_params.device = devices.front();
device_available = true;
}
/* handle invalid configurations */
if (options.session_params.device.type == DEVICE_NONE || !device_available) {
fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
exit(EXIT_FAILURE);
}
#ifdef WITH_OSL
else if (!(ssname == "osl" || ssname == "svm")) {
fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
exit(EXIT_FAILURE);
}
else if (options.scene_params.shadingsystem == SHADINGSYSTEM_OSL &&
options.session_params.device.type != DEVICE_CPU) {
fprintf(stderr, "OSL shading system only works with CPU device\n");
exit(EXIT_FAILURE);
}
#endif
else if (options.session_params.samples < 0) {
fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
exit(EXIT_FAILURE);
}
else if (options.filepath == "") {
fprintf(stderr, "No file path specified\n");
exit(EXIT_FAILURE);
}
}
CCL_NAMESPACE_END
using namespace ccl;
int main(int argc, const char **argv)
{
util_logging_init(argv[0]);
path_init();
options_parse(argc, argv);
#ifdef WITH_CYCLES_STANDALONE_GUI
if (options.session_params.background) {
#endif
session_init();
options.session->wait();
session_exit();
#ifdef WITH_CYCLES_STANDALONE_GUI
}
else {
string title = "Cycles: " + path_filename(options.filepath);
/* init/exit are callback so they run while GL is initialized */
view_main_loop(title.c_str(),
options.width,
options.height,
session_init,
session_exit,
resize,
display,
keyboard,
motion);
}
#endif
return 0;
}