Cycles: refactor API for render output
* Add OutputDriver, replacing function callbacks in Session. * Add PathTraceTile, replacing tile access methods in Session. * Add more detailed comments about how this driver should be implemented. * Add OIIOOutputDriver for Cycles standalone to output an image. Differential Revision: https://developer.blender.org/D12627
This commit is contained in:
parent
a754e35198
commit
1a134c4c30
@ -64,6 +64,8 @@ if(WITH_CYCLES_STANDALONE)
|
||||
cycles_standalone.cpp
|
||||
cycles_xml.cpp
|
||||
cycles_xml.h
|
||||
oiio_output_driver.cpp
|
||||
oiio_output_driver.h
|
||||
)
|
||||
add_executable(cycles ${SRC} ${INC} ${INC_SYS})
|
||||
unset(SRC)
|
||||
@ -73,7 +75,7 @@ if(WITH_CYCLES_STANDALONE)
|
||||
|
||||
if(APPLE)
|
||||
if(WITH_OPENCOLORIO)
|
||||
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit")
|
||||
set_property(TARGET cycles APPEND_STRING PROPERTY LINK_FLAGS " -framework IOKit -framework Carbon")
|
||||
endif()
|
||||
if(WITH_OPENIMAGEDENOISE AND "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64")
|
||||
# OpenImageDenoise uses BNNS from the Accelerate framework.
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include "util/util_unique_ptr.h"
|
||||
#include "util/util_version.h"
|
||||
|
||||
#include "app/cycles_xml.h"
|
||||
#include "app/oiio_output_driver.h"
|
||||
|
||||
#ifdef WITH_CYCLES_STANDALONE_GUI
|
||||
# include "util/util_view.h"
|
||||
#endif
|
||||
@ -54,6 +57,7 @@ struct Options {
|
||||
bool quiet;
|
||||
bool show_help, interactive, pause;
|
||||
string output_filepath;
|
||||
string output_pass;
|
||||
} options;
|
||||
|
||||
static void session_print(const string &str)
|
||||
@ -89,30 +93,6 @@ static void session_print_status()
|
||||
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;
|
||||
@ -147,9 +127,14 @@ static void scene_init()
|
||||
|
||||
static void session_init()
|
||||
{
|
||||
options.session_params.write_render_cb = write_render;
|
||||
options.output_pass = "combined";
|
||||
options.session = new Session(options.session_params, options.scene_params);
|
||||
|
||||
if (!options.output_filepath.empty()) {
|
||||
options.session->set_output_driver(make_unique<OIIOOutputDriver>(
|
||||
options.output_filepath, options.output_pass, session_print));
|
||||
}
|
||||
|
||||
if (options.session_params.background && !options.quiet)
|
||||
options.session->progress.set_update_callback(function_bind(&session_print_status));
|
||||
#ifdef WITH_CYCLES_STANDALONE_GUI
|
||||
@ -160,6 +145,11 @@ static void session_init()
|
||||
/* load scene */
|
||||
scene_init();
|
||||
|
||||
/* add pass for output. */
|
||||
Pass *pass = options.scene->create_node<Pass>();
|
||||
pass->set_name(ustring(options.output_pass.c_str()));
|
||||
pass->set_type(PASS_COMBINED);
|
||||
|
||||
options.session->reset(options.session_params, session_buffer_params());
|
||||
options.session->start();
|
||||
}
|
||||
|
@ -333,6 +333,7 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node
|
||||
}
|
||||
|
||||
snode = (ShaderNode *)node_type->create(node_type);
|
||||
snode->set_owner(graph);
|
||||
}
|
||||
|
||||
xml_read_node(graph_reader, snode, node);
|
||||
|
71
intern/cycles/app/oiio_output_driver.cpp
Normal file
71
intern/cycles/app/oiio_output_driver.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2021 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 "app/oiio_output_driver.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
OIIOOutputDriver::OIIOOutputDriver(const string_view filepath,
|
||||
const string_view pass,
|
||||
LogFunction log)
|
||||
: filepath_(filepath), pass_(pass), log_(log)
|
||||
{
|
||||
}
|
||||
|
||||
OIIOOutputDriver::~OIIOOutputDriver()
|
||||
{
|
||||
}
|
||||
|
||||
void OIIOOutputDriver::write_render_tile(const Tile &tile)
|
||||
{
|
||||
/* Only write the full buffer, no intermediate tiles. */
|
||||
if (!(tile.size == tile.full_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_(string_printf("Writing image %s", filepath_.c_str()));
|
||||
|
||||
unique_ptr<ImageOutput> image_output(ImageOutput::create(filepath_));
|
||||
if (image_output == nullptr) {
|
||||
log_("Failed to create image file");
|
||||
return;
|
||||
}
|
||||
|
||||
const int width = tile.size.x;
|
||||
const int height = tile.size.y;
|
||||
|
||||
ImageSpec spec(width, height, 4, TypeDesc::FLOAT);
|
||||
if (!image_output->open(filepath_, spec)) {
|
||||
log_("Failed to create image file");
|
||||
return;
|
||||
}
|
||||
|
||||
vector<float> pixels(width * height * 4);
|
||||
if (!tile.get_pass_pixels(pass_, 4, pixels.data())) {
|
||||
log_("Failed to read render pass pixels");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Manipulate offset and stride to convert from bottom-up to top-down convention. */
|
||||
image_output->write_image(TypeDesc::FLOAT,
|
||||
pixels.data() + (height - 1) * width * 4,
|
||||
AutoStride,
|
||||
-width * 4 * sizeof(float),
|
||||
AutoStride);
|
||||
image_output->close();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
42
intern/cycles/app/oiio_output_driver.h
Normal file
42
intern/cycles/app/oiio_output_driver.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2021 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 "render/output_driver.h"
|
||||
|
||||
#include "util/util_function.h"
|
||||
#include "util/util_image.h"
|
||||
#include "util/util_string.h"
|
||||
#include "util/util_unique_ptr.h"
|
||||
#include "util/util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class OIIOOutputDriver : public OutputDriver {
|
||||
public:
|
||||
typedef function<void(const string &)> LogFunction;
|
||||
|
||||
OIIOOutputDriver(const string_view filepath, const string_view pass, LogFunction log);
|
||||
virtual ~OIIOOutputDriver();
|
||||
|
||||
void write_render_tile(const Tile &tile) override;
|
||||
|
||||
protected:
|
||||
string filepath_;
|
||||
string pass_;
|
||||
LogFunction log_;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@ -38,6 +38,7 @@ set(SRC
|
||||
blender_mesh.cpp
|
||||
blender_object.cpp
|
||||
blender_object_cull.cpp
|
||||
blender_output_driver.cpp
|
||||
blender_particles.cpp
|
||||
blender_curves.cpp
|
||||
blender_logging.cpp
|
||||
@ -55,6 +56,7 @@ set(SRC
|
||||
blender_id_map.h
|
||||
blender_image.h
|
||||
blender_object_cull.h
|
||||
blender_output_driver.h
|
||||
blender_sync.h
|
||||
blender_session.h
|
||||
blender_texture.h
|
||||
|
127
intern/cycles/blender/blender_output_driver.cpp
Normal file
127
intern/cycles/blender/blender_output_driver.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2021 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 "blender/blender_output_driver.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
BlenderOutputDriver::BlenderOutputDriver(BL::RenderEngine &b_engine) : b_engine_(b_engine)
|
||||
{
|
||||
}
|
||||
|
||||
BlenderOutputDriver::~BlenderOutputDriver()
|
||||
{
|
||||
}
|
||||
|
||||
bool BlenderOutputDriver::read_render_tile(const Tile &tile)
|
||||
{
|
||||
/* Get render result. */
|
||||
BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
|
||||
tile.offset.y,
|
||||
tile.size.x,
|
||||
tile.size.y,
|
||||
tile.layer.c_str(),
|
||||
tile.view.c_str());
|
||||
|
||||
/* Can happen if the intersected rectangle gives 0 width or height. */
|
||||
if (b_rr.ptr.data == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BL::RenderResult::layers_iterator b_single_rlay;
|
||||
b_rr.layers.begin(b_single_rlay);
|
||||
|
||||
/* layer will be missing if it was disabled in the UI */
|
||||
if (b_single_rlay == b_rr.layers.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||
|
||||
vector<float> pixels(tile.size.x * tile.size.y * 4);
|
||||
|
||||
/* Copy each pass.
|
||||
* TODO:copy only the required ones for better performance? */
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
tile.set_pass_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
|
||||
}
|
||||
|
||||
b_engine_.end_result(b_rr, false, false, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BlenderOutputDriver::update_render_tile(const Tile &tile)
|
||||
{
|
||||
/* Use final write for preview renders, otherwise render result wouldn't be be updated
|
||||
* quickly on Blender side. For all other cases we use the display driver. */
|
||||
if (b_engine_.is_preview()) {
|
||||
write_render_tile(tile);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
/* Don't highlight full-frame tile. */
|
||||
if (!(tile.size == tile.full_size)) {
|
||||
b_engine_.tile_highlight_clear_all();
|
||||
b_engine_.tile_highlight_set(tile.offset.x, tile.offset.y, tile.size.x, tile.size.y, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderOutputDriver::write_render_tile(const Tile &tile)
|
||||
{
|
||||
b_engine_.tile_highlight_clear_all();
|
||||
|
||||
/* Get render result. */
|
||||
BL::RenderResult b_rr = b_engine_.begin_result(tile.offset.x,
|
||||
tile.offset.y,
|
||||
tile.size.x,
|
||||
tile.size.y,
|
||||
tile.layer.c_str(),
|
||||
tile.view.c_str());
|
||||
|
||||
/* Can happen if the intersected rectangle gives 0 width or height. */
|
||||
if (b_rr.ptr.data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::RenderResult::layers_iterator b_single_rlay;
|
||||
b_rr.layers.begin(b_single_rlay);
|
||||
|
||||
/* Layer will be missing if it was disabled in the UI. */
|
||||
if (b_single_rlay == b_rr.layers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||
|
||||
vector<float> pixels(tile.size.x * tile.size.y * 4);
|
||||
|
||||
/* Copy each pass. */
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
if (!tile.get_pass_pixels(b_pass.name(), b_pass.channels(), &pixels[0])) {
|
||||
memset(&pixels[0], 0, pixels.size() * sizeof(float));
|
||||
}
|
||||
|
||||
b_pass.rect(&pixels[0]);
|
||||
}
|
||||
|
||||
b_engine_.end_result(b_rr, true, false, true);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
40
intern/cycles/blender/blender_output_driver.h
Normal file
40
intern/cycles/blender/blender_output_driver.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_blender_cpp.h"
|
||||
|
||||
#include "render/output_driver.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class BlenderOutputDriver : public OutputDriver {
|
||||
public:
|
||||
BlenderOutputDriver(BL::RenderEngine &b_engine);
|
||||
~BlenderOutputDriver();
|
||||
|
||||
virtual void write_render_tile(const Tile &tile) override;
|
||||
virtual bool update_render_tile(const Tile &tile) override;
|
||||
virtual bool read_render_tile(const Tile &tile) override;
|
||||
|
||||
protected:
|
||||
BL::RenderEngine b_engine_;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@ -43,6 +43,7 @@
|
||||
#include "util/util_time.h"
|
||||
|
||||
#include "blender/blender_display_driver.h"
|
||||
#include "blender/blender_output_driver.h"
|
||||
#include "blender/blender_session.h"
|
||||
#include "blender/blender_sync.h"
|
||||
#include "blender/blender_util.h"
|
||||
@ -157,7 +158,8 @@ void BlenderSession::create_session()
|
||||
b_v3d, b_rv3d, scene->camera, width, height);
|
||||
session->reset(session_params, buffer_params);
|
||||
|
||||
/* Create GPU display. */
|
||||
/* Create GPU display.
|
||||
* TODO(sergey): Investigate whether DisplayDriver can be used for the preview as well. */
|
||||
if (!b_engine.is_preview() && !headless) {
|
||||
unique_ptr<BlenderDisplayDriver> display_driver = make_unique<BlenderDisplayDriver>(b_engine,
|
||||
b_scene);
|
||||
@ -279,96 +281,6 @@ void BlenderSession::free_session()
|
||||
session = nullptr;
|
||||
}
|
||||
|
||||
void BlenderSession::read_render_tile()
|
||||
{
|
||||
const int2 tile_offset = session->get_render_tile_offset();
|
||||
const int2 tile_size = session->get_render_tile_size();
|
||||
|
||||
/* get render result */
|
||||
BL::RenderResult b_rr = b_engine.begin_result(tile_offset.x,
|
||||
tile_offset.y,
|
||||
tile_size.x,
|
||||
tile_size.y,
|
||||
b_rlay_name.c_str(),
|
||||
b_rview_name.c_str());
|
||||
|
||||
/* can happen if the intersected rectangle gives 0 width or height */
|
||||
if (b_rr.ptr.data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::RenderResult::layers_iterator b_single_rlay;
|
||||
b_rr.layers.begin(b_single_rlay);
|
||||
|
||||
/* layer will be missing if it was disabled in the UI */
|
||||
if (b_single_rlay == b_rr.layers.end())
|
||||
return;
|
||||
|
||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||
|
||||
vector<float> pixels(tile_size.x * tile_size.y * 4);
|
||||
|
||||
/* Copy each pass.
|
||||
* TODO:copy only the required ones for better performance? */
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
session->set_render_tile_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
|
||||
}
|
||||
|
||||
b_engine.end_result(b_rr, false, false, false);
|
||||
}
|
||||
|
||||
void BlenderSession::write_render_tile()
|
||||
{
|
||||
const int2 tile_offset = session->get_render_tile_offset();
|
||||
const int2 tile_size = session->get_render_tile_size();
|
||||
|
||||
const string_view render_layer_name = session->get_render_tile_layer();
|
||||
const string_view render_view_name = session->get_render_tile_view();
|
||||
|
||||
b_engine.tile_highlight_clear_all();
|
||||
|
||||
/* get render result */
|
||||
BL::RenderResult b_rr = b_engine.begin_result(tile_offset.x,
|
||||
tile_offset.y,
|
||||
tile_size.x,
|
||||
tile_size.y,
|
||||
render_layer_name.c_str(),
|
||||
render_view_name.c_str());
|
||||
|
||||
/* can happen if the intersected rectangle gives 0 width or height */
|
||||
if (b_rr.ptr.data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::RenderResult::layers_iterator b_single_rlay;
|
||||
b_rr.layers.begin(b_single_rlay);
|
||||
|
||||
/* layer will be missing if it was disabled in the UI */
|
||||
if (b_single_rlay == b_rr.layers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::RenderLayer b_rlay = *b_single_rlay;
|
||||
|
||||
write_render_result(b_rlay);
|
||||
|
||||
b_engine.end_result(b_rr, true, false, true);
|
||||
}
|
||||
|
||||
void BlenderSession::update_render_tile()
|
||||
{
|
||||
if (!session->has_multiple_render_tiles()) {
|
||||
/* Don't highlight full-frame tile. */
|
||||
return;
|
||||
}
|
||||
|
||||
const int2 tile_offset = session->get_render_tile_offset();
|
||||
const int2 tile_size = session->get_render_tile_size();
|
||||
|
||||
b_engine.tile_highlight_clear_all();
|
||||
b_engine.tile_highlight_set(tile_offset.x, tile_offset.y, tile_size.x, tile_size.y, true);
|
||||
}
|
||||
|
||||
void BlenderSession::full_buffer_written(string_view filename)
|
||||
{
|
||||
full_buffer_files_.emplace_back(filename);
|
||||
@ -442,18 +354,8 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
|
||||
return;
|
||||
}
|
||||
|
||||
/* set callback to write out render results */
|
||||
session->write_render_tile_cb = [&]() { write_render_tile(); };
|
||||
|
||||
/* Use final write for preview renders, otherwise render result wouldn't be be updated on Blender
|
||||
* side. */
|
||||
/* TODO(sergey): Investigate whether DisplayDriver can be used for the preview as well. */
|
||||
if (b_engine.is_preview()) {
|
||||
session->update_render_tile_cb = [&]() { write_render_tile(); };
|
||||
}
|
||||
else {
|
||||
session->update_render_tile_cb = [&]() { update_render_tile(); };
|
||||
}
|
||||
/* Create driver to write out render results. */
|
||||
session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
|
||||
|
||||
session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
|
||||
|
||||
@ -599,9 +501,8 @@ void BlenderSession::render_frame_finish()
|
||||
path_remove(filename);
|
||||
}
|
||||
|
||||
/* clear callback */
|
||||
session->write_render_tile_cb = function_null;
|
||||
session->update_render_tile_cb = function_null;
|
||||
/* Clear driver. */
|
||||
session->set_output_driver(nullptr);
|
||||
session->full_buffer_written_cb = function_null;
|
||||
}
|
||||
|
||||
@ -707,9 +608,8 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
|
||||
pass->set_type(bake_type_to_pass(bake_type, bake_filter));
|
||||
pass->set_include_albedo((bake_filter & BL::BakeSettings::pass_filter_COLOR));
|
||||
|
||||
session->read_render_tile_cb = [&]() { read_render_tile(); };
|
||||
session->write_render_tile_cb = [&]() { write_render_tile(); };
|
||||
session->set_display_driver(nullptr);
|
||||
session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
|
||||
|
||||
if (!session->progress.get_cancel()) {
|
||||
/* Sync scene. */
|
||||
@ -752,43 +652,7 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_,
|
||||
session->wait();
|
||||
}
|
||||
|
||||
session->read_render_tile_cb = function_null;
|
||||
session->write_render_tile_cb = function_null;
|
||||
}
|
||||
|
||||
void BlenderSession::write_render_result(BL::RenderLayer &b_rlay)
|
||||
{
|
||||
if (!session->copy_render_tile_from_device()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int2 tile_size = session->get_render_tile_size();
|
||||
vector<float> pixels(tile_size.x * tile_size.y * 4);
|
||||
|
||||
/* Copy each pass. */
|
||||
for (BL::RenderPass &b_pass : b_rlay.passes) {
|
||||
if (!session->get_render_tile_pixels(b_pass.name(), b_pass.channels(), &pixels[0])) {
|
||||
memset(&pixels[0], 0, pixels.size() * sizeof(float));
|
||||
}
|
||||
|
||||
b_pass.rect(&pixels[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSession::update_render_result(BL::RenderLayer &b_rlay)
|
||||
{
|
||||
if (!session->copy_render_tile_from_device()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int2 tile_size = session->get_render_tile_size();
|
||||
vector<float> pixels(tile_size.x * tile_size.y * 4);
|
||||
|
||||
/* Copy combined pass. */
|
||||
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
|
||||
if (session->get_render_tile_pixels("Combined", b_combined_pass.channels(), &pixels[0])) {
|
||||
b_combined_pass.rect(&pixels[0]);
|
||||
}
|
||||
session->set_output_driver(nullptr);
|
||||
}
|
||||
|
||||
void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
|
||||
|
@ -70,20 +70,7 @@ class BlenderSession {
|
||||
const int bake_width,
|
||||
const int bake_height);
|
||||
|
||||
void write_render_result(BL::RenderLayer &b_rlay);
|
||||
void write_render_tile();
|
||||
|
||||
void update_render_tile();
|
||||
|
||||
void full_buffer_written(string_view filename);
|
||||
|
||||
/* update functions are used to update display buffer only after sample was rendered
|
||||
* only needed for better visual feedback */
|
||||
void update_render_result(BL::RenderLayer &b_rlay);
|
||||
|
||||
/* read functions for baking input */
|
||||
void read_render_tile();
|
||||
|
||||
/* interactive updates */
|
||||
void synchronize(BL::Depsgraph &b_depsgraph);
|
||||
|
||||
|
@ -28,6 +28,7 @@ set(SRC
|
||||
pass_accessor_cpu.cpp
|
||||
pass_accessor_gpu.cpp
|
||||
path_trace_display.cpp
|
||||
path_trace_tile.cpp
|
||||
path_trace_work.cpp
|
||||
path_trace_work_cpu.cpp
|
||||
path_trace_work_gpu.cpp
|
||||
@ -49,6 +50,7 @@ set(SRC_HEADERS
|
||||
pass_accessor_cpu.h
|
||||
pass_accessor_gpu.h
|
||||
path_trace_display.h
|
||||
path_trace_tile.h
|
||||
path_trace_work.h
|
||||
path_trace_work_cpu.h
|
||||
path_trace_work_gpu.h
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "device/device.h"
|
||||
#include "integrator/pass_accessor.h"
|
||||
#include "integrator/path_trace_display.h"
|
||||
#include "integrator/path_trace_tile.h"
|
||||
#include "integrator/render_scheduler.h"
|
||||
#include "render/pass.h"
|
||||
#include "render/scene.h"
|
||||
@ -535,6 +536,11 @@ void PathTrace::denoise(const RenderWork &render_work)
|
||||
render_scheduler_.report_denoise_time(render_work, time_dt() - start_time);
|
||||
}
|
||||
|
||||
void PathTrace::set_output_driver(unique_ptr<OutputDriver> driver)
|
||||
{
|
||||
output_driver_ = move(driver);
|
||||
}
|
||||
|
||||
void PathTrace::set_display_driver(unique_ptr<DisplayDriver> driver)
|
||||
{
|
||||
if (driver) {
|
||||
@ -567,7 +573,7 @@ void PathTrace::update_display(const RenderWork &render_work)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!display_ && !tile_buffer_update_cb) {
|
||||
if (!display_ && !output_driver_) {
|
||||
VLOG(3) << "Ignore display update.";
|
||||
return;
|
||||
}
|
||||
@ -579,10 +585,11 @@ void PathTrace::update_display(const RenderWork &render_work)
|
||||
|
||||
const double start_time = time_dt();
|
||||
|
||||
if (tile_buffer_update_cb) {
|
||||
if (output_driver_) {
|
||||
VLOG(3) << "Invoke buffer update callback.";
|
||||
|
||||
tile_buffer_update_cb();
|
||||
PathTraceTile tile(*this);
|
||||
output_driver_->update_render_tile(tile);
|
||||
}
|
||||
|
||||
if (display_) {
|
||||
@ -758,20 +765,26 @@ bool PathTrace::is_cancel_requested()
|
||||
|
||||
void PathTrace::tile_buffer_write()
|
||||
{
|
||||
if (!tile_buffer_write_cb) {
|
||||
if (!output_driver_) {
|
||||
return;
|
||||
}
|
||||
|
||||
tile_buffer_write_cb();
|
||||
PathTraceTile tile(*this);
|
||||
output_driver_->write_render_tile(tile);
|
||||
}
|
||||
|
||||
void PathTrace::tile_buffer_read()
|
||||
{
|
||||
if (!tile_buffer_read_cb) {
|
||||
if (!device_scene_->data.bake.use) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tile_buffer_read_cb()) {
|
||||
if (!output_driver_) {
|
||||
return;
|
||||
}
|
||||
|
||||
PathTraceTile tile(*this);
|
||||
if (output_driver_->read_render_tile(tile)) {
|
||||
tbb::parallel_for_each(path_trace_works_, [](unique_ptr<PathTraceWork> &path_trace_work) {
|
||||
path_trace_work->copy_render_buffers_to_device();
|
||||
});
|
||||
@ -1010,6 +1023,11 @@ int2 PathTrace::get_render_tile_offset() const
|
||||
return make_int2(tile.x, tile.y);
|
||||
}
|
||||
|
||||
int2 PathTrace::get_render_size() const
|
||||
{
|
||||
return tile_manager_.get_size();
|
||||
}
|
||||
|
||||
const BufferParams &PathTrace::get_render_tile_params() const
|
||||
{
|
||||
if (full_frame_state_.render_buffers) {
|
||||
|
@ -37,6 +37,7 @@ class RenderBuffers;
|
||||
class RenderScheduler;
|
||||
class RenderWork;
|
||||
class PathTraceDisplay;
|
||||
class OutputDriver;
|
||||
class Progress;
|
||||
class TileManager;
|
||||
|
||||
@ -99,7 +100,10 @@ class PathTrace {
|
||||
* Use this to configure the adaptive sampler before rendering any samples. */
|
||||
void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling);
|
||||
|
||||
/* Set display driver which takes care of drawing the render result. */
|
||||
/* Sets output driver for render buffer output. */
|
||||
void set_output_driver(unique_ptr<OutputDriver> driver);
|
||||
|
||||
/* Set display driver for interactive render buffer display. */
|
||||
void set_display_driver(unique_ptr<DisplayDriver> driver);
|
||||
|
||||
/* Clear the display buffer by filling it in with all zeroes. */
|
||||
@ -158,6 +162,7 @@ class PathTrace {
|
||||
* instead. */
|
||||
int2 get_render_tile_size() const;
|
||||
int2 get_render_tile_offset() const;
|
||||
int2 get_render_size() const;
|
||||
|
||||
/* Get buffer parameters of the current tile.
|
||||
*
|
||||
@ -169,18 +174,6 @@ class PathTrace {
|
||||
* times, and so on. */
|
||||
string full_report() const;
|
||||
|
||||
/* Callback which communicates an updates state of the render buffer of the current big tile.
|
||||
* Is called during path tracing to communicate work-in-progress state of the final buffer. */
|
||||
function<void(void)> tile_buffer_update_cb;
|
||||
|
||||
/* Callback which communicates final rendered buffer. Is called after path-tracing is done. */
|
||||
function<void(void)> tile_buffer_write_cb;
|
||||
|
||||
/* Callback which initializes rendered buffer. Is called before path-tracing starts.
|
||||
*
|
||||
* This is used for baking. */
|
||||
function<bool(void)> tile_buffer_read_cb;
|
||||
|
||||
/* Callback which is called to report current rendering progress.
|
||||
*
|
||||
* It is supposed to be cheaper than buffer update/write, hence can be called more often.
|
||||
@ -253,8 +246,12 @@ class PathTrace {
|
||||
RenderScheduler &render_scheduler_;
|
||||
TileManager &tile_manager_;
|
||||
|
||||
/* Display driver for interactive render buffer display. */
|
||||
unique_ptr<PathTraceDisplay> display_;
|
||||
|
||||
/* Output driver to write render buffer to. */
|
||||
unique_ptr<OutputDriver> output_driver_;
|
||||
|
||||
/* Per-compute device descriptors of work which is responsible for path tracing on its configured
|
||||
* device. */
|
||||
vector<unique_ptr<PathTraceWork>> path_trace_works_;
|
||||
|
107
intern/cycles/integrator/path_trace_tile.cpp
Normal file
107
intern/cycles/integrator/path_trace_tile.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2021 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 "integrator/path_trace_tile.h"
|
||||
#include "integrator/pass_accessor_cpu.h"
|
||||
#include "integrator/path_trace.h"
|
||||
|
||||
#include "render/buffers.h"
|
||||
#include "render/film.h"
|
||||
#include "render/pass.h"
|
||||
#include "render/scene.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
PathTraceTile::PathTraceTile(PathTrace &path_trace)
|
||||
: OutputDriver::Tile(path_trace.get_render_tile_offset(),
|
||||
path_trace.get_render_tile_size(),
|
||||
path_trace.get_render_size(),
|
||||
path_trace.get_render_tile_params().layer,
|
||||
path_trace.get_render_tile_params().view),
|
||||
path_trace_(path_trace),
|
||||
copied_from_device_(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool PathTraceTile::get_pass_pixels(const string_view pass_name,
|
||||
const int num_channels,
|
||||
float *pixels) const
|
||||
{
|
||||
/* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
|
||||
* is happening while this function runs. */
|
||||
|
||||
if (!copied_from_device_) {
|
||||
/* Copy from device on demand. */
|
||||
path_trace_.copy_render_tile_from_device();
|
||||
const_cast<PathTraceTile *>(this)->copied_from_device_ = true;
|
||||
}
|
||||
|
||||
const BufferParams &buffer_params = path_trace_.get_render_tile_params();
|
||||
|
||||
const BufferPass *pass = buffer_params.find_pass(pass_name);
|
||||
if (pass == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool has_denoised_result = path_trace_.has_denoised_result();
|
||||
if (pass->mode == PassMode::DENOISED && !has_denoised_result) {
|
||||
pass = buffer_params.find_pass(pass->type);
|
||||
if (pass == nullptr) {
|
||||
/* Happens when denoised result pass is requested but is never written by the kernel. */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pass = buffer_params.get_actual_display_pass(pass);
|
||||
|
||||
const float exposure = buffer_params.exposure;
|
||||
const int num_samples = path_trace_.get_num_render_tile_samples();
|
||||
|
||||
PassAccessor::PassAccessInfo pass_access_info(*pass);
|
||||
pass_access_info.use_approximate_shadow_catcher = buffer_params.use_approximate_shadow_catcher;
|
||||
pass_access_info.use_approximate_shadow_catcher_background =
|
||||
pass_access_info.use_approximate_shadow_catcher && !buffer_params.use_transparent_background;
|
||||
|
||||
const PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
|
||||
const PassAccessor::Destination destination(pixels, num_channels);
|
||||
|
||||
return path_trace_.get_render_tile_pixels(pass_accessor, destination);
|
||||
}
|
||||
|
||||
bool PathTraceTile::set_pass_pixels(const string_view pass_name,
|
||||
const int num_channels,
|
||||
const float *pixels) const
|
||||
{
|
||||
/* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
|
||||
* is happening while this function runs. */
|
||||
|
||||
const BufferParams &buffer_params = path_trace_.get_render_tile_params();
|
||||
const BufferPass *pass = buffer_params.find_pass(pass_name);
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const float exposure = buffer_params.exposure;
|
||||
const int num_samples = 1;
|
||||
|
||||
const PassAccessor::PassAccessInfo pass_access_info(*pass);
|
||||
PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
|
||||
PassAccessor::Source source(pixels, num_channels);
|
||||
|
||||
return path_trace_.set_render_tile_pixels(pass_accessor, source);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
43
intern/cycles/integrator/path_trace_tile.h
Normal file
43
intern/cycles/integrator/path_trace_tile.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "render/output_driver.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* PathTraceTile
|
||||
*
|
||||
* Implementation of OutputDriver::Tile interface for path tracer. */
|
||||
|
||||
class PathTrace;
|
||||
|
||||
class PathTraceTile : public OutputDriver::Tile {
|
||||
public:
|
||||
PathTraceTile(PathTrace &path_trace);
|
||||
|
||||
bool get_pass_pixels(const string_view pass_name, const int num_channels, float *pixels) const;
|
||||
bool set_pass_pixels(const string_view pass_name,
|
||||
const int num_channels,
|
||||
const float *pixels) const;
|
||||
|
||||
private:
|
||||
PathTrace &path_trace_;
|
||||
bool copied_from_device_;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@ -78,6 +78,7 @@ set(SRC_HEADERS
|
||||
constant_fold.h
|
||||
denoising.h
|
||||
display_driver.h
|
||||
output_driver.h
|
||||
film.h
|
||||
geometry.h
|
||||
graph.h
|
||||
|
82
intern/cycles/render/output_driver.h
Normal file
82
intern/cycles/render/output_driver.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/util_math.h"
|
||||
#include "util/util_string.h"
|
||||
#include "util/util_types.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Output driver for reading render buffers.
|
||||
*
|
||||
* Host applications implement this interface for outputting render buffers for offline rendering.
|
||||
* Drivers can be used to copy the buffers into the host application or write them directly to
|
||||
* disk. This interface may also be used for interactive display, however the DisplayDriver is more
|
||||
* efficient for that purpose.
|
||||
*/
|
||||
class OutputDriver {
|
||||
public:
|
||||
OutputDriver() = default;
|
||||
virtual ~OutputDriver() = default;
|
||||
|
||||
class Tile {
|
||||
public:
|
||||
Tile(const int2 offset,
|
||||
const int2 size,
|
||||
const int2 full_size,
|
||||
const string_view layer,
|
||||
const string_view view)
|
||||
: offset(offset), size(size), full_size(full_size), layer(layer), view(view)
|
||||
{
|
||||
}
|
||||
virtual ~Tile() = default;
|
||||
|
||||
const int2 offset;
|
||||
const int2 size;
|
||||
const int2 full_size;
|
||||
const string layer;
|
||||
const string view;
|
||||
|
||||
virtual bool get_pass_pixels(const string_view pass_name,
|
||||
const int num_channels,
|
||||
float *pixels) const = 0;
|
||||
virtual bool set_pass_pixels(const string_view pass_name,
|
||||
const int num_channels,
|
||||
const float *pixels) const = 0;
|
||||
};
|
||||
|
||||
/* Write tile once it has finished rendering. */
|
||||
virtual void write_render_tile(const Tile &tile) = 0;
|
||||
|
||||
/* Update tile while rendering is in progress. Return true if any update
|
||||
* was performed. */
|
||||
virtual bool update_render_tile(const Tile & /* tile */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For baking, read render pass PASS_BAKE_PRIMITIVE and PASS_BAKE_DIFFERENTIAL
|
||||
* to determine which shading points to use for baking at each pixel. Return
|
||||
* true if any data was read. */
|
||||
virtual bool read_render_tile(const Tile & /* tile */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
@ -31,6 +31,7 @@
|
||||
#include "render/light.h"
|
||||
#include "render/mesh.h"
|
||||
#include "render/object.h"
|
||||
#include "render/output_driver.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/session.h"
|
||||
|
||||
@ -64,25 +65,6 @@ Session::Session(const SessionParams ¶ms_, const SceneParams &scene_params)
|
||||
path_trace_ = make_unique<PathTrace>(
|
||||
device, scene->film, &scene->dscene, render_scheduler_, tile_manager_);
|
||||
path_trace_->set_progress(&progress);
|
||||
path_trace_->tile_buffer_update_cb = [&]() {
|
||||
if (!update_render_tile_cb) {
|
||||
return;
|
||||
}
|
||||
update_render_tile_cb();
|
||||
};
|
||||
path_trace_->tile_buffer_write_cb = [&]() {
|
||||
if (!write_render_tile_cb) {
|
||||
return;
|
||||
}
|
||||
write_render_tile_cb();
|
||||
};
|
||||
path_trace_->tile_buffer_read_cb = [&]() -> bool {
|
||||
if (!read_render_tile_cb) {
|
||||
return false;
|
||||
}
|
||||
read_render_tile_cb();
|
||||
return true;
|
||||
};
|
||||
path_trace_->progress_update_cb = [&]() { update_status_time(); };
|
||||
|
||||
tile_manager_.full_buffer_written_cb = [&](string_view filename) {
|
||||
@ -97,24 +79,6 @@ Session::~Session()
|
||||
{
|
||||
cancel();
|
||||
|
||||
/* TODO(sergey): Bring the passes in viewport back.
|
||||
* It is unclear why there is such an exception needed though. */
|
||||
#if 0
|
||||
if (buffers && params.write_render_cb) {
|
||||
/* Copy to display buffer and write out image if requested */
|
||||
delete display;
|
||||
|
||||
display = new DisplayBuffer(device, false);
|
||||
display->reset(buffers->params);
|
||||
copy_to_display_buffer(params.samples);
|
||||
|
||||
int w = display->draw_width;
|
||||
int h = display->draw_height;
|
||||
uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h);
|
||||
params.write_render_cb((uchar *)pixels, w, h, 4);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure path tracer is destroyed before the device. This is needed because destruction might
|
||||
* need to access device for device memory free. */
|
||||
/* TODO(sergey): Convert device to be unique_ptr, and rely on C++ to destruct objects in the
|
||||
@ -514,6 +478,11 @@ void Session::set_pause(bool pause)
|
||||
}
|
||||
}
|
||||
|
||||
void Session::set_output_driver(unique_ptr<OutputDriver> driver)
|
||||
{
|
||||
path_trace_->set_output_driver(move(driver));
|
||||
}
|
||||
|
||||
void Session::set_display_driver(unique_ptr<DisplayDriver> driver)
|
||||
{
|
||||
path_trace_->set_display_driver(move(driver));
|
||||
@ -636,101 +605,6 @@ void Session::collect_statistics(RenderStats *render_stats)
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Tile and tile pixels access.
|
||||
*/
|
||||
|
||||
bool Session::has_multiple_render_tiles() const
|
||||
{
|
||||
return tile_manager_.has_multiple_tiles();
|
||||
}
|
||||
|
||||
int2 Session::get_render_tile_size() const
|
||||
{
|
||||
return path_trace_->get_render_tile_size();
|
||||
}
|
||||
|
||||
int2 Session::get_render_tile_offset() const
|
||||
{
|
||||
return path_trace_->get_render_tile_offset();
|
||||
}
|
||||
|
||||
string_view Session::get_render_tile_layer() const
|
||||
{
|
||||
const BufferParams &buffer_params = path_trace_->get_render_tile_params();
|
||||
return buffer_params.layer;
|
||||
}
|
||||
|
||||
string_view Session::get_render_tile_view() const
|
||||
{
|
||||
const BufferParams &buffer_params = path_trace_->get_render_tile_params();
|
||||
return buffer_params.view;
|
||||
}
|
||||
|
||||
bool Session::copy_render_tile_from_device()
|
||||
{
|
||||
return path_trace_->copy_render_tile_from_device();
|
||||
}
|
||||
|
||||
bool Session::get_render_tile_pixels(const string &pass_name, int num_components, float *pixels)
|
||||
{
|
||||
/* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
|
||||
* is happening while this function runs. */
|
||||
|
||||
const BufferParams &buffer_params = path_trace_->get_render_tile_params();
|
||||
|
||||
const BufferPass *pass = buffer_params.find_pass(pass_name);
|
||||
if (pass == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool has_denoised_result = path_trace_->has_denoised_result();
|
||||
if (pass->mode == PassMode::DENOISED && !has_denoised_result) {
|
||||
pass = buffer_params.find_pass(pass->type);
|
||||
if (pass == nullptr) {
|
||||
/* Happens when denoised result pass is requested but is never written by the kernel. */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pass = buffer_params.get_actual_display_pass(pass);
|
||||
|
||||
const float exposure = buffer_params.exposure;
|
||||
const int num_samples = path_trace_->get_num_render_tile_samples();
|
||||
|
||||
PassAccessor::PassAccessInfo pass_access_info(*pass);
|
||||
pass_access_info.use_approximate_shadow_catcher = buffer_params.use_approximate_shadow_catcher;
|
||||
pass_access_info.use_approximate_shadow_catcher_background =
|
||||
pass_access_info.use_approximate_shadow_catcher && !buffer_params.use_transparent_background;
|
||||
|
||||
const PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
|
||||
const PassAccessor::Destination destination(pixels, num_components);
|
||||
|
||||
return path_trace_->get_render_tile_pixels(pass_accessor, destination);
|
||||
}
|
||||
|
||||
bool Session::set_render_tile_pixels(const string &pass_name,
|
||||
int num_components,
|
||||
const float *pixels)
|
||||
{
|
||||
/* NOTE: The code relies on a fact that session is fully update and no scene/buffer modification
|
||||
* is happening while this function runs. */
|
||||
|
||||
const BufferPass *pass = buffer_params_.find_pass(pass_name);
|
||||
if (!pass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const float exposure = scene->film->get_exposure();
|
||||
const int num_samples = render_scheduler_.get_num_rendered_samples();
|
||||
|
||||
const PassAccessor::PassAccessInfo pass_access_info(*pass);
|
||||
PassAccessorCPU pass_accessor(pass_access_info, exposure, num_samples);
|
||||
PassAccessor::Source source(pixels, num_components);
|
||||
|
||||
return path_trace_->set_render_tile_pixels(pass_accessor, source);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Full-frame on-disk storage.
|
||||
*/
|
||||
|
@ -36,6 +36,7 @@ class BufferParams;
|
||||
class Device;
|
||||
class DeviceScene;
|
||||
class DisplayDriver;
|
||||
class OutputDriver;
|
||||
class PathTrace;
|
||||
class Progress;
|
||||
class RenderBuffers;
|
||||
@ -67,8 +68,6 @@ class SessionParams {
|
||||
|
||||
ShadingSystem shadingsystem;
|
||||
|
||||
function<bool(const uchar *pixels, int width, int height, int channels)> write_render_cb;
|
||||
|
||||
SessionParams()
|
||||
{
|
||||
headless = false;
|
||||
@ -114,10 +113,6 @@ class Session {
|
||||
Stats stats;
|
||||
Profiler profiler;
|
||||
|
||||
function<void(void)> write_render_tile_cb;
|
||||
function<void(void)> update_render_tile_cb;
|
||||
function<void(void)> read_render_tile_cb;
|
||||
|
||||
/* Callback is invoked by tile manager whenever on-dist tiles storage file is closed after
|
||||
* writing. Allows an engine integration to keep track of those files without worry about
|
||||
* transferring the information when it needs to re-create session during rendering. */
|
||||
@ -143,6 +138,7 @@ class Session {
|
||||
void set_samples(int samples);
|
||||
void set_time_limit(double time_limit);
|
||||
|
||||
void set_output_driver(unique_ptr<OutputDriver> driver);
|
||||
void set_display_driver(unique_ptr<DisplayDriver> driver);
|
||||
|
||||
double get_estimated_remaining_time() const;
|
||||
@ -155,24 +151,6 @@ class Session {
|
||||
|
||||
void collect_statistics(RenderStats *stats);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Tile and tile pixels access.
|
||||
*/
|
||||
|
||||
bool has_multiple_render_tiles() const;
|
||||
|
||||
/* Get size and offset (relative to the buffer's full x/y) of the currently rendering tile. */
|
||||
int2 get_render_tile_size() const;
|
||||
int2 get_render_tile_offset() const;
|
||||
|
||||
string_view get_render_tile_layer() const;
|
||||
string_view get_render_tile_view() const;
|
||||
|
||||
bool copy_render_tile_from_device();
|
||||
|
||||
bool get_render_tile_pixels(const string &pass_name, int num_components, float *pixels);
|
||||
bool set_render_tile_pixels(const string &pass_name, int num_components, const float *pixels);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Full-frame on-disk storage.
|
||||
*/
|
||||
|
@ -420,6 +420,11 @@ const Tile &TileManager::get_current_tile() const
|
||||
return tile_state_.current_tile;
|
||||
}
|
||||
|
||||
const int2 TileManager::get_size() const
|
||||
{
|
||||
return make_int2(buffer_params_.width, buffer_params_.height);
|
||||
}
|
||||
|
||||
bool TileManager::open_tile_output()
|
||||
{
|
||||
write_state_.filename = path_temp_get("cycles-tile-buffer-" + tile_file_unique_part_ + "-" +
|
||||
|
@ -82,6 +82,7 @@ class TileManager {
|
||||
bool done();
|
||||
|
||||
const Tile &get_current_tile() const;
|
||||
const int2 get_size() const;
|
||||
|
||||
/* Write render buffer of a tile to a file on disk.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user