Cycles: Synchronize images after building mesh BVH

This way memory overhead caused by the BVH building is not so visible and peak
memory usage will be reduced.

Implementing this idea is not so straightforward actually, because we need to
synchronize images used for true displacement before meshes. Detecting whether
image is used for true displacement is not so striaghtforward, so for now all
all displacement types will synchronize images used for them.

Such change brings memory usage from 4.1G to 4.0G with the 01_01_01_D scene
from gooseberry. With 01_01_01_G scene it's 7.6G vs. 6.8G (before and after
the patch).

Reviewers: campbellbarton, juicyfruit, brecht

Subscribers: eyecandy

Differential Revision: https://developer.blender.org/D1217
This commit is contained in:
Sergey Sharybin 2015-04-02 20:37:57 +05:00
parent b07c630676
commit cd44449578
8 changed files with 120 additions and 11 deletions

@ -81,6 +81,7 @@ enum ShaderNodeSpecialType {
SHADER_SPECIAL_TYPE_GEOMETRY,
SHADER_SPECIAL_TYPE_SCRIPT,
SHADER_SPECIAL_TYPE_BACKGROUND,
SHADER_SPECIAL_TYPE_IMAGE_SLOT,
};
/* Enum

@ -791,6 +791,33 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress&
need_update = false;
}
void ImageManager::device_update_slot(Device *device,
DeviceScene *dscene,
int slot,
Progress *progress)
{
Image *image;
if(slot >= tex_image_byte_start) {
int byte_slot = slot - tex_image_byte_start;
assert(images[byte_slot] != NULL);
image = images[byte_slot];
}
else {
assert(float_images[slot] != NULL);
image = float_images[slot];
}
if(image->users == 0) {
device_free_image(device, dscene, slot);
}
else if(image->need_load) {
if(!osl_texture_system || float_images[slot]->builtin_data)
device_load_image(device,
dscene,
slot,
progress);
}
}
void ImageManager::device_pack_images(Device *device,
DeviceScene *dscene,
Progress& /*progess*/)

@ -63,6 +63,7 @@ public:
bool is_float_image(const string& filename, void *builtin_data, bool& is_linear);
void device_update(Device *device, DeviceScene *dscene, Progress& progress);
void device_update_slot(Device *device, DeviceScene *dscene, int slot, Progress *progress);
void device_free(Device *device, DeviceScene *dscene);
void device_free_builtin(Device *device, DeviceScene *dscene);

@ -20,9 +20,11 @@
#include "camera.h"
#include "curves.h"
#include "device.h"
#include "graph.h"
#include "shader.h"
#include "light.h"
#include "mesh.h"
#include "nodes.h"
#include "object.h"
#include "scene.h"
@ -1148,6 +1150,55 @@ void MeshManager::device_update_flags(Device * /*device*/,
need_flags_update = false;
}
void MeshManager::device_update_displacement_images(Device *device,
DeviceScene *dscene,
Scene *scene,
Progress& progress)
{
progress.set_status("Updating Displacement Images");
TaskPool pool;
ImageManager *image_manager = scene->image_manager;
set<int> bump_images;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
foreach(uint shader_index, mesh->used_shaders) {
Shader *shader = scene->shaders[shader_index];
if(shader->graph_bump == NULL) {
continue;
}
foreach(ShaderNode* node, shader->graph_bump->nodes) {
if(node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
continue;
}
if(device->info.pack_images) {
/* If device requires packed images we need to update all
* images now, even if they're not used for displacement.
*/
image_manager->device_update(device,
dscene,
progress);
return;
}
ImageSlotNode *image_node = static_cast<ImageSlotNode*>(node);
int slot = image_node->slot;
if(slot != -1) {
bump_images.insert(slot);
}
}
}
}
}
foreach(int slot, bump_images) {
pool.push(function_bind(&ImageManager::device_update_slot,
image_manager,
device,
dscene,
slot,
&progress));
}
pool.wait_work();
}
void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
{
VLOG(1) << "Total " << scene->meshes.size() << " meshes.";
@ -1170,6 +1221,21 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
}
}
/* Update images needed for true displacement. */
bool need_displacement_images = false;
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update &&
mesh->displacement_method != Mesh::DISPLACE_BUMP)
{
need_displacement_images = true;
break;
}
}
if(need_displacement_images) {
VLOG(1) << "Updating images used for true displacement.";
device_update_displacement_images(device, dscene, scene, progress);
}
/* device update */
device_free(device, dscene);

@ -167,6 +167,7 @@ public:
void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);

@ -186,7 +186,7 @@ ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
ImageTextureNode::ImageTextureNode()
: TextureNode("image_texture")
: ImageSlotTextureNode("image_texture")
{
image_manager = NULL;
slot = -1;
@ -380,7 +380,7 @@ ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
EnvironmentTextureNode::EnvironmentTextureNode()
: TextureNode("environment_texture")
: ImageSlotTextureNode("environment_texture")
{
image_manager = NULL;
slot = -1;

@ -55,13 +55,28 @@ public:
/* Nodes */
/* Any node which uses image manager's slot should be a subclass of this one. */
class ImageSlotNode : public ShaderNode {
public:
ImageSlotNode(const char *name_) : ShaderNode(name_) {
special_type = SHADER_SPECIAL_TYPE_IMAGE_SLOT;
}
int slot;
};
class TextureNode : public ShaderNode {
public:
TextureNode(const char *name_) : ShaderNode(name_) {}
TextureMapping tex_mapping;
};
class ImageTextureNode : public TextureNode {
class ImageSlotTextureNode : public ImageSlotNode {
public:
ImageSlotTextureNode(const char *name_) : ImageSlotNode(name_) {}
TextureMapping tex_mapping;
};
class ImageTextureNode : public ImageSlotTextureNode {
public:
SHADER_NODE_NO_CLONE_CLASS(ImageTextureNode)
~ImageTextureNode();
@ -69,7 +84,6 @@ public:
void attributes(Shader *shader, AttributeRequestSet *attributes);
ImageManager *image_manager;
int slot;
int is_float;
bool is_linear;
bool use_alpha;
@ -85,7 +99,7 @@ public:
static ShaderEnum projection_enum;
};
class EnvironmentTextureNode : public TextureNode {
class EnvironmentTextureNode : public ImageSlotTextureNode {
public:
SHADER_NODE_NO_CLONE_CLASS(EnvironmentTextureNode)
~EnvironmentTextureNode();
@ -93,7 +107,6 @@ public:
void attributes(Shader *shader, AttributeRequestSet *attributes);
ImageManager *image_manager;
int slot;
int is_float;
bool is_linear;
bool use_alpha;

@ -160,11 +160,6 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Images");
image_manager->device_update(device, &dscene, progress);
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Background");
background->device_update(device, &dscene, this);
@ -195,6 +190,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Images");
image_manager->device_update(device, &dscene, progress);
if(progress.get_cancel() || device->have_error()) return;
progress.set_status("Updating Camera Volume");
camera->device_update_volume(device, &dscene, this);