diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-09-04 17:29:07 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-09-04 17:29:07 +0400 |
commit | adea12cb01e4c4f18f345dfbbf49e9e622192e4e (patch) | |
tree | b43018344c696e4d59437fabc7f17f5b9d6a8e80 /intern/cycles/render | |
parent | 68563134d4800be4eb46aa6b598fd719cdaf2980 (diff) |
Cycles: merge of changes from tomato branch.
Regular rendering now works tiled, and supports save buffers to save memory
during render and cache render results.
Brick texture node by Thomas.
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Textures#Brick_Texture
Image texture Blended Box Mapping.
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/Textures#Image_Texture
http://mango.blender.org/production/blended_box/
Various bug fixes by Sergey and Campbell.
* Fix for reading freed memory in some node setups.
* Fix incorrect memory read when synchronizing mesh motion.
* Fix crash appearing when direct light usage is different on different layers.
* Fix for vector pass gives wrong result in some circumstances.
* Fix for wrong resolution used for rendering Render Layer node.
* Option to cancel rendering when doing initial synchronization.
* No more texture limit when using CPU render.
* Many fixes for new tiled rendering.
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/buffers.cpp | 25 | ||||
-rw-r--r-- | intern/cycles/render/buffers.h | 29 | ||||
-rw-r--r-- | intern/cycles/render/camera.cpp | 12 | ||||
-rw-r--r-- | intern/cycles/render/camera.h | 1 | ||||
-rw-r--r-- | intern/cycles/render/graph.cpp | 14 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 75 | ||||
-rw-r--r-- | intern/cycles/render/image.h | 13 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 135 | ||||
-rw-r--r-- | intern/cycles/render/nodes.h | 11 | ||||
-rw-r--r-- | intern/cycles/render/scene.cpp | 5 | ||||
-rw-r--r-- | intern/cycles/render/scene.h | 7 | ||||
-rw-r--r-- | intern/cycles/render/session.cpp | 220 | ||||
-rw-r--r-- | intern/cycles/render/session.h | 27 | ||||
-rw-r--r-- | intern/cycles/render/tile.cpp | 138 | ||||
-rw-r--r-- | intern/cycles/render/tile.h | 28 |
15 files changed, 588 insertions, 152 deletions
diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index a79a3591e0f..51568f65323 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -74,6 +74,29 @@ int BufferParams::get_passes_size() return align_up(size, 4); } +/* Render Buffer Task */ + +RenderTile::RenderTile() +{ + x = 0; + y = 0; + w = 0; + h = 0; + + start_sample = 0; + num_samples = 0; + resolution = 0; + + offset = 0; + stride = 0; + + buffer = 0; + rng_state = 0; + rgba = 0; + + buffers = NULL; +} + /* Render Buffers */ RenderBuffers::RenderBuffers(Device *device_) @@ -135,7 +158,7 @@ bool RenderBuffers::copy_from_device() return true; } -bool RenderBuffers::get_pass(PassType type, float exposure, int sample, int components, float *pixels) +bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels) { int pass_offset = 0; diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h index 78712ed89ef..ee0d78a1cd8 100644 --- a/intern/cycles/render/buffers.h +++ b/intern/cycles/render/buffers.h @@ -67,12 +67,11 @@ class RenderBuffers { public: /* buffer parameters */ BufferParams params; + /* float buffer */ device_vector<float> buffer; /* random number generator state */ device_vector<uint> rng_state; - /* mutex, must be locked manually by callers */ - thread_mutex mutex; RenderBuffers(Device *device); ~RenderBuffers(); @@ -80,7 +79,7 @@ public: void reset(Device *device, BufferParams& params); bool copy_from_device(); - bool get_pass(PassType type, float exposure, int sample, int components, float *pixels); + bool get_pass_rect(PassType type, float exposure, int sample, int components, float *pixels); protected: void device_free(); @@ -105,8 +104,6 @@ public: bool transparent; /* byte buffer for tonemapped result */ device_vector<uchar4> rgba; - /* mutex, must be locked manually by callers */ - thread_mutex mutex; DisplayBuffer(Device *device); ~DisplayBuffer(); @@ -124,6 +121,28 @@ protected: Device *device; }; +/* Render Tile + * Rendering task on a buffer */ + +class RenderTile { +public: + int x, y, w, h; + int start_sample; + int num_samples; + int sample; + int resolution; + int offset; + int stride; + + device_ptr buffer; + device_ptr rng_state; + device_ptr rgba; + + RenderBuffers *buffers; + + RenderTile(); +}; + CCL_NAMESPACE_END #endif /* __BUFFERS_H__ */ diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 55a0f23f8d0..e44caa90f12 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -75,6 +75,7 @@ Camera::Camera() need_update = true; need_device_update = true; + previous_need_motion = -1; } Camera::~Camera() @@ -140,8 +141,17 @@ void Camera::update() void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) { + Scene::MotionType need_motion = scene->need_motion(); + update(); + if (previous_need_motion != need_motion) { + /* scene's motion model could have been changed since previous device + * camera update this could happen for example in case when one render + * layer has got motion pass and another not */ + need_device_update = true; + } + if(!need_device_update) return; @@ -159,7 +169,6 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) kcam->worldtocamera = transform_inverse(cameratoworld); /* camera motion */ - Scene::MotionType need_motion = scene->need_motion(); kcam->have_motion = 0; if(need_motion == Scene::MOTION_PASS) { @@ -226,6 +235,7 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene) kcam->cliplength = (farclip == FLT_MAX)? FLT_MAX: farclip - nearclip; need_device_update = false; + previous_need_motion = need_motion; } void Camera::device_free(Device *device, DeviceScene *dscene) diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index d2a3cce1817..82852bde5e0 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -91,6 +91,7 @@ public: /* update */ bool need_update; bool need_device_update; + int previous_need_motion; /* functions */ Camera(); diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 6ed0812a239..20fbfa0cf27 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -402,6 +402,20 @@ void ShaderGraph::clean() /* break cycles */ break_cycles(output(), visited, on_stack); + /* disconnect unused nodes */ + foreach(ShaderNode *node, nodes) { + if(!visited[node->id]) { + foreach(ShaderInput *to, node->inputs) { + ShaderOutput *from = to->link; + + if (from) { + to->link = NULL; + from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end()); + } + } + } + } + /* remove unused nodes */ foreach(ShaderNode *node, nodes) { if(visited[node->id]) diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 1af0972ecf9..4ee024dd52a 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -36,6 +36,10 @@ ImageManager::ImageManager() need_update = true; pack_images = false; osl_texture_system = NULL; + + tex_num_images = TEX_NUM_IMAGES; + tex_num_float_images = TEX_NUM_FLOAT_IMAGES; + tex_image_byte_start = TEX_IMAGE_BYTE_START; } ImageManager::~ImageManager() @@ -56,6 +60,13 @@ void ImageManager::set_osl_texture_system(void *texture_system) osl_texture_system = texture_system; } +void ImageManager::set_extended_image_limits(void) +{ + tex_num_images = TEX_EXTENDED_NUM_IMAGES; + tex_num_float_images = TEX_EXTENDED_NUM_FLOAT_IMAGES; + tex_image_byte_start = TEX_EXTENDED_IMAGE_BYTE_START; +} + static bool is_float_image(const string& filename) { ImageInput *in = ImageInput::create(filename); @@ -97,7 +108,7 @@ int ImageManager::add_image(const string& filename, bool& is_float) for(slot = 0; slot < float_images.size(); slot++) { if(float_images[slot] && float_images[slot]->filename == filename) { float_images[slot]->users++; - return slot+TEX_IMAGE_FLOAT_START; + return slot; } } @@ -110,8 +121,8 @@ int ImageManager::add_image(const string& filename, bool& is_float) if(slot == float_images.size()) { /* max images limit reached */ if(float_images.size() == TEX_NUM_FLOAT_IMAGES) { - printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n", - TEX_NUM_IMAGES, filename.c_str()); + printf("ImageManager::add_image: float image limit reached %d, skipping '%s'\n", + tex_num_float_images, filename.c_str()); return -1; } @@ -125,14 +136,12 @@ int ImageManager::add_image(const string& filename, bool& is_float) img->users = 1; float_images[slot] = img; - /* report slot out of total set of textures */ - slot += TEX_IMAGE_FLOAT_START; } else { for(slot = 0; slot < images.size(); slot++) { if(images[slot] && images[slot]->filename == filename) { images[slot]->users++; - return slot; + return slot+tex_image_byte_start; } } @@ -144,9 +153,9 @@ int ImageManager::add_image(const string& filename, bool& is_float) if(slot == images.size()) { /* max images limit reached */ - if(images.size() == TEX_NUM_IMAGES) { + if(images.size() == tex_num_images) { printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n", - TEX_NUM_IMAGES, filename.c_str()); + tex_num_images, filename.c_str()); return -1; } @@ -160,6 +169,8 @@ int ImageManager::add_image(const string& filename, bool& is_float) img->users = 1; images[slot] = img; + + slot += tex_image_byte_start; } need_update = true; @@ -340,20 +351,20 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl Image *img; bool is_float; - if(slot < TEX_IMAGE_FLOAT_START) { - img = images[slot]; + if(slot >= tex_image_byte_start) { + img = images[slot - tex_image_byte_start]; is_float = false; } else { - img = float_images[slot - TEX_IMAGE_FLOAT_START]; + img = float_images[slot]; is_float = true; } if(is_float) { - string filename = path_filename(float_images[slot - TEX_IMAGE_FLOAT_START]->filename); + string filename = path_filename(float_images[slot]->filename); progress->set_status("Updating Images", "Loading " + filename); - device_vector<float4>& tex_img = dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START]; + device_vector<float4>& tex_img = dscene->tex_float_image[slot]; if(tex_img.device_pointer) device->tex_free(tex_img); @@ -377,10 +388,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl device->tex_alloc(name.c_str(), tex_img, true, true); } else { - string filename = path_filename(images[slot]->filename); + string filename = path_filename(images[slot - tex_image_byte_start]->filename); progress->set_status("Updating Images", "Loading " + filename); - device_vector<uchar4>& tex_img = dscene->tex_image[slot]; + device_vector<uchar4>& tex_img = dscene->tex_image[slot - tex_image_byte_start]; if(tex_img.device_pointer) device->tex_free(tex_img); @@ -412,12 +423,12 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int sl Image *img; bool is_float; - if(slot < TEX_IMAGE_FLOAT_START) { - img = images[slot]; + if(slot >= tex_image_byte_start) { + img = images[slot - tex_image_byte_start]; is_float = false; } else { - img = float_images[slot - TEX_IMAGE_FLOAT_START]; + img = float_images[slot]; is_float = true; } @@ -429,18 +440,18 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, int sl #endif } else if(is_float) { - device->tex_free(dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START]); - dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START].clear(); + device->tex_free(dscene->tex_float_image[slot]); + dscene->tex_float_image[slot].clear(); - delete float_images[slot - TEX_IMAGE_FLOAT_START]; - float_images[slot - TEX_IMAGE_FLOAT_START] = NULL; + delete float_images[slot]; + float_images[slot] = NULL; } else { - device->tex_free(dscene->tex_image[slot]); - dscene->tex_image[slot].clear(); + device->tex_free(dscene->tex_image[slot - tex_image_byte_start]); + dscene->tex_image[slot - tex_image_byte_start].clear(); - delete images[slot]; - images[slot] = NULL; + delete images[slot - tex_image_byte_start]; + images[slot - tex_image_byte_start] = NULL; } } } @@ -457,11 +468,11 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& continue; if(images[slot]->users == 0) { - device_free_image(device, dscene, slot); + device_free_image(device, dscene, slot + tex_image_byte_start); } else if(images[slot]->need_load) { if(!osl_texture_system) - pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress)); + pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + tex_image_byte_start, &progress)); } } @@ -470,11 +481,11 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& continue; if(float_images[slot]->users == 0) { - device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START); + device_free_image(device, dscene, slot); } else if(float_images[slot]->need_load) { if(!osl_texture_system) - pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + TEX_IMAGE_FLOAT_START, &progress)); + pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress)); } } @@ -526,9 +537,9 @@ void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progr void ImageManager::device_free(Device *device, DeviceScene *dscene) { for(size_t slot = 0; slot < images.size(); slot++) - device_free_image(device, dscene, slot); + device_free_image(device, dscene, slot + tex_image_byte_start); for(size_t slot = 0; slot < float_images.size(); slot++) - device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START); + device_free_image(device, dscene, slot); device->tex_free(dscene->tex_image_packed); dscene->tex_image_packed.clear(); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index ef046cfcafb..04a705c27bf 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -28,8 +28,11 @@ CCL_NAMESPACE_BEGIN #define TEX_NUM_FLOAT_IMAGES 5 #define TEX_NUM_IMAGES 95 -#define TEX_IMAGE_MAX (TEX_NUM_IMAGES + TEX_NUM_FLOAT_IMAGES) -#define TEX_IMAGE_FLOAT_START TEX_NUM_IMAGES +#define TEX_IMAGE_BYTE_START TEX_NUM_FLOAT_IMAGES + +#define TEX_EXTENDED_NUM_FLOAT_IMAGES 5 +#define TEX_EXTENDED_NUM_IMAGES 512 +#define TEX_EXTENDED_IMAGE_BYTE_START TEX_EXTENDED_NUM_FLOAT_IMAGES /* color to use when textures are not found */ #define TEX_IMAGE_MISSING_R 1 @@ -55,9 +58,15 @@ public: void set_osl_texture_system(void *texture_system); void set_pack_images(bool pack_images_); + void set_extended_image_limits(void); + bool need_update; private: + int tex_num_images; + int tex_num_float_images; + int tex_image_byte_start; + struct Image { string filename; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index d5ca20e6af1..da511b2d2f4 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -112,7 +112,18 @@ static ShaderEnum color_space_init() return enm; } +static ShaderEnum image_projection_init() +{ + ShaderEnum enm; + + enm.insert("Flat", 0); + enm.insert("Box", 1); + + return enm; +} + ShaderEnum ImageTextureNode::color_space_enum = color_space_init(); +ShaderEnum ImageTextureNode::projection_enum = image_projection_init(); ImageTextureNode::ImageTextureNode() : TextureNode("image_texture") @@ -122,6 +133,8 @@ ImageTextureNode::ImageTextureNode() is_float = false; filename = ""; color_space = ustring("Color"); + projection = ustring("Flat");; + projection_blend = 0.0f; add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV); add_output("Color", SHADER_SOCKET_COLOR); @@ -169,13 +182,25 @@ void ImageTextureNode::compile(SVMCompiler& compiler) tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset); } - compiler.add_node(NODE_TEX_IMAGE, - slot, - compiler.encode_uchar4( - vector_offset, - color_out->stack_offset, - alpha_out->stack_offset, - srgb)); + if(projection == "Flat") { + compiler.add_node(NODE_TEX_IMAGE, + slot, + compiler.encode_uchar4( + vector_offset, + color_out->stack_offset, + alpha_out->stack_offset, + srgb)); + } + else { + compiler.add_node(NODE_TEX_IMAGE_BOX, + slot, + compiler.encode_uchar4( + vector_offset, + color_out->stack_offset, + alpha_out->stack_offset, + srgb), + __float_as_int(projection_blend)); + } if(vector_offset != vector_in->stack_offset) compiler.stack_clear_offset(vector_in->type, vector_offset); @@ -205,7 +230,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) /* Environment Texture */ -static ShaderEnum projection_init() +static ShaderEnum env_projection_init() { ShaderEnum enm; @@ -216,7 +241,7 @@ static ShaderEnum projection_init() } ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init(); -ShaderEnum EnvironmentTextureNode::projection_enum = projection_init(); +ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init(); EnvironmentTextureNode::EnvironmentTextureNode() : TextureNode("environment_texture") @@ -873,6 +898,98 @@ void CheckerTextureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_checker_texture"); } +/* Brick Texture */ + +BrickTextureNode::BrickTextureNode() +: TextureNode("brick_texture") +{ + offset = 0.5f; + offset_frequency = 2; + squash = 1.0f; + squash_frequency = 2; + + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED); + add_input("Color1", SHADER_SOCKET_COLOR); + add_input("Color2", SHADER_SOCKET_COLOR); + add_input("Mortar", SHADER_SOCKET_COLOR); + add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f); + add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f); + add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f); + add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f); + + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void BrickTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *color1_in = input("Color1"); + ShaderInput *color2_in = input("Color2"); + ShaderInput *mortar_in = input("Mortar"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *mortar_size_in = input("Mortar Size"); + ShaderInput *bias_in = input("Bias"); + ShaderInput *brick_width_in = input("Brick Width"); + ShaderInput *row_height_in = input("Row Height"); + + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); + + compiler.stack_assign(vector_in); + compiler.stack_assign(color1_in); + compiler.stack_assign(color2_in); + compiler.stack_assign(mortar_in); + if(scale_in->link) compiler.stack_assign(scale_in); + if(mortar_size_in->link) compiler.stack_assign(mortar_size_in); + if(bias_in->link) compiler.stack_assign(bias_in); + if(brick_width_in->link) compiler.stack_assign(brick_width_in); + if(row_height_in->link) compiler.stack_assign(row_height_in); + + int vector_offset = vector_in->stack_offset; + + if(!tex_mapping.skip()) { + vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR); + tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset); + } + + if(!color_out->links.empty()) + compiler.stack_assign(color_out); + if(!fac_out->links.empty()) + compiler.stack_assign(fac_out); + + compiler.add_node(NODE_TEX_BRICK, + compiler.encode_uchar4(vector_offset, + color1_in->stack_offset, color2_in->stack_offset, mortar_in->stack_offset), + compiler.encode_uchar4(scale_in->stack_offset, + mortar_size_in->stack_offset, bias_in->stack_offset, brick_width_in->stack_offset), + compiler.encode_uchar4(row_height_in->stack_offset, + color_out->stack_offset, fac_out->stack_offset)); + + compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), + __float_as_int(scale_in->value.x), + __float_as_int(mortar_size_in->value.x), + __float_as_int(bias_in->value.x)); + + compiler.add_node(__float_as_int(brick_width_in->value.x), + __float_as_int(row_height_in->value.x), + __float_as_int(offset), + __float_as_int(squash)); + + if(vector_offset != vector_in->stack_offset) + compiler.stack_clear_offset(vector_in->type, vector_offset); +} + +void BrickTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Offset", offset); + compiler.parameter("Offset Frequency", offset_frequency); + compiler.parameter("Squash", squash); + compiler.parameter("Squash Frequency", squash_frequency); + compiler.add(this, "node_brick_texture"); +} + /* Normal */ NormalNode::NormalNode() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 650d6092f29..82bead7e41a 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -70,8 +70,11 @@ public: bool is_float; string filename; ustring color_space; + ustring projection; + float projection_blend; static ShaderEnum color_space_enum; + static ShaderEnum projection_enum; }; class EnvironmentTextureNode : public TextureNode { @@ -155,6 +158,14 @@ public: SHADER_NODE_CLASS(CheckerTextureNode) }; +class BrickTextureNode : public TextureNode { +public: + SHADER_NODE_CLASS(BrickTextureNode) + + float offset, squash; + int offset_frequency, squash_frequency; +}; + class MappingNode : public ShaderNode { public: SHADER_NODE_CLASS(MappingNode) diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 4f5420dec61..071338d49c2 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -38,7 +38,7 @@ CCL_NAMESPACE_BEGIN -Scene::Scene(const SceneParams& params_) +Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_) : params(params_) { device = NULL; @@ -55,6 +55,9 @@ Scene::Scene(const SceneParams& params_) image_manager = new ImageManager(); shader_manager = ShaderManager::create(this); particle_system_manager = new ParticleSystemManager(); + + if (device_info_.type == DEVICE_CPU) + image_manager->set_extended_image_limits(); } Scene::~Scene() diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index d9341af08e0..f6c1ef44146 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -37,6 +37,7 @@ class AttributeRequestSet; class Background; class Camera; class Device; +class DeviceInfo; class Film; class Filter; class Integrator; @@ -99,8 +100,8 @@ public: device_vector<uint> sobol_directions; /* images */ - device_vector<uchar4> tex_image[TEX_NUM_IMAGES]; - device_vector<float4> tex_float_image[TEX_NUM_FLOAT_IMAGES]; + device_vector<uchar4> tex_image[TEX_EXTENDED_NUM_IMAGES]; + device_vector<float4> tex_float_image[TEX_EXTENDED_NUM_FLOAT_IMAGES]; /* opencl images */ device_vector<uchar4> tex_image_packed; @@ -183,7 +184,7 @@ public: /* mutex must be locked manually by callers */ thread_mutex mutex; - Scene(const SceneParams& params); + Scene(const SceneParams& params, const DeviceInfo& device_info); ~Scene(); void device_update(Device *device, Progress& progress); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index a9f7e5beb56..2fb1f49e563 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -27,6 +27,7 @@ #include "util_foreach.h" #include "util_function.h" +#include "util_math.h" #include "util_opengl.h" #include "util_task.h" #include "util_time.h" @@ -35,15 +36,23 @@ CCL_NAMESPACE_BEGIN Session::Session(const SessionParams& params_) : params(params_), - tile_manager(params.progressive, params.samples, params.tile_size, params.min_size) + tile_manager(params.progressive, params.samples, params.tile_size, params.resolution, + (params.background)? 1: max(params.device.multi_devices.size(), 1)) { device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background); TaskScheduler::init(params.threads); device = Device::create(params.device, params.background, params.threads); - buffers = new RenderBuffers(device); - display = new DisplayBuffer(device); + + if(params.background) { + buffers = NULL; + display = NULL; + } + else { + buffers = new RenderBuffers(device); + display = new DisplayBuffer(device); + } session_thread = NULL; scene = NULL; @@ -52,7 +61,6 @@ Session::Session(const SessionParams& params_) reset_time = 0.0; preview_time = 0.0; paused_time = 0.0; - sample = 0; delayed_reset.do_reset = false; delayed_reset.samples = 0; @@ -81,7 +89,7 @@ Session::~Session() wait(); } - if(params.output_path != "") { + if(display && params.output_path != "") { tonemap(); progress.set_status("Writing Image", params.output_path); @@ -118,8 +126,8 @@ void Session::reset_gpu(BufferParams& buffer_params, int samples) /* block for buffer acces and reset immediately. we can't do this * in the thread, because we need to allocate an OpenGL buffer, and * that only works in the main thread */ - thread_scoped_lock display_lock(display->mutex); - thread_scoped_lock buffers_lock(buffers->mutex); + thread_scoped_lock display_lock(display_mutex); + thread_scoped_lock buffers_lock(buffers_mutex); display_outdated = true; reset_time = time_dt(); @@ -135,7 +143,7 @@ void Session::reset_gpu(BufferParams& buffer_params, int samples) bool Session::draw_gpu(BufferParams& buffer_params) { /* block for buffer access */ - thread_scoped_lock display_lock(display->mutex); + thread_scoped_lock display_lock(display_mutex); /* first check we already rendered something */ if(gpu_draw_ready) { @@ -145,7 +153,7 @@ bool Session::draw_gpu(BufferParams& buffer_params) /* for CUDA we need to do tonemapping still, since we can * only access GL buffers from the main thread */ if(gpu_need_tonemap) { - thread_scoped_lock buffers_lock(buffers->mutex); + thread_scoped_lock buffers_lock(buffers_mutex); tonemap(); gpu_need_tonemap = false; gpu_need_tonemap_cond.notify_all(); @@ -226,23 +234,18 @@ void Session::run_gpu() /* buffers mutex is locked entirely while rendering each * sample, and released/reacquired on each iteration to allow * reset and draw in between */ - thread_scoped_lock buffers_lock(buffers->mutex); + thread_scoped_lock buffers_lock(buffers_mutex); /* update status and timing */ update_status_time(); /* path trace */ - foreach(Tile& tile, tile_manager.state.tiles) { - path_trace(tile); - - device->task_wait(); + path_trace(); - if(device->error_message() != "") - progress.set_cancel(device->error_message()); + device->task_wait(); - if(progress.get_cancel()) - break; - } + if(device->error_message() != "") + progress.set_cancel(device->error_message()); /* update status and timing */ update_status_time(); @@ -289,7 +292,7 @@ void Session::reset_cpu(BufferParams& buffer_params, int samples) bool Session::draw_cpu(BufferParams& buffer_params) { - thread_scoped_lock display_lock(display->mutex); + thread_scoped_lock display_lock(display_mutex); /* first check we already rendered something */ if(display->draw_ready()) { @@ -308,13 +311,101 @@ bool Session::draw_cpu(BufferParams& buffer_params) return false; } +bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) +{ + if(progress.get_cancel()) + return false; + + thread_scoped_lock tile_lock(tile_mutex); + + /* get next tile from manager */ + Tile tile; + int device_num = device->device_number(tile_device); + + if(!tile_manager.next_tile(tile, device_num)) + return false; + + /* fill render tile */ + rtile.x = tile_manager.state.buffer.full_x + tile.x; + rtile.y = tile_manager.state.buffer.full_y + tile.y; + rtile.w = tile.w; + rtile.h = tile.h; + rtile.start_sample = tile_manager.state.sample; + rtile.num_samples = tile_manager.state.num_samples; + rtile.resolution = tile_manager.state.resolution; + + tile_lock.unlock(); + + /* in case of a permant buffer, return it, otherwise we will allocate + * a new temporary buffer */ + if(!write_render_tile_cb) { + tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); + + rtile.buffer = buffers->buffer.device_pointer; + rtile.rng_state = buffers->rng_state.device_pointer; + rtile.rgba = display->rgba.device_pointer; + rtile.buffers = buffers; + + device->map_tile(tile_device, rtile); + + return true; + } + + /* fill buffer parameters */ + BufferParams buffer_params = tile_manager.params; + buffer_params.full_x = rtile.x; + buffer_params.full_y = rtile.y; + buffer_params.width = rtile.w; + buffer_params.height = rtile.h; + + buffer_params.get_offset_stride(rtile.offset, rtile.stride); + + /* allocate buffers */ + RenderBuffers *tilebuffers = new RenderBuffers(tile_device); + tilebuffers->reset(tile_device, buffer_params); + + rtile.buffer = tilebuffers->buffer.device_pointer; + rtile.rng_state = tilebuffers->rng_state.device_pointer; + rtile.rgba = 0; + rtile.buffers = tilebuffers; + + return true; +} + +void Session::update_tile_sample(RenderTile& rtile) +{ + thread_scoped_lock tile_lock(tile_mutex); + + if(update_render_tile_cb) { + /* todo: optimize this by making it thread safe and removing lock */ + + update_render_tile_cb(rtile); + } + + update_status_time(); +} + +void Session::release_tile(RenderTile& rtile) +{ + thread_scoped_lock tile_lock(tile_mutex); + + if(write_render_tile_cb) { + /* todo: optimize this by making it thread safe and removing lock */ + write_render_tile_cb(rtile); + + delete rtile.buffers; + } + + update_status_time(); +} + void Session::run_cpu() { { /* reset once to start */ thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock buffers_lock(buffers->mutex); - thread_scoped_lock display_lock(display->mutex); + thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock display_lock(display_mutex); reset_(delayed_reset.params, delayed_reset.samples); delayed_reset.do_reset = false; @@ -364,7 +455,7 @@ void Session::run_cpu() /* buffers mutex is locked entirely while rendering each * sample, and released/reacquired on each iteration to allow * reset and draw in between */ - thread_scoped_lock buffers_lock(buffers->mutex); + thread_scoped_lock buffers_lock(buffers_mutex); /* update scene */ update_scene(); @@ -379,8 +470,7 @@ void Session::run_cpu() update_status_time(); /* path trace */ - foreach(Tile& tile, tile_manager.state.tiles) - path_trace(tile); + path_trace(); /* update status and timing */ update_status_time(); @@ -396,8 +486,8 @@ void Session::run_cpu() { thread_scoped_lock reset_lock(delayed_reset.mutex); - thread_scoped_lock buffers_lock(buffers->mutex); - thread_scoped_lock display_lock(display->mutex); + thread_scoped_lock buffers_lock(buffers_mutex); + thread_scoped_lock display_lock(display_mutex); if(delayed_reset.do_reset) { /* reset rendering if request from main thread */ @@ -442,6 +532,9 @@ void Session::run() /* run */ if(!progress.get_cancel()) { + /* reset number of rendered samples */ + progress.reset_sample(); + if(device_use_gl) run_gpu(); else @@ -465,10 +558,12 @@ bool Session::draw(BufferParams& buffer_params) void Session::reset_(BufferParams& buffer_params, int samples) { - if(buffer_params.modified(buffers->params)) { - gpu_draw_ready = false; - buffers->reset(device, buffer_params); - display->reset(device, buffer_params); + if(buffers) { + if(buffer_params.modified(buffers->params)) { + gpu_draw_ready = false; + buffers->reset(device, buffer_params); + display->reset(device, buffer_params); + } } tile_manager.reset(buffer_params, samples); @@ -476,7 +571,6 @@ void Session::reset_(BufferParams& buffer_params, int samples) start_time = time_dt(); preview_time = 0.0; paused_time = 0.0; - sample = 0; if(!params.background) progress.set_start_time(start_time + paused_time); @@ -532,8 +626,6 @@ void Session::update_scene() { thread_scoped_lock scene_lock(scene->mutex); - progress.set_status("Updating Scene"); - /* update camera if dimensions changed for progressive render. the camera * knows nothing about progressive or cropped rendering, it just gets the * image dimensions passed in */ @@ -548,20 +640,47 @@ void Session::update_scene() } /* update scene */ - if(scene->need_update()) + if(scene->need_update()) { + progress.set_status("Updating Scene"); scene->device_update(device, progress); + } } void Session::update_status_time(bool show_pause, bool show_done) { int sample = tile_manager.state.sample; int resolution = tile_manager.state.resolution; + int num_tiles = tile_manager.state.num_tiles; + int tile = tile_manager.state.num_rendered_tiles; /* update status */ string status, substatus; - if(!params.progressive) - substatus = "Path Tracing"; + if(!params.progressive) { + substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles); + + if(params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL || + (params.device.type == DEVICE_CPU && num_tiles == 1)) { + /* when rendering on GPU multithreading happens within single tile, as in + * tiles are handling sequentially and in this case we could display + * currently rendering sample number + * this helps a lot from feedback point of view. + * also display the info on CPU, when using 1 tile only + */ + + int sample = progress.get_sample(), num_samples = tile_manager.state.num_samples; + + if(tile > 1) { + /* sample counter is global for all tiles, subtract samples + * from already finished tiles to get sample counter for + * current tile only + */ + sample -= (tile - 1) * num_samples; + } + + substatus += string_printf(", Sample %d/%d", sample, num_samples); + } + } else if(params.samples == INT_MAX) substatus = string_printf("Path Tracing Sample %d", sample+1); else @@ -580,28 +699,29 @@ void Session::update_status_time(bool show_pause, bool show_done) if(preview_time == 0.0 && resolution == 1) preview_time = time_dt(); - double sample_time = (sample == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample); + double tile_time = (tile == 0)? 0.0: (time_dt() - preview_time - paused_time)/(sample); /* negative can happen when we pause a bit before rendering, can discard that */ if(preview_time < 0.0) preview_time = 0.0; - progress.set_sample(sample + 1, sample_time); + progress.set_tile(tile, tile_time); +} + +void Session::update_progress_sample() +{ + progress.increment_sample(); } -void Session::path_trace(Tile& tile) +void Session::path_trace() { /* add path trace task */ DeviceTask task(DeviceTask::PATH_TRACE); - - task.x = tile_manager.state.buffer.full_x + tile.x; - task.y = tile_manager.state.buffer.full_y + tile.y; - task.w = tile.w; - task.h = tile.h; - task.buffer = buffers->buffer.device_pointer; - task.rng_state = buffers->rng_state.device_pointer; - task.sample = tile_manager.state.sample; - task.resolution = tile_manager.state.resolution; - tile_manager.state.buffer.get_offset_stride(task.offset, task.stride); + + task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2); + task.release_tile = function_bind(&Session::release_tile, this, _1); + task.get_cancel = function_bind(&Progress::get_cancel, &this->progress); + task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1); + task.update_progress_sample = function_bind(&Session::update_progress_sample, this); device->task_add(task); } diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 90616f011ea..7b01357a2b7 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -47,8 +47,8 @@ public: bool progressive; bool experimental; int samples; - int tile_size; - int min_size; + int2 tile_size; + int resolution; int threads; double cancel_timeout; @@ -63,8 +63,8 @@ public: progressive = false; experimental = false; samples = INT_MAX; - tile_size = 64; - min_size = 64; + tile_size = make_int2(64, 64); + resolution = 4; threads = 0; cancel_timeout = 0.1; @@ -81,7 +81,7 @@ public: && progressive == params.progressive && experimental == params.experimental && tile_size == params.tile_size - && min_size == params.min_size + && resolution == params.resolution && threads == params.threads && cancel_timeout == params.cancel_timeout && reset_timeout == params.reset_timeout @@ -102,7 +102,10 @@ public: DisplayBuffer *display; Progress progress; SessionParams params; - int sample; + TileManager tile_manager; + + boost::function<void(RenderTile&)> write_render_tile_cb; + boost::function<void(RenderTile&)> update_render_tile_cb; Session(const SessionParams& params); ~Session(); @@ -130,7 +133,7 @@ protected: void update_status_time(bool show_pause = false, bool show_done = false); void tonemap(); - void path_trace(Tile& tile); + void path_trace(); void reset_(BufferParams& params, int samples); void run_cpu(); @@ -141,7 +144,12 @@ protected: bool draw_gpu(BufferParams& params); void reset_gpu(BufferParams& params, int samples); - TileManager tile_manager; + bool acquire_tile(Device *tile_device, RenderTile& tile); + void update_tile_sample(RenderTile& tile); + void release_tile(RenderTile& tile); + + void update_progress_sample(); + bool device_use_gl; thread *session_thread; @@ -155,6 +163,9 @@ protected: bool pause; thread_condition_variable pause_cond; thread_mutex pause_mutex; + thread_mutex tile_mutex; + thread_mutex buffers_mutex; + thread_mutex display_mutex; bool kernels_loaded; diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index 04e48d44029..b4156fd9471 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -19,14 +19,16 @@ #include "tile.h" #include "util_algorithm.h" +#include "util_types.h" CCL_NAMESPACE_BEGIN -TileManager::TileManager(bool progressive_, int samples_, int tile_size_, int min_size_) +TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int resolution_, int num_devices_) { progressive = progressive_; tile_size = tile_size_; - min_size = min_size_; + resolution = resolution_; + num_devices = num_devices_; BufferParams buffer_params; reset(buffer_params, 0); @@ -36,34 +38,24 @@ TileManager::~TileManager() { } -void TileManager::reset(BufferParams& params_, int samples_) +void TileManager::reset(BufferParams& params_, int num_samples_) { params = params_; - start_resolution = 1; - - int w = params.width, h = params.height; - - if(min_size != INT_MAX) { - while(w*h > min_size*min_size) { - w = max(1, w/2); - h = max(1, h/2); - - start_resolution *= 2; - } - } - - samples = samples_; + num_samples = num_samples_; state.buffer = BufferParams(); state.sample = -1; - state.resolution = start_resolution; + state.num_tiles = 0; + state.num_rendered_tiles = 0; + state.num_samples = 0; + state.resolution = resolution; state.tiles.clear(); } -void TileManager::set_samples(int samples_) +void TileManager::set_samples(int num_samples_) { - samples = samples_; + num_samples = num_samples_; } void TileManager::set_tiles() @@ -71,24 +63,34 @@ void TileManager::set_tiles() int resolution = state.resolution; int image_w = max(1, params.width/resolution); int image_h = max(1, params.height/resolution); - int tile_w = (tile_size >= image_w)? 1: (image_w + tile_size - 1)/tile_size; - int tile_h = (tile_size >= image_h)? 1: (image_h + tile_size - 1)/tile_size; - int sub_w = image_w/tile_w; - int sub_h = image_h/tile_h; state.tiles.clear(); - for(int tile_y = 0; tile_y < tile_h; tile_y++) { - for(int tile_x = 0; tile_x < tile_w; tile_x++) { - int x = tile_x * sub_w; - int y = tile_y * sub_h; - int w = (tile_x == tile_w-1)? image_w - x: sub_w; - int h = (tile_y == tile_h-1)? image_h - y: sub_h; + int num = min(image_h, num_devices); + + for(int device = 0; device < num; device++) { + int device_y = (image_h/num)*device; + int device_h = (device == num-1)? image_h - device*(image_h/num): image_h/num; + + int tile_w = (tile_size.x >= image_w)? 1: (image_w + tile_size.x - 1)/tile_size.x; + int tile_h = (tile_size.y >= device_h)? 1: (device_h + tile_size.y - 1)/tile_size.y; + int sub_w = (image_w + tile_w - 1)/tile_w; + int sub_h = (device_h + tile_h - 1)/tile_h; - state.tiles.push_back(Tile(x, y, w, h)); + for(int tile_y = 0; tile_y < tile_h; tile_y++) { + for(int tile_x = 0; tile_x < tile_w; tile_x++) { + int x = tile_x * sub_w; + int y = tile_y * sub_h; + int w = (tile_x == tile_w-1)? image_w - x: sub_w; + int h = (tile_y == tile_h-1)? device_h - y: sub_h; + + state.tiles.push_back(Tile(x, y + device_y, w, h, device)); + } } } + state.num_tiles = state.tiles.size(); + state.buffer.width = image_w; state.buffer.height = image_h; @@ -98,9 +100,74 @@ void TileManager::set_tiles() state.buffer.full_height = max(1, params.full_height/resolution); } +list<Tile>::iterator TileManager::next_center_tile(int device) +{ + list<Tile>::iterator iter, best = state.tiles.end(); + + int resolution = state.resolution; + int image_w = max(1, params.width/resolution); + int image_h = max(1, params.height/resolution); + + int num = min(image_h, num_devices); + + int device_y = (image_h / num) * device; + int device_h = (device == num - 1) ? image_h - device * (image_h / num) : image_h / num; + + int64_t centx = image_w / 2, centy = device_y + device_h / 2, tot = 1; + int64_t mindist = (int64_t) image_w * (int64_t) device_h; + + /* find center of rendering tiles, image center counts for 1 too */ + for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) { + if(iter->rendering) { + Tile &cur_tile = *iter; + centx += cur_tile.x + cur_tile.w / 2; + centy += cur_tile.y + cur_tile.h / 2; + tot++; + } + } + + centx /= tot; + centy /= tot; + + /* closest of the non-rendering tiles */ + for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) { + if(iter->device == device && iter->rendering == false) { + Tile &cur_tile = *iter; + + int64_t distx = centx - (cur_tile.x + cur_tile.w / 2); + int64_t disty = centy - (cur_tile.y + cur_tile.h / 2); + distx = (int64_t) sqrt((double)distx * distx + disty * disty); + + if(distx < mindist) { + best = iter; + mindist = distx; + } + } + } + + return best; +} + +bool TileManager::next_tile(Tile& tile, int device) +{ + list<Tile>::iterator tile_it; + + tile_it = next_center_tile(device); + + if(tile_it != state.tiles.end()) { + tile_it->rendering = true; + tile = *tile_it; + state.num_rendered_tiles++; + + return true; + } + + return false; +} + bool TileManager::done() { - return (state.sample+1 >= samples && state.resolution == 1); + return (state.sample+state.num_samples >= num_samples && state.resolution == 1); } bool TileManager::next() @@ -111,10 +178,17 @@ bool TileManager::next() if(progressive && state.resolution > 1) { state.sample = 0; state.resolution /= 2; + state.num_samples = 1; set_tiles(); } else { state.sample++; + + if(progressive) + state.num_samples = 1; + else + state.num_samples = num_samples; + state.resolution = 1; set_tiles(); } diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index b6e610c8d90..29f2b1ef9f9 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -31,9 +31,14 @@ CCL_NAMESPACE_BEGIN class Tile { public: int x, y, w, h; + int device; + bool rendering; - Tile(int x_, int y_, int w_, int h_) - : x(x_), y(y_), w(w_), h(h_) {} + Tile() + {} + + Tile(int x_, int y_, int w_, int h_, int device_) + : x(x_), y(y_), w(w_), h(h_), device(device_), rendering(false) {} }; /* Tile Manager */ @@ -45,27 +50,34 @@ public: struct State { BufferParams buffer; int sample; + int num_samples; int resolution; + int num_tiles; + int num_rendered_tiles; list<Tile> tiles; } state; - TileManager(bool progressive, int samples, int tile_size, int min_size); + TileManager(bool progressive, int num_samples, int2 tile_size, int resolution, int num_devices = 1); ~TileManager(); - void reset(BufferParams& params, int samples); - void set_samples(int samples); + void reset(BufferParams& params, int num_samples); + void set_samples(int num_samples); bool next(); + bool next_tile(Tile& tile, int device = 0); bool done(); protected: void set_tiles(); bool progressive; - int samples; - int tile_size; - int min_size; + int num_samples; + int2 tile_size; + int resolution; + int num_devices; int start_resolution; + + list<Tile>::iterator next_center_tile(int device = 0); }; CCL_NAMESPACE_END |