diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index b39b3dae324..301938aa158 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -81,6 +81,7 @@ enum ShaderNodeSpecialType { SHADER_SPECIAL_TYPE_GEOMETRY, SHADER_SPECIAL_TYPE_SCRIPT, SHADER_SPECIAL_TYPE_BACKGROUND, + SHADER_SPECIAL_TYPE_IMAGE_SLOT, }; /* Enum diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 6e63b433709..f0608965d09 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -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*/) diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 1045b4532e4..70cc4935daa 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -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); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 74ea3c94593..b6f3cb3502b 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -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 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(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); diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 6eaafea8729..76c186a3feb 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -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); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 40bb82c6330..747bafcc904 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -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; diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 0ec0fce512f..ee984773dcf 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -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; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 524574f096d..71741c0dfd1 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -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);