Commit: 6995b4d8d96a14ea574f85658b73504fa0d8070a
Author: Lukas Stockner
Date:   Sun Jan 10 00:11:34 2016 +0100
Branches: master
https://developer.blender.org/rB6995b4d8d96a14ea574f85658b73504fa0d8070a

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

===================================================================

M       intern/cycles/blender/addon/properties.py
M       intern/cycles/render/tile.cpp
M       intern/cycles/render/tile.h
M       intern/cycles/util/util_math.h

===================================================================

diff --git a/intern/cycles/blender/addon/properties.py 
b/intern/cycles/blender/addon/properties.py
index f48bc93..a64a033 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -92,6 +92,7 @@ enum_tile_order = (
     ('LEFT_TO_RIGHT', "Left to Right", "Render from left to right"),
     ('TOP_TO_BOTTOM', "Top to Bottom", "Render from top to bottom"),
     ('BOTTOM_TO_TOP', "Bottom to Top", "Render from bottom to top"),
+    ('HILBERT_SPIRAL', "Hilbert Spiral", "Render in a Hilbert Spiral"),
     )
 
 enum_use_layer_samples = (
diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp
index 37b9647..3fb6073 100644
--- a/intern/cycles/render/tile.cpp
+++ b/intern/cycles/render/tile.cpp
@@ -58,6 +58,31 @@ protected:
        int2 center_;
 };
 
+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,
+};
+
 }  /* namespace */
 
 TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, 
int start_resolution_,
@@ -132,6 +157,100 @@ int TileManager::gen_tiles(bool sliced)
        state.tiles.resize(num);
        vector<list<Tile> >::iterator tile_list = state.tiles.begin();
 
+       if(tile_order == TILE_HILBERT_SPIRAL) {
+               assert(!sliced);
+
+               /* 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;
+
+               int tile_w = (tile_size.x >= image_w)? 1: (image_w + 
tile_size.x - 1)/tile_size.x;
+               int tile_h = (tile_size.y >= image_h)? 1: (image_h + 
tile_size.y - 1)/tile_size.y;
+               int tiles_per_device = (tile_w * tile_h + num - 1) / num;
+               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 */
+               int blocks_x = (block_size.x >= image_w)? 1: (image_w + 
block_size.x - 1)/block_size.x;
+               int blocks_y = (block_size.y >= image_h)? 1: (image_h + 
block_size.y - 1)/block_size.y;
+               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);
+                                       tile_list->push_front(Tile(tile_index, 
pos.x, pos.y, w, h, cur_device));
+                                       cur_tiles++;
+                                       tile_index++;
+
+                                       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;
+                       }
+               }
+               return tile_index;
+       }
+
        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;
diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h
index 09e1b25..700e00c 100644
--- a/intern/cycles/render/tile.h
+++ b/intern/cycles/render/tile.h
@@ -47,7 +47,8 @@ enum TileOrder {
        TILE_RIGHT_TO_LEFT = 1,
        TILE_LEFT_TO_RIGHT = 2,
        TILE_TOP_TO_BOTTOM = 3,
-       TILE_BOTTOM_TO_TOP = 4
+       TILE_BOTTOM_TO_TOP = 4,
+       TILE_HILBERT_SPIRAL = 5,
 };
 
 /* Tile Manager */
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index 4a676d0..f3fd1b3 100644
--- a/intern/cycles/util/util_math.h
+++ b/intern/cycles/util/util_math.h
@@ -939,6 +939,37 @@ ccl_device_inline void print_float4(const char *label, 
const float4& a)
 
 #endif
 
+/* Int2 */
+
+#ifndef __KERNEL_OPENCL__
+
+ccl_device_inline int2 operator+(const int2 &a, const int2 &b)
+{
+       return make_int2(a.x + b.x, a.y + b.y);
+}
+
+ccl_device_inline int2 operator+=(int2 &a, const int2 &b)
+{
+       return a = a + b;
+}
+
+ccl_device_inline int2 operator-(const int2 &a, const int2 &b)
+{
+       return make_int2(a.x - b.x, a.y - b.y);
+}
+
+ccl_device_inline int2 operator*(const int2 &a, const int2 &b)
+{
+       return make_int2(a.x * b.x, a.y * b.y);
+}
+
+ccl_device_inline int2 operator/(const int2 &a, const int2 &b)
+{
+       return make_int2(a.x / b.x, a.y / b.y);
+}
+
+#endif
+
 /* Int3 */
 
 #ifndef __KERNEL_OPENCL__

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to