diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-07-27 18:21:43 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2018-07-27 18:21:43 +0300 |
commit | 31657fef40d1a99e96b4a318a6ca6b4b5b68539d (patch) | |
tree | 0c27962cb3f4fdb286252721f3aeb89c379c22f2 /intern | |
parent | af2a801731441d132b81bd109c999bde3db58a88 (diff) | |
parent | 84d47e3685c7ccfeaf2dd41ab64d1b642f157add (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'intern')
-rw-r--r-- | intern/cycles/blender/addon/engine.py | 10 | ||||
-rw-r--r-- | intern/cycles/blender/blender_python.cpp | 9 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/blender/blender_session.h | 2 | ||||
-rw-r--r-- | intern/cycles/graph/node.cpp | 85 | ||||
-rw-r--r-- | intern/cycles/graph/node.h | 3 | ||||
-rw-r--r-- | intern/cycles/graph/node_type.cpp | 2 | ||||
-rw-r--r-- | intern/cycles/graph/node_type.h | 6 | ||||
-rw-r--r-- | intern/cycles/render/CMakeLists.txt | 2 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 140 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 10 | ||||
-rw-r--r-- | intern/cycles/render/mesh.cpp | 24 | ||||
-rw-r--r-- | intern/cycles/render/mesh.h | 7 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 6 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 3 | ||||
-rw-r--r-- | intern/cycles/render/stats.cpp | 119 | ||||
-rw-r--r-- | intern/cycles/render/stats.h | 104 |
17 files changed, 454 insertions, 86 deletions
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 60057818e37..476cf975737 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -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(): diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 4c199f4838f..a79c28e43aa 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -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, ""}, diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 1a4b26128e3..05adb6f5fe0 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -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; } diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 1d727e416a0..2be57f293b4 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -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, diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index 45ffc8d7d6b..5960d9aa7d5 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -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 diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h index a738bfe197e..11695a8631d 100644 --- a/intern/cycles/graph/node.h +++ b/intern/cycles/graph/node.h @@ -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; }; diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index 671ae2d815a..e045777e969 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -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; diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index d4e2dbceff6..1d565794b27 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -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; diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b7248354abd..7d2220f37f9 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -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 diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 28ef026135a..2865b0e5e97 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -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 diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index c9667fb77a9..0bf06c322d0 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -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); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 7a9d604244d..ade575a52d6 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -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) diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index e7dc1c8e5cf..444f03a3664 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -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 diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 1d65ef65980..9f93fed139c 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -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 diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 713eba623b1..dd8069537eb 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -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. diff --git a/intern/cycles/render/stats.cpp b/intern/cycles/render/stats.cpp new file mode 100644 index 00000000000..101d33fcf65 --- /dev/null +++ b/intern/cycles/render/stats.cpp @@ -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 diff --git a/intern/cycles/render/stats.h b/intern/cycles/render/stats.h new file mode 100644 index 00000000000..72d5f1dd93d --- /dev/null +++ b/intern/cycles/render/stats.h @@ -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__ */ |