Merge branch 'master' into blender2.8
This commit is contained in:
commit
31657fef40
|
@ -52,7 +52,9 @@ def _workaround_buggy_drivers():
|
|||
|
||||
def _configure_argument_parser():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Cycles Addon argument parser")
|
||||
# No help because it conflicts with general Python scripts argument parsing
|
||||
parser = argparse.ArgumentParser(description="Cycles Addon argument parser",
|
||||
add_help=False)
|
||||
parser.add_argument("--cycles-resumable-num-chunks",
|
||||
help="Number of chunks to split sample range into",
|
||||
default=None)
|
||||
|
@ -65,6 +67,9 @@ def _configure_argument_parser():
|
|||
parser.add_argument("--cycles-resumable-end-chunk",
|
||||
help="End chunk to render",
|
||||
default=None)
|
||||
parser.add_argument("--cycles-print-stats",
|
||||
help="Print rendering statistics to stderr",
|
||||
action='store_true')
|
||||
return parser
|
||||
|
||||
|
||||
|
@ -93,6 +98,9 @@ def _parse_command_line():
|
|||
int(args.cycles_resumable_start_chunk),
|
||||
int(args.cycles_resumable_end_chunk),
|
||||
)
|
||||
if args.cycles_print_stats:
|
||||
import _cycles
|
||||
_cycles.enable_print_stats()
|
||||
|
||||
|
||||
def init():
|
||||
|
|
|
@ -738,6 +738,12 @@ static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *a
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
|
||||
{
|
||||
BlenderSession::print_render_stats = true;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
|
||||
{
|
||||
vector<DeviceInfo>& devices = Device::available_devices();
|
||||
|
@ -776,6 +782,9 @@ static PyMethodDef methods[] = {
|
|||
{"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
|
||||
{"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
|
||||
|
||||
/* Statistics. */
|
||||
{"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
|
||||
|
||||
/* Resumable render */
|
||||
{"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
|
||||
{"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "render/scene.h"
|
||||
#include "render/session.h"
|
||||
#include "render/shader.h"
|
||||
#include "render/stats.h"
|
||||
|
||||
#include "util/util_color.h"
|
||||
#include "util/util_foreach.h"
|
||||
|
@ -48,6 +49,7 @@ int BlenderSession::num_resumable_chunks = 0;
|
|||
int BlenderSession::current_resumable_chunk = 0;
|
||||
int BlenderSession::start_resumable_chunk = 0;
|
||||
int BlenderSession::end_resumable_chunk = 0;
|
||||
bool BlenderSession::print_render_stats = false;
|
||||
|
||||
BlenderSession::BlenderSession(BL::RenderEngine& b_engine,
|
||||
BL::UserPreferences& b_userpref,
|
||||
|
@ -479,6 +481,12 @@ void BlenderSession::render(BL::Depsgraph& b_depsgraph_)
|
|||
session->start();
|
||||
session->wait();
|
||||
|
||||
if(!b_engine.is_preview() && background && print_render_stats) {
|
||||
RenderStats stats;
|
||||
session->scene->collect_statistics(&stats);
|
||||
printf("Render statistics:\n%s\n", stats.full_report().c_str());
|
||||
}
|
||||
|
||||
if(session->progress.get_cancel())
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -145,6 +145,8 @@ public:
|
|||
static int start_resumable_chunk;
|
||||
static int end_resumable_chunk;
|
||||
|
||||
static bool print_render_stats;
|
||||
|
||||
protected:
|
||||
void do_write_update_render_result(BL::RenderResult& b_rr,
|
||||
BL::RenderLayer& b_rlay,
|
||||
|
|
|
@ -425,20 +425,22 @@ bool Node::equals(const Node& other) const
|
|||
|
||||
/* Hash */
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
static void value_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
void value_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
{
|
||||
md5.append(((uint8_t*)node) + socket.struct_offset, socket.size());
|
||||
}
|
||||
|
||||
static void float3_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
void float3_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
{
|
||||
/* Don't compare 4th element used for padding. */
|
||||
md5.append(((uint8_t*)node) + socket.struct_offset, sizeof(float) * 3);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
{
|
||||
const array<T>& a = *(const array<T>*)(((char*)node) + socket.struct_offset);
|
||||
for (size_t i = 0; i < a.size(); i++) {
|
||||
|
@ -446,7 +448,7 @@ static void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
|||
}
|
||||
}
|
||||
|
||||
static void float3_array_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
void float3_array_hash(const Node *node, const SocketType& socket, MD5Hash& md5)
|
||||
{
|
||||
/* Don't compare 4th element used for padding. */
|
||||
const array<float3>& a = *(const array<float3>*)(((char*)node) + socket.struct_offset);
|
||||
|
@ -455,6 +457,8 @@ static void float3_array_hash(const Node *node, const SocketType& socket, MD5Has
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Node::hash(MD5Hash& md5)
|
||||
{
|
||||
md5.append(type->name.string());
|
||||
|
@ -495,4 +499,77 @@ void Node::hash(MD5Hash& md5)
|
|||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
size_t array_size_in_bytes(const Node *node, const SocketType& socket)
|
||||
{
|
||||
const array<T>& a = *(const array<T>*)(((char*)node) + socket.struct_offset);
|
||||
return a.size() * sizeof(T);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
size_t Node::get_total_size_in_bytes() const
|
||||
{
|
||||
size_t total_size = 0;
|
||||
foreach(const SocketType& socket, type->inputs) {
|
||||
switch(socket.type) {
|
||||
case SocketType::BOOLEAN:
|
||||
case SocketType::FLOAT:
|
||||
case SocketType::INT:
|
||||
case SocketType::UINT:
|
||||
case SocketType::COLOR:
|
||||
case SocketType::VECTOR:
|
||||
case SocketType::POINT:
|
||||
case SocketType::NORMAL:
|
||||
case SocketType::POINT2:
|
||||
case SocketType::CLOSURE:
|
||||
case SocketType::STRING:
|
||||
case SocketType::ENUM:
|
||||
case SocketType::TRANSFORM:
|
||||
case SocketType::NODE:
|
||||
total_size += socket.size();
|
||||
break;
|
||||
|
||||
case SocketType::BOOLEAN_ARRAY:
|
||||
total_size += array_size_in_bytes<bool>(this, socket);
|
||||
break;
|
||||
case SocketType::FLOAT_ARRAY:
|
||||
total_size += array_size_in_bytes<float>(this, socket);
|
||||
break;
|
||||
case SocketType::INT_ARRAY:
|
||||
total_size += array_size_in_bytes<int>(this, socket);
|
||||
break;
|
||||
case SocketType::COLOR_ARRAY:
|
||||
total_size += array_size_in_bytes<float3>(this, socket);
|
||||
break;
|
||||
case SocketType::VECTOR_ARRAY:
|
||||
total_size += array_size_in_bytes<float3>(this, socket);
|
||||
break;
|
||||
case SocketType::POINT_ARRAY:
|
||||
total_size += array_size_in_bytes<float3>(this, socket);
|
||||
break;
|
||||
case SocketType::NORMAL_ARRAY:
|
||||
total_size += array_size_in_bytes<float3>(this, socket);
|
||||
break;
|
||||
case SocketType::POINT2_ARRAY:
|
||||
total_size += array_size_in_bytes<float2>(this, socket);
|
||||
break;
|
||||
case SocketType::STRING_ARRAY:
|
||||
total_size += array_size_in_bytes<ustring>(this, socket);
|
||||
break;
|
||||
case SocketType::TRANSFORM_ARRAY:
|
||||
total_size += array_size_in_bytes<Transform>(this, socket);
|
||||
break;
|
||||
case SocketType::NODE_ARRAY:
|
||||
total_size += array_size_in_bytes<void*>(this, socket);
|
||||
break;
|
||||
|
||||
case SocketType::UNDEFINED: break;
|
||||
}
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -92,6 +92,9 @@ struct Node
|
|||
/* compute hash of node and its socket values */
|
||||
void hash(MD5Hash& md5);
|
||||
|
||||
/* Get total size of this node. */
|
||||
size_t get_total_size_in_bytes() const;
|
||||
|
||||
ustring name;
|
||||
const NodeType *type;
|
||||
};
|
||||
|
|
|
@ -134,7 +134,7 @@ NodeType::~NodeType()
|
|||
|
||||
void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type type, int struct_offset,
|
||||
const void *default_value, const NodeEnum *enum_values,
|
||||
const NodeType **node_type, int flags, int extra_flags)
|
||||
const NodeType **node_type, int flags, int extra_flags)
|
||||
{
|
||||
SocketType socket;
|
||||
socket.name = name;
|
||||
|
|
|
@ -114,9 +114,9 @@ struct NodeType
|
|||
|
||||
void register_input(ustring name, ustring ui_name, SocketType::Type type,
|
||||
int struct_offset, const void *default_value,
|
||||
const NodeEnum *enum_values = NULL,
|
||||
const NodeType **node_type = NULL,
|
||||
int flags = 0, int extra_flags = 0);
|
||||
const NodeEnum *enum_values = NULL,
|
||||
const NodeType **node_type = NULL,
|
||||
int flags = 0, int extra_flags = 0);
|
||||
void register_output(ustring name, ustring ui_name, SocketType::Type type);
|
||||
|
||||
const SocketType *find_input(ustring name) const;
|
||||
|
|
|
@ -33,6 +33,7 @@ set(SRC
|
|||
session.cpp
|
||||
shader.cpp
|
||||
sobol.cpp
|
||||
stats.cpp
|
||||
svm.cpp
|
||||
tables.cpp
|
||||
tile.cpp
|
||||
|
@ -60,6 +61,7 @@ set(SRC_HEADERS
|
|||
session.h
|
||||
shader.h
|
||||
sobol.h
|
||||
stats.h
|
||||
svm.h
|
||||
tables.h
|
||||
tile.h
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "device/device.h"
|
||||
#include "render/image.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/stats.h"
|
||||
|
||||
#include "util/util_foreach.h"
|
||||
#include "util/util_logging.h"
|
||||
|
@ -30,20 +31,58 @@
|
|||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
/* Some helpers to silence warning in templated function. */
|
||||
static bool isfinite(uchar /*value*/)
|
||||
bool isfinite(uchar /*value*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static bool isfinite(half /*value*/)
|
||||
bool isfinite(half /*value*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static bool isfinite(uint16_t /*value*/)
|
||||
bool isfinite(uint16_t /*value*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The lower three bits of a device texture slot number indicate its type.
|
||||
* These functions convert the slot ids from ImageManager "images" ones
|
||||
* to device ones and vice verse.
|
||||
*/
|
||||
int type_index_to_flattened_slot(int slot, ImageDataType type)
|
||||
{
|
||||
return (slot << IMAGE_DATA_TYPE_SHIFT) | (type);
|
||||
}
|
||||
|
||||
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type)
|
||||
{
|
||||
*type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK);
|
||||
return flat_slot >> IMAGE_DATA_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
const char* name_from_type(ImageDataType type)
|
||||
{
|
||||
switch(type) {
|
||||
case IMAGE_DATA_TYPE_FLOAT4: return "float4";
|
||||
case IMAGE_DATA_TYPE_BYTE4: return "byte4";
|
||||
case IMAGE_DATA_TYPE_HALF4: return "half4";
|
||||
case IMAGE_DATA_TYPE_FLOAT: return "float";
|
||||
case IMAGE_DATA_TYPE_BYTE: return "byte";
|
||||
case IMAGE_DATA_TYPE_HALF: return "half";
|
||||
case IMAGE_DATA_TYPE_USHORT4: return "ushort4";
|
||||
case IMAGE_DATA_TYPE_USHORT: return "ushort";
|
||||
case IMAGE_DATA_NUM_TYPES:
|
||||
assert(!"System enumerator type, should never be used");
|
||||
return "";
|
||||
}
|
||||
assert(!"Unhandled image data type");
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ImageManager::ImageManager(const DeviceInfo& info)
|
||||
{
|
||||
need_update = true;
|
||||
|
@ -90,12 +129,12 @@ bool ImageManager::set_animation_frame_update(int frame)
|
|||
|
||||
device_memory *ImageManager::image_memory(int flat_slot)
|
||||
{
|
||||
ImageDataType type;
|
||||
int slot = flattened_slot_to_type_index(flat_slot, &type);
|
||||
ImageDataType type;
|
||||
int slot = flattened_slot_to_type_index(flat_slot, &type);
|
||||
|
||||
Image *img = images[type][slot];
|
||||
Image *img = images[type][slot];
|
||||
|
||||
return img->mem;
|
||||
return img->mem;
|
||||
}
|
||||
|
||||
bool ImageManager::get_image_metadata(int flat_slot,
|
||||
|
@ -133,10 +172,12 @@ bool ImageManager::get_image_metadata(const string& filename,
|
|||
|
||||
if(metadata.is_float) {
|
||||
metadata.is_linear = true;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4
|
||||
: IMAGE_DATA_TYPE_FLOAT;
|
||||
}
|
||||
else {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4
|
||||
: IMAGE_DATA_TYPE_BYTE;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -148,7 +189,8 @@ bool ImageManager::get_image_metadata(const string& filename,
|
|||
return false;
|
||||
}
|
||||
if(path_is_directory(filename)) {
|
||||
VLOG(1) << "File '" << filename << "' is a directory, can't use as image.";
|
||||
VLOG(1) << "File '" << filename
|
||||
<< "' is a directory, can't use as image.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -211,16 +253,20 @@ bool ImageManager::get_image_metadata(const string& filename,
|
|||
metadata.channels = spec.nchannels;
|
||||
|
||||
if(metadata.is_half) {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4
|
||||
: IMAGE_DATA_TYPE_HALF;
|
||||
}
|
||||
else if(metadata.is_float) {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4
|
||||
: IMAGE_DATA_TYPE_FLOAT;
|
||||
}
|
||||
else if(spec.format == TypeDesc::USHORT) {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4
|
||||
: IMAGE_DATA_TYPE_USHORT;
|
||||
}
|
||||
else {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE;
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4
|
||||
: IMAGE_DATA_TYPE_BYTE;
|
||||
}
|
||||
|
||||
in->close();
|
||||
|
@ -229,50 +275,6 @@ bool ImageManager::get_image_metadata(const string& filename,
|
|||
return true;
|
||||
}
|
||||
|
||||
int ImageManager::max_flattened_slot(ImageDataType type)
|
||||
{
|
||||
if(tex_num_images[type] == 0) {
|
||||
/* No textures for the type, no slots needs allocation. */
|
||||
return 0;
|
||||
}
|
||||
return type_index_to_flattened_slot(tex_num_images[type], type);
|
||||
}
|
||||
|
||||
/* The lower three bits of a device texture slot number indicate its type.
|
||||
* These functions convert the slot ids from ImageManager "images" ones
|
||||
* to device ones and vice verse.
|
||||
*/
|
||||
int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type)
|
||||
{
|
||||
return (slot << IMAGE_DATA_TYPE_SHIFT) | (type);
|
||||
}
|
||||
|
||||
int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type)
|
||||
{
|
||||
*type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK);
|
||||
return flat_slot >> IMAGE_DATA_TYPE_SHIFT;
|
||||
}
|
||||
|
||||
string ImageManager::name_from_type(int type)
|
||||
{
|
||||
if(type == IMAGE_DATA_TYPE_FLOAT4)
|
||||
return "float4";
|
||||
else if(type == IMAGE_DATA_TYPE_FLOAT)
|
||||
return "float";
|
||||
else if(type == IMAGE_DATA_TYPE_BYTE)
|
||||
return "byte";
|
||||
else if(type == IMAGE_DATA_TYPE_HALF4)
|
||||
return "half4";
|
||||
else if(type == IMAGE_DATA_TYPE_HALF)
|
||||
return "half";
|
||||
else if(type == IMAGE_DATA_TYPE_USHORT)
|
||||
return "ushort";
|
||||
else if(type == IMAGE_DATA_TYPE_USHORT4)
|
||||
return "ushort4";
|
||||
else
|
||||
return "byte4";
|
||||
}
|
||||
|
||||
static bool image_equals(ImageManager::Image *image,
|
||||
const string& filename,
|
||||
void *builtin_data,
|
||||
|
@ -344,14 +346,16 @@ int ImageManager::add_image(const string& filename,
|
|||
}
|
||||
|
||||
/* Count if we're over the limit.
|
||||
* Very unlikely, since max_num_images is insanely big. But better safe than sorry. */
|
||||
* Very unlikely, since max_num_images is insanely big. But better safe
|
||||
* than sorry.
|
||||
*/
|
||||
int tex_count = 0;
|
||||
for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
|
||||
tex_count += tex_num_images[type];
|
||||
}
|
||||
if(tex_count > max_num_images) {
|
||||
printf("ImageManager::add_image: Reached image limit (%d), skipping '%s'\n",
|
||||
max_num_images, filename.c_str());
|
||||
printf("ImageManager::add_image: Reached image limit (%d), "
|
||||
"skipping '%s'\n", max_num_images, filename.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -732,7 +736,8 @@ void ImageManager::device_load_image(Device *device,
|
|||
|
||||
/* Slot assignment */
|
||||
int flat_slot = type_index_to_flattened_slot(slot, type);
|
||||
img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type).c_str(), flat_slot);
|
||||
img->mem_name = string_printf("__tex_image_%s_%03d",
|
||||
name_from_type(type), flat_slot);
|
||||
|
||||
/* Free previous texture in slot. */
|
||||
if(img->mem) {
|
||||
|
@ -1071,4 +1076,15 @@ void ImageManager::device_free(Device *device)
|
|||
}
|
||||
}
|
||||
|
||||
void ImageManager::collect_statistics(RenderStats *stats)
|
||||
{
|
||||
for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) {
|
||||
foreach(const Image *image, images[type]) {
|
||||
stats->image.textures.add_entry(
|
||||
NamedSizeEntry(path_filename(image->filename),
|
||||
image->mem->memory_size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -29,6 +29,7 @@ CCL_NAMESPACE_BEGIN
|
|||
|
||||
class Device;
|
||||
class Progress;
|
||||
class RenderStats;
|
||||
class Scene;
|
||||
|
||||
class ImageMetaData {
|
||||
|
@ -93,6 +94,8 @@ public:
|
|||
|
||||
device_memory *image_memory(int flat_slot);
|
||||
|
||||
void collect_statistics(RenderStats *stats);
|
||||
|
||||
bool need_update;
|
||||
|
||||
/* NOTE: Here pixels_size is a size of storage, which equals to
|
||||
|
@ -153,16 +156,11 @@ private:
|
|||
int texture_limit,
|
||||
device_vector<DeviceType>& tex_img);
|
||||
|
||||
int max_flattened_slot(ImageDataType type);
|
||||
int type_index_to_flattened_slot(int slot, ImageDataType type);
|
||||
int flattened_slot_to_type_index(int flat_slot, ImageDataType *type);
|
||||
string name_from_type(int type);
|
||||
|
||||
void device_load_image(Device *device,
|
||||
Scene *scene,
|
||||
ImageDataType type,
|
||||
int slot,
|
||||
Progress *progess);
|
||||
Progress *progress);
|
||||
void device_free_image(Device *device,
|
||||
ImageDataType type,
|
||||
int slot);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "render/nodes.h"
|
||||
#include "render/object.h"
|
||||
#include "render/scene.h"
|
||||
#include "render/stats.h"
|
||||
|
||||
#include "kernel/osl/osl_globals.h"
|
||||
|
||||
|
@ -2015,8 +2016,8 @@ void MeshManager::device_update_displacement_images(Device *device,
|
|||
}
|
||||
|
||||
void MeshManager::device_update_volume_images(Device *device,
|
||||
Scene *scene,
|
||||
Progress& progress)
|
||||
Scene *scene,
|
||||
Progress& progress)
|
||||
{
|
||||
progress.set_status("Updating Volume Images");
|
||||
TaskPool pool;
|
||||
|
@ -2043,11 +2044,11 @@ void MeshManager::device_update_volume_images(Device *device,
|
|||
|
||||
foreach(int slot, volume_images) {
|
||||
pool.push(function_bind(&ImageManager::device_update_slot,
|
||||
image_manager,
|
||||
device,
|
||||
scene,
|
||||
slot,
|
||||
&progress));
|
||||
image_manager,
|
||||
device,
|
||||
scene,
|
||||
slot,
|
||||
&progress));
|
||||
}
|
||||
pool.wait_work();
|
||||
}
|
||||
|
@ -2276,6 +2277,15 @@ void MeshManager::tag_update(Scene *scene)
|
|||
scene->object_manager->need_update = true;
|
||||
}
|
||||
|
||||
void MeshManager::collect_statistics(const Scene *scene, RenderStats *stats)
|
||||
{
|
||||
foreach(Mesh *mesh, scene->meshes) {
|
||||
stats->mesh.geometry.add_entry(
|
||||
NamedSizeEntry(string(mesh->name.c_str()),
|
||||
mesh->get_total_size_in_bytes()));
|
||||
}
|
||||
}
|
||||
|
||||
bool Mesh::need_attribute(Scene *scene, AttributeStandard std)
|
||||
{
|
||||
if(std == ATTR_STD_NONE)
|
||||
|
|
|
@ -38,6 +38,7 @@ class Device;
|
|||
class DeviceScene;
|
||||
class Mesh;
|
||||
class Progress;
|
||||
class RenderStats;
|
||||
class Scene;
|
||||
class SceneParams;
|
||||
class AttributeRequest;
|
||||
|
@ -351,6 +352,8 @@ public:
|
|||
|
||||
void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress);
|
||||
|
||||
void collect_statistics(const Scene *scene, RenderStats *stats);
|
||||
|
||||
protected:
|
||||
/* Calculate verts/triangles/curves offsets in global arrays. */
|
||||
void mesh_calc_offset(Scene *scene);
|
||||
|
@ -381,8 +384,8 @@ protected:
|
|||
Progress& progress);
|
||||
|
||||
void device_update_volume_images(Device *device,
|
||||
Scene *scene,
|
||||
Progress& progress);
|
||||
Scene *scene,
|
||||
Progress& progress);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -379,4 +379,10 @@ void Scene::device_free()
|
|||
free_memory(false);
|
||||
}
|
||||
|
||||
void Scene::collect_statistics(RenderStats *stats)
|
||||
{
|
||||
mesh_manager->collect_statistics(this, stats);
|
||||
image_manager->collect_statistics(stats);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
|
|
@ -56,6 +56,7 @@ class ShaderManager;
|
|||
class Progress;
|
||||
class BakeManager;
|
||||
class BakeData;
|
||||
class RenderStats;
|
||||
|
||||
/* Scene Device Data */
|
||||
|
||||
|
@ -255,6 +256,8 @@ public:
|
|||
void reset();
|
||||
void device_free();
|
||||
|
||||
void collect_statistics(RenderStats *stats);
|
||||
|
||||
protected:
|
||||
/* Check if some heavy data worth logging was updated.
|
||||
* Mainly used to suppress extra annoying logging.
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright 2011-2018 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/stats.h"
|
||||
#include "util/util_algorithm.h"
|
||||
#include "util/util_foreach.h"
|
||||
#include "util/util_string.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static int kIndentNumSpaces = 2;
|
||||
|
||||
/* Named size entry. */
|
||||
|
||||
namespace {
|
||||
|
||||
bool namedSizeEntryComparator(const NamedSizeEntry& a, const NamedSizeEntry& b)
|
||||
{
|
||||
/* We sort in descending order. */
|
||||
return a.size > b.size;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NamedSizeEntry::NamedSizeEntry()
|
||||
: name(""),
|
||||
size(0) {
|
||||
}
|
||||
|
||||
NamedSizeEntry::NamedSizeEntry(const string& name, size_t size)
|
||||
: name(name),
|
||||
size(size) {
|
||||
}
|
||||
|
||||
/* Named size statistics. */
|
||||
|
||||
NamedSizeStats::NamedSizeStats()
|
||||
: total_size(0) {
|
||||
}
|
||||
|
||||
void NamedSizeStats::add_entry(const NamedSizeEntry& entry) {
|
||||
total_size += entry.size;
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
string NamedSizeStats::full_report(int indent_level)
|
||||
{
|
||||
const string indent(indent_level * kIndentNumSpaces, ' ');
|
||||
const string double_indent = indent + indent;
|
||||
string result = "";
|
||||
result += string_printf("%sTotal memory: %s (%s)\n",
|
||||
indent.c_str(),
|
||||
string_human_readable_size(total_size).c_str(),
|
||||
string_human_readable_number(total_size).c_str());
|
||||
sort(entries.begin(), entries.end(), namedSizeEntryComparator);
|
||||
foreach(const NamedSizeEntry& entry, entries) {
|
||||
result += string_printf(
|
||||
"%s%-32s %s (%s)\n",
|
||||
double_indent.c_str(),
|
||||
entry.name.c_str(),
|
||||
string_human_readable_size(entry.size).c_str(),
|
||||
string_human_readable_number(entry.size).c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Mesh statistics. */
|
||||
|
||||
MeshStats::MeshStats() {
|
||||
}
|
||||
|
||||
string MeshStats::full_report(int indent_level)
|
||||
{
|
||||
const string indent(indent_level * kIndentNumSpaces, ' ');
|
||||
string result = "";
|
||||
result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Image statistics. */
|
||||
|
||||
ImageStats::ImageStats() {
|
||||
}
|
||||
|
||||
string ImageStats::full_report(int indent_level)
|
||||
{
|
||||
const string indent(indent_level * kIndentNumSpaces, ' ');
|
||||
string result = "";
|
||||
result += indent + "Textures:\n" + textures.full_report(indent_level + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Overall statistics. */
|
||||
|
||||
RenderStats::RenderStats() {
|
||||
}
|
||||
|
||||
string RenderStats::full_report()
|
||||
{
|
||||
string result = "";
|
||||
result += "Mesh statistics:\n" + mesh.full_report(1);
|
||||
result += "Image statistics:\n" + image.full_report(1);
|
||||
return result;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2011-2018 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.
|
||||
*/
|
||||
|
||||
#ifndef __RENDER_STATS_H__
|
||||
#define __RENDER_STATS_H__
|
||||
|
||||
#include "util/util_string.h"
|
||||
#include "util/util_vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Named statistics entry, which corresponds to a size. There is no real
|
||||
* semantic around the units of size, it just should be the same for all
|
||||
* entries.
|
||||
*
|
||||
* This is a generic entry foi all size-related statistics, which helps
|
||||
* avoiding duplicating code for things like sorting.
|
||||
*/
|
||||
class NamedSizeEntry {
|
||||
public:
|
||||
NamedSizeEntry();
|
||||
NamedSizeEntry(const string& name, size_t size);
|
||||
|
||||
string name;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Container of named size entries. Used, for example, to store per-mesh memory
|
||||
* usage statistics. But also keeps track of overall memory usage of the
|
||||
* container.
|
||||
*/
|
||||
class NamedSizeStats {
|
||||
public:
|
||||
NamedSizeStats();
|
||||
|
||||
/* Add entry to the statistics. */
|
||||
void add_entry(const NamedSizeEntry& entry);
|
||||
|
||||
/* Generate full human-readable report. */
|
||||
string full_report(int indent_level = 0);
|
||||
|
||||
/* Total size of all entries. */
|
||||
size_t total_size;
|
||||
|
||||
/* NOTE: Is fine to read directly, but for adding use add_entry(), which
|
||||
* makes sure all accumulating values are properly updated.
|
||||
*/
|
||||
vector<NamedSizeEntry> entries;
|
||||
};
|
||||
|
||||
/* Statistics about mesh in the render database. */
|
||||
class MeshStats {
|
||||
public:
|
||||
MeshStats();
|
||||
|
||||
/* Generate full human-readable report. */
|
||||
string full_report(int indent_level = 0);
|
||||
|
||||
/* Input geometry statistics, this is what is coming as an input to render
|
||||
* from. say, Blender. This does not include runtime or engine specific
|
||||
* memory like BVH.
|
||||
*/
|
||||
NamedSizeStats geometry;
|
||||
};
|
||||
|
||||
/* Statistics about images held in memory. */
|
||||
class ImageStats {
|
||||
public:
|
||||
ImageStats();
|
||||
|
||||
/* Generate full human-readable report. */
|
||||
string full_report(int indent_level = 0);
|
||||
|
||||
NamedSizeStats textures;
|
||||
};
|
||||
|
||||
/* Render process statistics. */
|
||||
class RenderStats {
|
||||
public:
|
||||
RenderStats();
|
||||
|
||||
/* Return full report as string. */
|
||||
string full_report();
|
||||
|
||||
MeshStats mesh;
|
||||
ImageStats image;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __RENDER_STATS_H__ */
|
Loading…
Reference in New Issue