2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* 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
|
2014-12-25 01:50:24 +00:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "render/tile.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "util/util_algorithm.h"
|
|
|
|
#include "util/util_types.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2015-12-22 11:51:27 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
class TileComparator {
|
|
|
|
public:
|
2017-05-07 12:40:58 +00:00
|
|
|
TileComparator(TileOrder order_, int2 center_, Tile *tiles_)
|
|
|
|
: order(order_),
|
|
|
|
center(center_),
|
|
|
|
tiles(tiles_)
|
2015-12-22 11:51:27 +00:00
|
|
|
{}
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
bool operator()(int a, int b)
|
2015-12-22 11:51:27 +00:00
|
|
|
{
|
2017-05-07 12:40:58 +00:00
|
|
|
switch(order) {
|
2015-12-22 11:51:27 +00:00
|
|
|
case TILE_CENTER:
|
|
|
|
{
|
2017-05-07 12:40:58 +00:00
|
|
|
float2 dist_a = make_float2(center.x - (tiles[a].x + tiles[a].w/2),
|
|
|
|
center.y - (tiles[a].y + tiles[a].h/2));
|
|
|
|
float2 dist_b = make_float2(center.x - (tiles[b].x + tiles[b].w/2),
|
|
|
|
center.y - (tiles[b].y + tiles[b].h/2));
|
2015-12-22 11:51:27 +00:00
|
|
|
return dot(dist_a, dist_a) < dot(dist_b, dist_b);
|
|
|
|
}
|
|
|
|
case TILE_LEFT_TO_RIGHT:
|
2017-05-07 12:40:58 +00:00
|
|
|
return (tiles[a].x == tiles[b].x)? (tiles[a].y < tiles[b].y): (tiles[a].x < tiles[b].x);
|
2015-12-22 11:51:27 +00:00
|
|
|
case TILE_RIGHT_TO_LEFT:
|
2017-05-07 12:40:58 +00:00
|
|
|
return (tiles[a].x == tiles[b].x)? (tiles[a].y < tiles[b].y): (tiles[a].x > tiles[b].x);
|
2015-12-22 11:51:27 +00:00
|
|
|
case TILE_TOP_TO_BOTTOM:
|
2017-05-07 12:40:58 +00:00
|
|
|
return (tiles[a].y == tiles[b].y)? (tiles[a].x < tiles[b].x): (tiles[a].y > tiles[b].y);
|
2015-12-22 11:51:27 +00:00
|
|
|
case TILE_BOTTOM_TO_TOP:
|
|
|
|
default:
|
2017-05-07 12:40:58 +00:00
|
|
|
return (tiles[a].y == tiles[b].y)? (tiles[a].x < tiles[b].x): (tiles[a].y < tiles[b].y);
|
2015-12-22 11:51:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2017-05-07 12:40:58 +00:00
|
|
|
TileOrder order;
|
|
|
|
int2 center;
|
|
|
|
Tile *tiles;
|
2015-12-22 11:51:27 +00:00
|
|
|
};
|
|
|
|
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
inline int2 hilbert_index_to_pos(int n, int d)
|
|
|
|
{
|
|
|
|
int2 r, xy = make_int2(0, 0);
|
|
|
|
for(int s = 1; s < n; s *= 2) {
|
|
|
|
r.x = (d >> 1) & 1;
|
|
|
|
r.y = (d ^ r.x) & 1;
|
|
|
|
if(!r.y) {
|
|
|
|
if(r.x) {
|
|
|
|
xy = make_int2(s-1, s-1) - xy;
|
|
|
|
}
|
|
|
|
swap(xy.x, xy.y);
|
|
|
|
}
|
|
|
|
xy += r*make_int2(s, s);
|
|
|
|
d >>= 2;
|
|
|
|
}
|
|
|
|
return xy;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum SpiralDirection {
|
|
|
|
DIRECTION_UP,
|
|
|
|
DIRECTION_LEFT,
|
|
|
|
DIRECTION_DOWN,
|
|
|
|
DIRECTION_RIGHT,
|
|
|
|
};
|
|
|
|
|
2015-12-22 11:51:27 +00:00
|
|
|
} /* namespace */
|
|
|
|
|
2012-10-23 16:36:53 +00:00
|
|
|
TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int start_resolution_,
|
2017-08-14 22:11:52 +00:00
|
|
|
bool preserve_tile_device_, bool background_, TileOrder tile_order_,
|
|
|
|
int num_devices_, int pixel_size_)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
progressive = progressive_;
|
|
|
|
tile_size = tile_size_;
|
2013-01-07 19:55:49 +00:00
|
|
|
tile_order = tile_order_;
|
2012-09-17 10:55:18 +00:00
|
|
|
start_resolution = start_resolution_;
|
2017-08-14 22:11:52 +00:00
|
|
|
pixel_size = pixel_size_;
|
2015-03-27 10:47:55 +00:00
|
|
|
num_samples = num_samples_;
|
2012-09-04 13:29:07 +00:00
|
|
|
num_devices = num_devices_;
|
2012-10-23 16:36:53 +00:00
|
|
|
preserve_tile_device = preserve_tile_device_;
|
2012-10-24 14:43:29 +00:00
|
|
|
background = background_;
|
2017-05-07 12:40:58 +00:00
|
|
|
schedule_denoising = false;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-03-30 13:55:12 +00:00
|
|
|
range_start_sample = 0;
|
|
|
|
range_num_samples = -1;
|
|
|
|
|
2011-12-20 12:25:37 +00:00
|
|
|
BufferParams buffer_params;
|
|
|
|
reset(buffer_params, 0);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TileManager::~TileManager()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
void TileManager::free_device()
|
|
|
|
{
|
|
|
|
if(schedule_denoising) {
|
|
|
|
for(int i = 0; i < state.tiles.size(); i++) {
|
|
|
|
delete state.tiles[i].buffers;
|
|
|
|
state.tiles[i].buffers = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
static int get_divider(int w, int h, int start_resolution)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-09-17 10:55:18 +00:00
|
|
|
int divider = 1;
|
|
|
|
if(start_resolution != INT_MAX) {
|
|
|
|
while(w*h > start_resolution*start_resolution) {
|
2015-12-22 11:51:27 +00:00
|
|
|
w = max(1, w/2);
|
|
|
|
h = max(1, h/2);
|
2012-09-17 10:55:18 +00:00
|
|
|
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
divider <<= 1;
|
2012-09-17 10:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
return divider;
|
|
|
|
}
|
2012-09-17 10:55:18 +00:00
|
|
|
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
void TileManager::reset(BufferParams& params_, int num_samples_)
|
|
|
|
{
|
|
|
|
params = params_;
|
|
|
|
|
|
|
|
set_samples(num_samples_);
|
2011-08-28 13:55:59 +00:00
|
|
|
|
2011-12-21 13:48:35 +00:00
|
|
|
state.buffer = BufferParams();
|
2016-03-30 13:55:12 +00:00
|
|
|
state.sample = range_start_sample - 1;
|
2012-09-04 13:29:07 +00:00
|
|
|
state.num_tiles = 0;
|
|
|
|
state.num_samples = 0;
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
state.resolution_divider = get_divider(params.width, params.height, start_resolution);
|
2017-05-07 12:40:58 +00:00
|
|
|
state.render_tiles.clear();
|
|
|
|
state.denoising_tiles.clear();
|
2011-04-27 11:58:34 +00:00
|
|
|
state.tiles.clear();
|
|
|
|
}
|
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
void TileManager::set_samples(int num_samples_)
|
2011-08-28 13:55:59 +00:00
|
|
|
{
|
2012-09-04 13:29:07 +00:00
|
|
|
num_samples = num_samples_;
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
|
|
|
|
/* No real progress indication is possible when using unlimited samples. */
|
|
|
|
if(num_samples == INT_MAX) {
|
|
|
|
state.total_pixel_samples = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
uint64_t pixel_samples = 0;
|
|
|
|
/* While rendering in the viewport, the initial preview resolution is increased to the native resolution
|
|
|
|
* before the actual rendering begins. Therefore, additional pixel samples will be rendered. */
|
2017-08-16 23:58:48 +00:00
|
|
|
int divider = max(get_divider(params.width, params.height, start_resolution) / 2, pixel_size);
|
|
|
|
while(divider > pixel_size) {
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
int image_w = max(1, params.width/divider);
|
|
|
|
int image_h = max(1, params.height/divider);
|
|
|
|
pixel_samples += image_w * image_h;
|
|
|
|
divider >>= 1;
|
|
|
|
}
|
|
|
|
|
2017-08-16 23:58:48 +00:00
|
|
|
int image_w = max(1, params.width/divider);
|
|
|
|
int image_h = max(1, params.height/divider);
|
|
|
|
state.total_pixel_samples = pixel_samples + (uint64_t)get_num_effective_samples() * image_w*image_h;
|
2017-05-07 12:40:58 +00:00
|
|
|
if(schedule_denoising) {
|
|
|
|
state.total_pixel_samples += params.width*params.height;
|
|
|
|
}
|
Cycles: Refactor Progress system to provide better estimates
The Progress system in Cycles had two limitations so far:
- It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image.
- Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased.
This patch fixes both problems:
First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time.
The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels.
Along with that, some unused variables were removed from the Progress and Session classes.
Reviewers: brecht, sergey, #cycles
Subscribers: brecht, candreacchio, sergey
Differential Revision: https://developer.blender.org/D2214
2016-11-26 03:22:34 +00:00
|
|
|
}
|
2011-08-28 13:55:59 +00:00
|
|
|
}
|
|
|
|
|
2015-12-22 11:51:27 +00:00
|
|
|
/* If sliced is false, splits image into tiles and assigns equal amount of tiles to every render device.
|
|
|
|
* If sliced is true, slice image into as much pieces as how many devices are rendering this image. */
|
|
|
|
int TileManager::gen_tiles(bool sliced)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-09-17 10:55:18 +00:00
|
|
|
int resolution = state.resolution_divider;
|
2011-12-20 12:25:37 +00:00
|
|
|
int image_w = max(1, params.width/resolution);
|
|
|
|
int image_h = max(1, params.height/resolution);
|
2015-12-22 11:51:27 +00:00
|
|
|
int2 center = make_int2(image_w/2, image_h/2);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-10-23 16:36:53 +00:00
|
|
|
int num_logical_devices = preserve_tile_device? num_devices: 1;
|
2012-10-24 14:43:29 +00:00
|
|
|
int num = min(image_h, num_logical_devices);
|
2015-12-22 11:51:27 +00:00
|
|
|
int slice_num = sliced? num: 1;
|
2017-05-07 12:40:58 +00:00
|
|
|
int tile_w = (tile_size.x >= image_w) ? 1 : divide_up(image_w, tile_size.x);
|
2012-10-24 14:43:29 +00:00
|
|
|
|
2015-12-23 23:29:40 +00:00
|
|
|
state.tiles.clear();
|
2017-05-07 12:40:58 +00:00
|
|
|
state.render_tiles.clear();
|
|
|
|
state.denoising_tiles.clear();
|
|
|
|
state.render_tiles.resize(num);
|
|
|
|
state.denoising_tiles.resize(num);
|
|
|
|
state.tile_stride = tile_w;
|
|
|
|
vector<list<int> >::iterator tile_list;
|
|
|
|
tile_list = state.render_tiles.begin();
|
2012-10-24 14:43:29 +00:00
|
|
|
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
if(tile_order == TILE_HILBERT_SPIRAL) {
|
|
|
|
assert(!sliced);
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int tile_h = (tile_size.y >= image_h) ? 1 : divide_up(image_h, tile_size.y);
|
|
|
|
state.tiles.resize(tile_w*tile_h);
|
|
|
|
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
/* Size of blocks in tiles, must be a power of 2 */
|
|
|
|
const int hilbert_size = (max(tile_size.x, tile_size.y) <= 12)? 8: 4;
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int tiles_per_device = divide_up(tile_w * tile_h, num);
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
int cur_device = 0, cur_tiles = 0;
|
|
|
|
|
|
|
|
int2 block_size = tile_size * make_int2(hilbert_size, hilbert_size);
|
|
|
|
/* Number of blocks to fill the image */
|
2017-05-07 12:40:58 +00:00
|
|
|
int blocks_x = (block_size.x >= image_w)? 1: divide_up(image_w, block_size.x);
|
|
|
|
int blocks_y = (block_size.y >= image_h)? 1: divide_up(image_h, block_size.y);
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
int n = max(blocks_x, blocks_y) | 0x1; /* Side length of the spiral (must be odd) */
|
|
|
|
/* Offset of spiral (to keep it centered) */
|
|
|
|
int2 offset = make_int2((image_w - n*block_size.x)/2, (image_h - n*block_size.y)/2);
|
|
|
|
offset = (offset / tile_size) * tile_size; /* Round to tile border. */
|
|
|
|
|
|
|
|
int2 block = make_int2(0, 0); /* Current block */
|
|
|
|
SpiralDirection prev_dir = DIRECTION_UP, dir = DIRECTION_UP;
|
|
|
|
for(int i = 0;;) {
|
|
|
|
/* Generate the tiles in the current block. */
|
|
|
|
for(int hilbert_index = 0; hilbert_index < hilbert_size*hilbert_size; hilbert_index++) {
|
|
|
|
int2 tile, hilbert_pos = hilbert_index_to_pos(hilbert_size, hilbert_index);
|
|
|
|
/* Rotate block according to spiral direction. */
|
|
|
|
if(prev_dir == DIRECTION_UP && dir == DIRECTION_UP) {
|
|
|
|
tile = make_int2(hilbert_pos.y, hilbert_pos.x);
|
|
|
|
}
|
|
|
|
else if(dir == DIRECTION_LEFT || prev_dir == DIRECTION_LEFT) {
|
|
|
|
tile = hilbert_pos;
|
|
|
|
}
|
|
|
|
else if(dir == DIRECTION_DOWN) {
|
|
|
|
tile = make_int2(hilbert_size-1-hilbert_pos.y, hilbert_size-1-hilbert_pos.x);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tile = make_int2(hilbert_size-1-hilbert_pos.x, hilbert_size-1-hilbert_pos.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
int2 pos = block*block_size + tile*tile_size + offset;
|
|
|
|
/* Only add tiles which are in the image (tiles outside of the image can be generated since the spiral is always square). */
|
|
|
|
if(pos.x >= 0 && pos.y >= 0 && pos.x < image_w && pos.y < image_h) {
|
|
|
|
int w = min(tile_size.x, image_w - pos.x);
|
|
|
|
int h = min(tile_size.y, image_h - pos.y);
|
2017-05-07 12:40:58 +00:00
|
|
|
int2 ipos = pos / tile_size;
|
|
|
|
int idx = ipos.y*tile_w + ipos.x;
|
|
|
|
state.tiles[idx] = Tile(idx, pos.x, pos.y, w, h, cur_device, Tile::RENDER);
|
|
|
|
tile_list->push_front(idx);
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
cur_tiles++;
|
|
|
|
|
|
|
|
if(cur_tiles == tiles_per_device) {
|
|
|
|
tile_list++;
|
|
|
|
cur_tiles = 0;
|
|
|
|
cur_device++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Stop as soon as the spiral has reached the center block. */
|
|
|
|
if(block.x == (n-1)/2 && block.y == (n-1)/2)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Advance to next block. */
|
|
|
|
prev_dir = dir;
|
|
|
|
switch(dir) {
|
|
|
|
case DIRECTION_UP:
|
|
|
|
block.y++;
|
|
|
|
if(block.y == (n-i-1)) {
|
|
|
|
dir = DIRECTION_LEFT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DIRECTION_LEFT:
|
|
|
|
block.x++;
|
|
|
|
if(block.x == (n-i-1)) {
|
|
|
|
dir = DIRECTION_DOWN;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DIRECTION_DOWN:
|
|
|
|
block.y--;
|
|
|
|
if(block.y == i) {
|
|
|
|
dir = DIRECTION_RIGHT;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DIRECTION_RIGHT:
|
|
|
|
block.x--;
|
|
|
|
if(block.x == i+1) {
|
|
|
|
dir = DIRECTION_UP;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-05-07 12:40:58 +00:00
|
|
|
return tile_w*tile_h;
|
Cycles: Adding Hilbert Spiral as a tile order for rendering
This patch adds the "Hilbert Spiral", a custom-designed continuous space-filling curve, as a tile order for rendering in Cycles.
It essentially works by dividing the tiles into tile blocks which are processed in a spiral outwards from the center. Inside each
block, the tiles are processed in a regular Hilbert curve pattern. By rotating that pattern according to the spiral direction,
a continuous curve is obtained, which helps with cache coherency and therefore rendering speed.
The curve is a compromise between the faster-rendering Bottom-to-Top etc. orders and the Center order, which is a bit slower,
but starts with the more important areas. The Hilbert Spiral also starts in the center (unless huge tiles are used) and is still
marginally slower than Bottom-to-Top, but noticeably faster than Center.
Reviewers: sergey, #cycles, dingto
Reviewed By: #cycles, dingto
Subscribers: iscream, gregzaal, sergey, mib2berlin
Differential Revision: https://developer.blender.org/D1166
2016-01-09 23:11:34 +00:00
|
|
|
}
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int idx = 0;
|
2015-12-22 11:51:27 +00:00
|
|
|
for(int slice = 0; slice < slice_num; slice++) {
|
|
|
|
int slice_y = (image_h/slice_num)*slice;
|
|
|
|
int slice_h = (slice == slice_num-1)? image_h - slice*(image_h/slice_num): image_h/slice_num;
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int tile_h = (tile_size.y >= slice_h)? 1: divide_up(slice_h, tile_size.y);
|
2015-12-22 11:51:27 +00:00
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int tiles_per_device = divide_up(tile_w * tile_h, num);
|
2015-12-22 11:51:27 +00:00
|
|
|
int cur_device = 0, cur_tiles = 0;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-09-04 13:29:07 +00:00
|
|
|
for(int tile_y = 0; tile_y < tile_h; tile_y++) {
|
2017-05-07 12:40:58 +00:00
|
|
|
for(int tile_x = 0; tile_x < tile_w; tile_x++, idx++) {
|
2012-11-05 08:05:14 +00:00
|
|
|
int x = tile_x * tile_size.x;
|
|
|
|
int y = tile_y * tile_size.y;
|
|
|
|
int w = (tile_x == tile_w-1)? image_w - x: tile_size.x;
|
2015-12-22 11:51:27 +00:00
|
|
|
int h = (tile_y == tile_h-1)? slice_h - y: tile_size.y;
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
state.tiles.push_back(Tile(idx, x, y + slice_y, w, h, sliced? slice: cur_device, Tile::RENDER));
|
|
|
|
tile_list->push_back(idx);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2015-12-22 11:51:27 +00:00
|
|
|
if(!sliced) {
|
|
|
|
cur_tiles++;
|
|
|
|
|
|
|
|
if(cur_tiles == tiles_per_device) {
|
2016-01-01 22:52:37 +00:00
|
|
|
/* Tiles are already generated in Bottom-to-Top order, so no sort is necessary in that case. */
|
|
|
|
if(tile_order != TILE_BOTTOM_TO_TOP) {
|
2017-05-07 12:40:58 +00:00
|
|
|
tile_list->sort(TileComparator(tile_order, center, &state.tiles[0]));
|
2016-01-01 22:52:37 +00:00
|
|
|
}
|
2015-12-22 11:51:27 +00:00
|
|
|
tile_list++;
|
|
|
|
cur_tiles = 0;
|
|
|
|
cur_device++;
|
|
|
|
}
|
|
|
|
}
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2015-12-31 12:48:38 +00:00
|
|
|
if(sliced) {
|
|
|
|
tile_list++;
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2015-12-22 11:51:27 +00:00
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
return idx;
|
2012-10-24 14:43:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void TileManager::set_tiles()
|
|
|
|
{
|
|
|
|
int resolution = state.resolution_divider;
|
|
|
|
int image_w = max(1, params.width/resolution);
|
|
|
|
int image_h = max(1, params.height/resolution);
|
|
|
|
|
2015-12-22 11:51:27 +00:00
|
|
|
state.num_tiles = gen_tiles(!background);
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2011-12-21 13:48:35 +00:00
|
|
|
state.buffer.width = image_w;
|
|
|
|
state.buffer.height = image_h;
|
|
|
|
|
|
|
|
state.buffer.full_x = params.full_x/resolution;
|
|
|
|
state.buffer.full_y = params.full_y/resolution;
|
|
|
|
state.buffer.full_width = max(1, params.full_width/resolution);
|
|
|
|
state.buffer.full_height = max(1, params.full_height/resolution);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int TileManager::get_neighbor_index(int index, int neighbor)
|
|
|
|
{
|
|
|
|
static const int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1, 0}, dy[] = {-1, -1, -1, 0, 0, 1, 1, 1, 0};
|
|
|
|
|
|
|
|
int resolution = state.resolution_divider;
|
|
|
|
int image_w = max(1, params.width/resolution);
|
|
|
|
int image_h = max(1, params.height/resolution);
|
|
|
|
int tile_w = (tile_size.x >= image_w)? 1: divide_up(image_w, tile_size.x);
|
|
|
|
int tile_h = (tile_size.y >= image_h)? 1: divide_up(image_h, tile_size.y);
|
|
|
|
|
|
|
|
int nx = state.tiles[index].x/tile_size.x + dx[neighbor], ny = state.tiles[index].y/tile_size.y + dy[neighbor];
|
|
|
|
if(nx < 0 || ny < 0 || nx >= tile_w || ny >= tile_h)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return ny*state.tile_stride + nx;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checks whether all neighbors of a tile (as well as the tile itself) are at least at state min_state. */
|
|
|
|
bool TileManager::check_neighbor_state(int index, Tile::State min_state)
|
|
|
|
{
|
|
|
|
if(index < 0 || state.tiles[index].state < min_state) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for(int neighbor = 0; neighbor < 9; neighbor++) {
|
|
|
|
int nindex = get_neighbor_index(index, neighbor);
|
|
|
|
/* Out-of-bounds tiles don't matter. */
|
|
|
|
if(nindex >= 0 && state.tiles[nindex].state < min_state) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns whether the tile should be written (and freed if no denoising is used) instead of updating. */
|
|
|
|
bool TileManager::finish_tile(int index, bool &delete_tile)
|
|
|
|
{
|
|
|
|
delete_tile = false;
|
|
|
|
|
|
|
|
switch(state.tiles[index].state) {
|
|
|
|
case Tile::RENDER:
|
|
|
|
{
|
|
|
|
if(!schedule_denoising) {
|
|
|
|
state.tiles[index].state = Tile::DONE;
|
|
|
|
delete_tile = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
state.tiles[index].state = Tile::RENDERED;
|
|
|
|
/* For each neighbor and the tile itself, check whether all of its neighbors have been rendered. If yes, it can be denoised. */
|
|
|
|
for(int neighbor = 0; neighbor < 9; neighbor++) {
|
|
|
|
int nindex = get_neighbor_index(index, neighbor);
|
|
|
|
if(check_neighbor_state(nindex, Tile::RENDERED)) {
|
|
|
|
state.tiles[nindex].state = Tile::DENOISE;
|
|
|
|
state.denoising_tiles[state.tiles[nindex].device].push_back(nindex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case Tile::DENOISE:
|
|
|
|
{
|
|
|
|
state.tiles[index].state = Tile::DENOISED;
|
|
|
|
/* For each neighbor and the tile itself, check whether all of its neighbors have been denoised. If yes, it can be freed. */
|
|
|
|
for(int neighbor = 0; neighbor < 9; neighbor++) {
|
|
|
|
int nindex = get_neighbor_index(index, neighbor);
|
|
|
|
if(check_neighbor_state(nindex, Tile::DENOISED)) {
|
|
|
|
state.tiles[nindex].state = Tile::DONE;
|
|
|
|
/* It can happen that the tile just finished denoising and already can be freed here.
|
|
|
|
* However, in that case it still has to be written before deleting, so we can't delete it yet. */
|
|
|
|
if(neighbor == 8) {
|
|
|
|
delete_tile = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete state.tiles[nindex].buffers;
|
|
|
|
state.tiles[nindex].buffers = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TileManager::next_tile(Tile* &tile, int device)
|
2012-10-25 12:03:36 +00:00
|
|
|
{
|
|
|
|
int logical_device = preserve_tile_device? device: 0;
|
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
if(logical_device >= state.render_tiles.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if(!state.denoising_tiles[logical_device].empty()) {
|
|
|
|
int idx = state.denoising_tiles[logical_device].front();
|
|
|
|
state.denoising_tiles[logical_device].pop_front();
|
|
|
|
tile = &state.tiles[idx];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(state.render_tiles[logical_device].empty())
|
2015-12-22 11:51:27 +00:00
|
|
|
return false;
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2017-05-07 12:40:58 +00:00
|
|
|
int idx = state.render_tiles[logical_device].front();
|
|
|
|
state.render_tiles[logical_device].pop_front();
|
|
|
|
tile = &state.tiles[idx];
|
2015-12-22 11:51:27 +00:00
|
|
|
return true;
|
2012-09-04 13:29:07 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
bool TileManager::done()
|
|
|
|
{
|
2016-03-30 13:55:12 +00:00
|
|
|
int end_sample = (range_num_samples == -1)
|
|
|
|
? num_samples
|
|
|
|
: range_start_sample + range_num_samples;
|
2017-08-14 22:11:52 +00:00
|
|
|
return (state.resolution_divider == pixel_size) &&
|
2016-03-30 13:55:12 +00:00
|
|
|
(state.sample+state.num_samples >= end_sample);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool TileManager::next()
|
|
|
|
{
|
|
|
|
if(done())
|
|
|
|
return false;
|
|
|
|
|
2017-08-14 22:11:52 +00:00
|
|
|
if(progressive && state.resolution_divider > pixel_size) {
|
2011-09-16 13:14:02 +00:00
|
|
|
state.sample = 0;
|
2017-08-14 22:11:52 +00:00
|
|
|
state.resolution_divider = max(state.resolution_divider/2, pixel_size);
|
2012-09-04 13:29:07 +00:00
|
|
|
state.num_samples = 1;
|
2011-04-27 11:58:34 +00:00
|
|
|
set_tiles();
|
|
|
|
}
|
|
|
|
else {
|
2011-09-16 13:14:02 +00:00
|
|
|
state.sample++;
|
2012-09-04 13:29:07 +00:00
|
|
|
|
|
|
|
if(progressive)
|
|
|
|
state.num_samples = 1;
|
2016-03-30 13:55:12 +00:00
|
|
|
else if(range_num_samples == -1)
|
2012-09-04 13:29:07 +00:00
|
|
|
state.num_samples = num_samples;
|
2016-03-30 13:55:12 +00:00
|
|
|
else
|
|
|
|
state.num_samples = range_num_samples;
|
2012-09-04 13:29:07 +00:00
|
|
|
|
2017-08-14 22:11:52 +00:00
|
|
|
state.resolution_divider = pixel_size;
|
2011-04-27 11:58:34 +00:00
|
|
|
set_tiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-30 13:55:12 +00:00
|
|
|
int TileManager::get_num_effective_samples()
|
|
|
|
{
|
|
|
|
return (range_num_samples == -1) ? num_samples
|
|
|
|
: range_num_samples;
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|
|
|
|
|