Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2018-07-27 18:21:43 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2018-07-27 18:21:43 +0300
commit31657fef40d1a99e96b4a318a6ca6b4b5b68539d (patch)
tree0c27962cb3f4fdb286252721f3aeb89c379c22f2
parentaf2a801731441d132b81bd109c999bde3db58a88 (diff)
parent84d47e3685c7ccfeaf2dd41ab64d1b642f157add (diff)
Merge branch 'master' into blender2.8
-rw-r--r--intern/cycles/blender/addon/engine.py10
-rw-r--r--intern/cycles/blender/blender_python.cpp9
-rw-r--r--intern/cycles/blender/blender_session.cpp8
-rw-r--r--intern/cycles/blender/blender_session.h2
-rw-r--r--intern/cycles/graph/node.cpp85
-rw-r--r--intern/cycles/graph/node.h3
-rw-r--r--intern/cycles/graph/node_type.cpp2
-rw-r--r--intern/cycles/graph/node_type.h6
-rw-r--r--intern/cycles/render/CMakeLists.txt2
-rw-r--r--intern/cycles/render/image.cpp140
-rw-r--r--intern/cycles/render/image.h10
-rw-r--r--intern/cycles/render/mesh.cpp24
-rw-r--r--intern/cycles/render/mesh.h7
-rw-r--r--intern/cycles/render/scene.cpp6
-rw-r--r--intern/cycles/render/scene.h3
-rw-r--r--intern/cycles/render/stats.cpp119
-rw-r--r--intern/cycles/render/stats.h104
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__ */