From ea18c6ef0abcdd5841d77175a67e2611dce446b5 Mon Sep 17 00:00:00 2001 From: Andre Susano Pinto Date: Sat, 29 Aug 2009 17:24:45 +0000 Subject: [PATCH] Code reorganization -separated vbvh, svbvh, qbvh in diferent files (before the only way to switch between them was at compile time) --- .../render/extern/include/RE_raytrace.h | 2 + source/blender/render/intern/raytrace/bvh.h | 59 ++- source/blender/render/intern/raytrace/qbvh.h | 0 .../render/intern/raytrace/rayobject_hint.h | 5 + .../render/intern/raytrace/rayobject_qbvh.cpp | 100 +++++ .../intern/raytrace/rayobject_svbvh.cpp | 104 +++++ .../render/intern/raytrace/rayobject_vbvh.cpp | 401 ++---------------- .../render/intern/raytrace/reorganize.h | 3 + source/blender/render/intern/raytrace/svbvh.h | 108 ++--- source/blender/render/intern/raytrace/vbvh.h | 186 ++++++++ .../blender/render/intern/source/rayshade.c | 2 +- 11 files changed, 523 insertions(+), 447 deletions(-) create mode 100644 source/blender/render/intern/raytrace/qbvh.h create mode 100644 source/blender/render/intern/raytrace/rayobject_qbvh.cpp create mode 100644 source/blender/render/intern/raytrace/rayobject_svbvh.cpp create mode 100644 source/blender/render/intern/raytrace/vbvh.h diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h index 864b6124db4..01b64c15058 100644 --- a/source/blender/render/extern/include/RE_raytrace.h +++ b/source/blender/render/extern/include/RE_raytrace.h @@ -102,6 +102,8 @@ RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], RayObject* RE_rayobject_blibvh_create(int size); /* BLI_kdopbvh.c */ RayObject* RE_rayobject_bvh_create(int size); /* raytrace/rayobject_bvh.c */ RayObject* RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */ +RayObject* RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_vbvh.c */ +RayObject* RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_vbvh.c */ RayObject* RE_rayobject_bih_create(int size); /* rayobject_bih.c */ typedef struct LCTSHint LCTSHint; diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h index 55bed6f0662..21234a40673 100644 --- a/source/blender/render/intern/raytrace/bvh.h +++ b/source/blender/render/intern/raytrace/bvh.h @@ -26,6 +26,12 @@ * * ***** END GPL LICENSE BLOCK ***** */ +#include "rayobject.h" +#include "MEM_guardedalloc.h" +#include "rayobject_rtbuild.h" +#include "rayobject_hint.h" + +#include #include #ifndef RE_RAYTRACE_BVH_H @@ -285,7 +291,6 @@ static int bvh_node_stack_raycast_simd(Node *root, Isect *isec) return hit; } - /* * recursively transverse a BVH looking for a rayhit using system stack */ @@ -336,4 +341,56 @@ static int bvh_node_raycast(Node *node, Isect *isec) } */ +template +void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject) +{ + assert( hint->size + reserve_space + 1 <= RE_RAY_LCTS_MAX_SIZE ); + + if(is_leaf(node)) + { + hint->stack[hint->size++] = (RayObject*)node; + } + else + { + int childs = count_childs(node); + if(hint->size + reserve_space + childs <= RE_RAY_LCTS_MAX_SIZE) + { + int result = hint_test_bb(hintObject, node->bb, node->bb+3); + if(result == HINT_RECURSE) + { + /* We are 100% sure the ray will be pass inside this node */ + bvh_dfs_make_hint_push_siblings(node->child, hint, reserve_space, hintObject); + } + else if(result == HINT_ACCEPT) + { + hint->stack[hint->size++] = (RayObject*)node; + } + } + else + { + hint->stack[hint->size++] = (RayObject*)node; + } + } +} + + +template +static RayObjectAPI* bvh_get_api(int maxstacksize); + + +template +static inline RayObject *bvh_create_tree(int size) +{ + Tree *obj= (Tree*)MEM_callocN(sizeof(Tree), "BVHTree" ); + assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */ + + obj->rayobj.api = bvh_get_api(DFS_STACK_SIZE); + obj->root = NULL; + + obj->node_arena = NULL; + obj->builder = rtbuild_create( size ); + + return RE_rayobject_unalignRayAPI((RayObject*) obj); +} + #endif diff --git a/source/blender/render/intern/raytrace/qbvh.h b/source/blender/render/intern/raytrace/qbvh.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h index cc8728a28cb..d85465aec66 100644 --- a/source/blender/render/intern/raytrace/rayobject_hint.h +++ b/source/blender/render/intern/raytrace/rayobject_hint.h @@ -26,6 +26,9 @@ * * ***** END GPL LICENSE BLOCK ***** */ +#ifndef RE_RAYTRACE_RAYOBJECT_HINT_H +#define RE_RAYTRACE_RAYOBJECT_HINT_H + #define HINT_RECURSE 1 #define HINT_ACCEPT 0 #define HINT_DISCARD -1 @@ -63,3 +66,5 @@ inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax) return HINT_ACCEPT; } */ + +#endif diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp new file mode 100644 index 00000000000..e3a15b5d7f3 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp @@ -0,0 +1,100 @@ +#include "vbvh.h" +#include "svbvh.h" +#include "qbvh.h" +#include "reorganize.h" + +#define DFS_STACK_SIZE 256 + +struct QBVHTree +{ + RayObject rayobj; + + SVBVHNode *root; + MemArena *node_arena; + + float cost; + RTBuilder *builder; +}; + + +template<> +void bvh_done(QBVHTree *obj) +{ + rtbuild_done(obj->builder); + + //TODO find a away to exactly calculate the needed memory + MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_malloc(arena1); + + MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_malloc(arena2); + BLI_memarena_use_align(arena2, 16); + + //Build and optimize the tree + VBVHNode *root = BuildBinaryVBVH(arena1).transform(obj->builder); + pushup_simd(root); + obj->root = Reorganize_SVBVH(arena2).transform(root); + + //Cleanup + BLI_memarena_free(arena1); + + rtbuild_free( obj->builder ); + obj->builder = NULL; + + obj->node_arena = arena2; + obj->cost = 1.0; +} + + +template +int intersect(QBVHTree *obj, Isect* isec) +{ + //TODO renable hint support + if(RE_rayobject_isAligned(obj->root)) + return bvh_node_stack_raycast( obj->root, isec); + else + return RE_rayobject_intersect( (RayObject*) obj->root, isec ); +} + +template +void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *min, float *max) +{ + //TODO renable hint support + { + hint->size = 0; + hint->stack[hint->size++] = (RayObject*)tree->root; + } +} +/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */ +template +RayObjectAPI make_api() +{ + static RayObjectAPI api = + { + (RE_rayobject_raycast_callback) ((int(*)(Tree*,Isect*)) &intersect), + (RE_rayobject_add_callback) ((void(*)(Tree*,RayObject*)) &bvh_add), + (RE_rayobject_done_callback) ((void(*)(Tree*)) &bvh_done), + (RE_rayobject_free_callback) ((void(*)(Tree*)) &bvh_free), + (RE_rayobject_merge_bb_callback)((void(*)(Tree*,float*,float*)) &bvh_bb), + (RE_rayobject_cost_callback) ((float(*)(Tree*)) &bvh_cost), + (RE_rayobject_hint_bb_callback) ((void(*)(Tree*,LCTSHint*,float*,float*)) &bvh_hint_bb) + }; + + return api; +} + +template +RayObjectAPI* bvh_get_api(int maxstacksize) +{ + static RayObjectAPI bvh_api256 = make_api(); + + if(maxstacksize <= 1024) return &bvh_api256; + assert(maxstacksize <= 256); + return 0; +} + + +RayObject *RE_rayobject_qbvh_create(int size) +{ + return bvh_create_tree(size); +} diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp new file mode 100644 index 00000000000..df033901526 --- /dev/null +++ b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp @@ -0,0 +1,104 @@ +#include "vbvh.h" +#include "svbvh.h" +#include "reorganize.h" + +#define DFS_STACK_SIZE 256 + +struct SVBVHTree +{ + RayObject rayobj; + + SVBVHNode *root; + MemArena *node_arena; + + float cost; + RTBuilder *builder; +}; + + +template<> +void bvh_done(SVBVHTree *obj) +{ + rtbuild_done(obj->builder); + + //TODO find a away to exactly calculate the needed memory + MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_malloc(arena1); + + //Build and optimize the tree + VBVHNode *root = BuildBinaryVBVH(arena1).transform(obj->builder); + + reorganize(root); + remove_useless(root, &root); + bvh_refit(root); + + pushup(root); + pushdown(root); + pushup_simd(root); + + MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_malloc(arena2); + BLI_memarena_use_align(arena2, 16); + obj->root = Reorganize_SVBVH(arena2).transform(root); + + BLI_memarena_free(arena1); + + obj->node_arena = arena2; + obj->cost = 1.0; + + + rtbuild_free( obj->builder ); + obj->builder = NULL; +} + +template +int intersect(SVBVHTree *obj, Isect* isec) +{ + //TODO renable hint support + if(RE_rayobject_isAligned(obj->root)) + return bvh_node_stack_raycast( obj->root, isec); + else + return RE_rayobject_intersect( (RayObject*) obj->root, isec ); +} + +template +void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *min, float *max) +{ + //TODO renable hint support + { + hint->size = 0; + hint->stack[hint->size++] = (RayObject*)tree->root; + } +} +/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */ +template +RayObjectAPI make_api() +{ + static RayObjectAPI api = + { + (RE_rayobject_raycast_callback) ((int(*)(Tree*,Isect*)) &intersect), + (RE_rayobject_add_callback) ((void(*)(Tree*,RayObject*)) &bvh_add), + (RE_rayobject_done_callback) ((void(*)(Tree*)) &bvh_done), + (RE_rayobject_free_callback) ((void(*)(Tree*)) &bvh_free), + (RE_rayobject_merge_bb_callback)((void(*)(Tree*,float*,float*)) &bvh_bb), + (RE_rayobject_cost_callback) ((float(*)(Tree*)) &bvh_cost), + (RE_rayobject_hint_bb_callback) ((void(*)(Tree*,LCTSHint*,float*,float*)) &bvh_hint_bb) + }; + + return api; +} + +template +RayObjectAPI* bvh_get_api(int maxstacksize) +{ + static RayObjectAPI bvh_api256 = make_api(); + + if(maxstacksize <= 1024) return &bvh_api256; + assert(maxstacksize <= 256); + return 0; +} + +RayObject *RE_rayobject_svbvh_create(int size) +{ + return bvh_create_tree(size); +} diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp index 6ec8fab15e4..f81ca1e5d1b 100644 --- a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp +++ b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp @@ -26,385 +26,82 @@ * * ***** END GPL LICENSE BLOCK ***** */ -#define RE_USE_HINT (0) -static int tot_pushup = 0; -static int tot_pushdown = 0; -static int tot_hints = 0; +int tot_pushup = 0; +int tot_pushdown = 0; +int tot_hints = 0; -extern "C" -{ #include +#include "rayobject.h" +#include "rayobject_rtbuild.h" +#include "RE_raytrace.h" +#include "BLI_memarena.h" #include "MEM_guardedalloc.h" #include "BKE_utildefines.h" #include "BLI_arithb.h" -#include "BLI_memarena.h" -#include "RE_raytrace.h" -#include "rayobject_rtbuild.h" -#include "rayobject.h" -}; -#include "rayobject_hint.h" #include "reorganize.h" #include "bvh.h" +#include "vbvh.h" #include "svbvh.h" #include +#include - -#define RE_DO_HINTS (0) -#define RAY_BB_TEST_COST (0.2f) #define DFS_STACK_SIZE 256 -//#define DYNAMIC_ALLOC_BB - - -//#define rtbuild_split rtbuild_mean_split_largest_axis /* objects mean split on the longest axis, childs BB are allowed to overlap */ -//#define rtbuild_split rtbuild_median_split_largest_axis /* space median split on the longest axis, childs BB are allowed to overlap */ -#define rtbuild_split rtbuild_heuristic_object_split /* split objects using heuristic */ - -struct VBVHNode -{ -#ifdef DYNAMIC_ALLOC_BB - float *bb; -#else - float bb[6]; -#endif - - VBVHNode *child; - VBVHNode *sibling; -}; struct VBVHTree { RayObject rayobj; - - SVBVHNode *root; - + VBVHNode *root; MemArena *node_arena; - float cost; RTBuilder *builder; }; - - -template -struct Reorganize_VBVH -{ - Tree *tree; - - Reorganize_VBVH(Tree *t) - { - tree = t; - } - - VBVHNode *create_node() - { - VBVHNode *node = (VBVHNode*)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode)); - return node; - } - - void copy_bb(VBVHNode *node, OldNode *old) - { - std::copy( old->bb, old->bb+6, node->bb ); - } - - VBVHNode *transform(OldNode *old) - { - if(is_leaf(old)) - return (VBVHNode*)old; - - VBVHNode *node = create_node(); - VBVHNode **child_ptr = &node->child; - node->sibling = 0; - - copy_bb(node,old); - - for(OldNode *o_child = old->child; o_child; o_child = o_child->sibling) - { - VBVHNode *n_child = transform(o_child); - *child_ptr = n_child; - if(is_leaf(n_child)) return node; - child_ptr = &n_child->sibling; - } - *child_ptr = 0; - - return node; - } -}; - - -/* - * Push nodes (used on dfs) - */ -template -inline static void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos) -{ - Node *child = node->child; - - if(is_leaf(child)) - { - stack[stack_pos++] = child; - } - else - { - while(child) - { - //Skips BB tests on primitives -/* - if(is_leaf(child->child)) - stack[stack_pos++] = child->child; - else -*/ - stack[stack_pos++] = child; - - child = child->sibling; - } - } -} - -/* - * BVH done - */ -static VBVHNode *bvh_new_node(VBVHTree *tree) -{ - VBVHNode *node = (VBVHNode*)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode)); - - if( (((intptr_t)node) & (0x0f)) != 0 ) - { - puts("WRONG!"); - printf("%08x\n", (intptr_t)node); - } - node->sibling = NULL; - node->child = NULL; - -#ifdef DYNAMIC_ALLOC_BB - node->bb = (float*)BLI_memarena_alloc(tree->node_arena, 6*sizeof(float)); -#endif - assert(RE_rayobject_isAligned(node)); - return node; -} - - - -template -int count_childs(Node *parent) -{ - int n = 0; - for(Node *i = parent->child; i; i = i->sibling) - { - n++; - if(is_leaf(i)) - break; - } - - return n; -} - -template -void append_sibling(Node *node, Node *sibling) -{ - while(node->sibling) - node = node->sibling; - - node->sibling = sibling; -} - - -template -Node *bvh_rearrange(Tree *tree, Builder *builder) -{ - - int size = rtbuild_size(builder); - if(size == 1) - { - Node *node = bvh_new_node(tree); - INIT_MINMAX(node->bb, node->bb+3); - rtbuild_merge_bb(builder, node->bb, node->bb+3); - node->child = (VBVHNode*) rtbuild_get_primitive( builder, 0 ); - return node; - } - else - { - Node *node = bvh_new_node(tree); - - INIT_MINMAX(node->bb, node->bb+3); - rtbuild_merge_bb(builder, node->bb, node->bb+3); - - Node **child = &node->child; - - int nc = rtbuild_split(builder, 2); - assert(nc == 2); - for(int i=0; i(tree, &tmp); - child = &((*child)->sibling); - } - - *child = 0; - return node; - } -} - template<> void bvh_done(VBVHTree *obj) { rtbuild_done(obj->builder); - int needed_nodes = (rtbuild_size(obj->builder)+1)*2; - if(needed_nodes > BLI_MEMARENA_STD_BUFSIZE) - needed_nodes = BLI_MEMARENA_STD_BUFSIZE; + //TODO find a away to exactly calculate the needed memory + MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE); + BLI_memarena_use_malloc(arena1); - MemArena *arena1 = BLI_memarena_new(needed_nodes); - BLI_memarena_use_malloc(arena1); - BLI_memarena_use_align(arena1, 16); - obj->node_arena = arena1; - VBVHNode *root = bvh_rearrange( obj, obj->builder ); + //Build and optimize the tree + VBVHNode *root = BuildBinaryVBVH(arena1).transform(obj->builder); + reorganize(root); remove_useless(root, &root); - printf("refit: %f\n", bvh_refit(root) ); + bvh_refit(root); pushup(root); pushdown(root); - pushup_simd(root); - //Memory re-organize - if(0) - { - MemArena *arena2 = BLI_memarena_new(needed_nodes); - BLI_memarena_use_malloc(arena2); - BLI_memarena_use_align(arena2, 16); - obj->node_arena = arena2; - root = Reorganize_VBVH(obj).transform(root); - - BLI_memarena_free(arena1); - } - - if(1) - { - MemArena *arena2 = BLI_memarena_new(needed_nodes); - BLI_memarena_use_malloc(arena2); - BLI_memarena_use_align(arena2, 16); - obj->node_arena = arena2; - obj->root = Reorganize_SVBVH(obj).transform(root); - - BLI_memarena_free(arena1); - } -/* - { - obj->root = root; - } -*/ - - obj->cost = 1.0; - + //Cleanup rtbuild_free( obj->builder ); obj->builder = NULL; + + obj->node_arena = arena1; + obj->root = root; + obj->cost = 1.0; } template int intersect(VBVHTree *obj, Isect* isec) { -/* - if(RE_DO_HINTS && isec->hint) - { - LCTSHint *lcts = (LCTSHint*)isec->hint; - isec->hint = 0; - - int hit = 0; - for(int i=0; isize; i++) - { - VBVHNode *node = (VBVHNode*)lcts->stack[i]; - if(RE_rayobject_isAligned(node)) - hit |= bvh_node_stack_raycast(node, isec); - else - hit |= RE_rayobject_intersect( (RayObject*)node, isec ); - - if(hit && isec->mode == RE_RAY_SHADOW) - break; - } - isec->hint = (RayHint*)lcts; - return hit; - } + //TODO renable hint support + if(RE_rayobject_isAligned(obj->root)) + return bvh_node_stack_raycast( obj->root, isec); else -*/ - { - if(RE_rayobject_isAligned(obj->root)) - return bvh_node_stack_raycast( obj->root, isec); - else - return RE_rayobject_intersect( (RayObject*) obj->root, isec ); - } -} - -template -void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject); - -template -void bvh_dfs_make_hint_push_siblings(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject) -{ - if(!RE_rayobject_isAligned(node)) - hint->stack[hint->size++] = (RayObject*)node; - else - { - if(node->sibling) - bvh_dfs_make_hint_push_siblings(node->sibling, hint, reserve_space+1, hintObject); - - bvh_dfs_make_hint(node, hint, reserve_space, hintObject); - } -} - -template -void bvh_dfs_make_hint(Node *node, LCTSHint *hint, int reserve_space, HintObject *hintObject) -{ - assert( hint->size + reserve_space + 1 <= RE_RAY_LCTS_MAX_SIZE ); - - if(is_leaf(node)) - { - hint->stack[hint->size++] = (RayObject*)node; - } - else - { - int childs = count_childs(node); - if(hint->size + reserve_space + childs <= RE_RAY_LCTS_MAX_SIZE) - { - int result = hint_test_bb(hintObject, node->bb, node->bb+3); - if(result == HINT_RECURSE) - { - /* We are 100% sure the ray will be pass inside this node */ - bvh_dfs_make_hint_push_siblings(node->child, hint, reserve_space, hintObject); - } - else if(result == HINT_ACCEPT) - { - hint->stack[hint->size++] = (RayObject*)node; - } - } - else - { - hint->stack[hint->size++] = (RayObject*)node; - } - } + return RE_rayobject_intersect( (RayObject*) obj->root, isec ); } template void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *min, float *max) { -/* - if(RE_USE_HINT) - { - HintBB bb; - VECCOPY(bb.bb, min); - VECCOPY(bb.bb+3, max); - - hint->size = 0; - bvh_dfs_make_hint( tree->root, hint, 0, &bb ); - tot_hints++; - } - else -*/ + //TODO renable hint support { hint->size = 0; hint->stack[hint->size++] = (RayObject*)tree->root; @@ -428,16 +125,15 @@ void bfree(VBVHTree *tree) } /* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */ -template -static RayObjectAPI make_api() +template +RayObjectAPI make_api() { static RayObjectAPI api = { (RE_rayobject_raycast_callback) ((int(*)(Tree*,Isect*)) &intersect), (RE_rayobject_add_callback) ((void(*)(Tree*,RayObject*)) &bvh_add), (RE_rayobject_done_callback) ((void(*)(Tree*)) &bvh_done), -// (RE_rayobject_free_callback) ((void(*)(Tree*)) &bvh_free), - (RE_rayobject_free_callback) ((void(*)(Tree*)) &bfree), + (RE_rayobject_free_callback) ((void(*)(Tree*)) &bvh_free), (RE_rayobject_merge_bb_callback)((void(*)(Tree*,float*,float*)) &bvh_bb), (RE_rayobject_cost_callback) ((float(*)(Tree*)) &bvh_cost), (RE_rayobject_hint_bb_callback) ((void(*)(Tree*,LCTSHint*,float*,float*)) &bvh_hint_bb) @@ -447,7 +143,7 @@ static RayObjectAPI make_api() } template -static RayObjectAPI* get_api(int maxstacksize) +RayObjectAPI* bvh_get_api(int maxstacksize) { static RayObjectAPI bvh_api256 = make_api(); @@ -458,38 +154,5 @@ static RayObjectAPI* get_api(int maxstacksize) RayObject *RE_rayobject_vbvh_create(int size) { - VBVHTree *obj= (VBVHTree*)MEM_callocN(sizeof(VBVHTree), "VBVHTree"); - assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */ - - obj->rayobj.api = get_api(DFS_STACK_SIZE); - obj->root = NULL; - - obj->node_arena = NULL; - obj->builder = rtbuild_create( size ); - - return RE_rayobject_unalignRayAPI((RayObject*) obj); + return bvh_create_tree(size); } - - - -/* SVBVH */ -template -void bvh_dfs_make_hint(VBVHNode *node, LCTSHint *hint, int reserve_space, HintObject *hintObject) -{ - return; -} -/* -RayObject *RE_rayobject_svbvh_create(int size) -{ - SVBVHTree *obj= (SVBVHTree*)MEM_callocN(sizeof(SVBVHTree), "SVBVHTree"); - assert( RE_rayobject_isAligned(obj) ); // RayObject API assumes real data to be 4-byte aligned - - obj->rayobj.api = get_api(DFS_STACK_SIZE); - obj->root = NULL; - - obj->node_arena = NULL; - obj->builder = rtbuild_create( size ); - - return RE_rayobject_unalignRayAPI((RayObject*) obj); -} -*/ \ No newline at end of file diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h index 2494f102003..712221fb739 100644 --- a/source/blender/render/intern/raytrace/reorganize.h +++ b/source/blender/render/intern/raytrace/reorganize.h @@ -29,6 +29,9 @@ #include #include +extern int tot_pushup; +extern int tot_pushdown; + template bool node_fits_inside(Node *a, Node *b) { diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h index 95f1c40765e..b243e91d381 100644 --- a/source/blender/render/intern/raytrace/svbvh.h +++ b/source/blender/render/intern/raytrace/svbvh.h @@ -29,10 +29,10 @@ #ifndef RE_RAYTRACE_SVBVH_H #define RE_RAYTRACE_SVBVH_H -#define SVBVH_SIMD 1 - #include "bvh.h" +#include "BLI_memarena.h" #include +#include struct SVBVHNode { @@ -52,38 +52,27 @@ inline int bvh_node_hit_test(SVBVHNode *node, Isect *isec) template<> inline void bvh_node_push_childs(SVBVHNode *node, Isect *isec, SVBVHNode **stack, int &stack_pos) { - if(SVBVH_SIMD) + int i=0; + while(i+4 <= node->nchilds) { - int i=0; - while(i+4 <= node->nchilds) - { - int res = test_bb_group4( (__m128*) (node->child_bb+6*i), isec ); - RE_RC_COUNT(isec->raycounter->bb.test); - RE_RC_COUNT(isec->raycounter->bb.test); - RE_RC_COUNT(isec->raycounter->bb.test); - RE_RC_COUNT(isec->raycounter->bb.test); - - if(res & 1) { stack[stack_pos++] = node->child[i+0]; RE_RC_COUNT(isec->raycounter->bb.hit); } - if(res & 2) { stack[stack_pos++] = node->child[i+1]; RE_RC_COUNT(isec->raycounter->bb.hit); } - if(res & 4) { stack[stack_pos++] = node->child[i+2]; RE_RC_COUNT(isec->raycounter->bb.hit); } - if(res & 8) { stack[stack_pos++] = node->child[i+3]; RE_RC_COUNT(isec->raycounter->bb.hit); } - - i += 4; - } - while(i < node->nchilds) - { - if(RE_rayobject_bb_intersect_test(isec, (const float*)node->child_bb+6*i)) - stack[stack_pos++] = node->child[i]; - i++; - } + int res = test_bb_group4( (__m128*) (node->child_bb+6*i), isec ); + RE_RC_COUNT(isec->raycounter->bb.test); + RE_RC_COUNT(isec->raycounter->bb.test); + RE_RC_COUNT(isec->raycounter->bb.test); + RE_RC_COUNT(isec->raycounter->bb.test); + + if(res & 1) { stack[stack_pos++] = node->child[i+0]; RE_RC_COUNT(isec->raycounter->bb.hit); } + if(res & 2) { stack[stack_pos++] = node->child[i+1]; RE_RC_COUNT(isec->raycounter->bb.hit); } + if(res & 4) { stack[stack_pos++] = node->child[i+2]; RE_RC_COUNT(isec->raycounter->bb.hit); } + if(res & 8) { stack[stack_pos++] = node->child[i+3]; RE_RC_COUNT(isec->raycounter->bb.hit); } + + i += 4; } - else + while(i < node->nchilds) { - for(int i=0; inchilds; i++) - { - if(RE_rayobject_bb_intersect_test(isec, (const float*)node->child_bb+6*i)) - stack[stack_pos++] = node->child[i]; - } + if(RE_rayobject_bb_intersect_test(isec, (const float*)node->child_bb+6*i)) + stack[stack_pos++] = node->child[i]; + i++; } } @@ -97,7 +86,7 @@ void bvh_node_merge_bb(SVBVHNode *node, float *min, float *max) else { int i=0; - while(SVBVH_SIMD && i+4 <= node->nchilds) + while(i+4 <= node->nchilds) { float *res = node->child_bb + 6*i; for(int j=0; j<3; j++) @@ -126,33 +115,24 @@ void bvh_node_merge_bb(SVBVHNode *node, float *min, float *max) } } -struct SVBVHTree -{ - RayObject rayobj; - - SVBVHNode *root; - - MemArena *node_arena; - - float cost; - RTBuilder *builder; -}; - -template +/* + * Builds a SVBVH tree form a VBVHTree + */ +template struct Reorganize_SVBVH { - Tree *tree; + MemArena *arena; float childs_per_node; int nodes_with_childs[16]; int useless_bb; int nodes; - Reorganize_SVBVH(Tree *t) + Reorganize_SVBVH(MemArena *a) { - tree = t; + arena = a; nodes = 0; childs_per_node = 0; useless_bb = 0; @@ -171,10 +151,10 @@ struct Reorganize_SVBVH SVBVHNode *create_node(int nchilds) { - SVBVHNode *node = (SVBVHNode*)BLI_memarena_alloc(tree->node_arena, sizeof(SVBVHNode)); + SVBVHNode *node = (SVBVHNode*)BLI_memarena_alloc(arena, sizeof(SVBVHNode)); node->nchilds = nchilds; - node->child_bb = (float*)BLI_memarena_alloc(tree->node_arena, sizeof(float)*6*nchilds); - node->child= (SVBVHNode**)BLI_memarena_alloc(tree->node_arena, sizeof(SVBVHNode*)*nchilds); + node->child_bb = (float*)BLI_memarena_alloc(arena, sizeof(float)*6*nchilds); + node->child= (SVBVHNode**)BLI_memarena_alloc(arena, sizeof(SVBVHNode*)*nchilds); return node; } @@ -200,29 +180,7 @@ struct Reorganize_SVBVH res[4*j+2] = vec_tmp[6*2+j]; res[4*j+3] = vec_tmp[6*3+j]; } -/* - const float *bb0 = vec_tmp+6*(i+0); - const float *bb1 = vec_tmp+6*(i+1); - const float *bb2 = vec_tmp+6*(i+2); - const float *bb3 = vec_tmp+6*(i+3); - //memmoves could be memory alligned - const __m128 x0y0x1y1 = _mm_shuffle_ps( _mm_loadu_ps(bb0), _mm_loadu_ps(bb1), _MM_SHUFFLE(1,0,1,0) ); - const __m128 x2y2x3y3 = _mm_shuffle_ps( _mm_loadu_ps(bb2), _mm_loadu_ps(bb3), _MM_SHUFFLE(1,0,1,0) ); - _mm_store_ps( node->child_bb+6*i+4*0, _mm_shuffle_ps( x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(2,0,2,0) ) ); - _mm_store_ps( node->child_bb+6*i+4*1, _mm_shuffle_ps( x0y0x1y1, x2y2x3y3, _MM_SHUFFLE(3,1,3,1) ) ); - - const __m128 z0X0z1X1 = _mm_shuffle_ps( _mm_loadu_ps(bb0), _mm_loadu_ps(bb1), _MM_SHUFFLE(3,2,3,2) ); - const __m128 z2X2z3X3 = _mm_shuffle_ps( _mm_loadu_ps(bb2), _mm_loadu_ps(bb3), _MM_SHUFFLE(3,2,3,2) ); - _mm_store_ps( node->child_bb+6*i+4*2, _mm_shuffle_ps( z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(2,0,2,0) ) ); - _mm_store_ps( node->child_bb+6*i+4*3, _mm_shuffle_ps( z0X0z1X1, z2X2z3X3, _MM_SHUFFLE(3,1,3,1) ) ); - - const __m128 Y0Z0Y1Z1 = _mm_shuffle_ps( _mm_loadu_ps(bb0+4), _mm_loadu_ps(bb1+4), _MM_SHUFFLE(1,0,1,0) ); - const __m128 Y2Z2Y3Z3 = _mm_shuffle_ps( _mm_loadu_ps(bb2+4), _mm_loadu_ps(bb3+4), _MM_SHUFFLE(1,0,1,0) ); - _mm_store_ps( node->child_bb+6*i+4*4, _mm_shuffle_ps( Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(2,0,2,0) ) ); - _mm_store_ps( node->child_bb+6*i+4*5, _mm_shuffle_ps( Y0Z0Y1Z1, Y2Z2Y3Z3, _MM_SHUFFLE(3,1,3,1) ) ); - */ - i += 4; } } @@ -280,10 +238,8 @@ struct Reorganize_SVBVH } } assert( i == 0 ); - - if(SVBVH_SIMD) - prepare_for_simd(node); + prepare_for_simd(node); return node; } diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h new file mode 100644 index 00000000000..7c07bd9ded0 --- /dev/null +++ b/source/blender/render/intern/raytrace/vbvh.h @@ -0,0 +1,186 @@ +#include + +#include +#include "rayobject_rtbuild.h" +#include "BLI_memarena.h" + + +/* + * VBVHNode represents a BVHNode with support for a variable number of childrens + */ +struct VBVHNode +{ + float bb[6]; + + VBVHNode *child; + VBVHNode *sibling; +}; + + +/* + * Push nodes (used on dfs) + */ +template +inline static void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos) +{ + Node *child = node->child; + + if(is_leaf(child)) + { + stack[stack_pos++] = child; + } + else + { + while(child) + { + //Skips BB tests on primitives +/* + if(is_leaf(child->child)) + stack[stack_pos++] = child->child; + else +*/ + stack[stack_pos++] = child; + + child = child->sibling; + } + } +} + + +template +int count_childs(Node *parent) +{ + int n = 0; + for(Node *i = parent->child; i; i = i->sibling) + { + n++; + if(is_leaf(i)) + break; + } + + return n; +} + + +template +void append_sibling(Node *node, Node *sibling) +{ + while(node->sibling) + node = node->sibling; + + node->sibling = sibling; +} + + +/* + * Builds a binary VBVH from a rtbuild + */ +struct BuildBinaryVBVH +{ + MemArena *arena; + + BuildBinaryVBVH(MemArena *a) + { + arena = a; + } + + VBVHNode *create_node() + { + VBVHNode *node = (VBVHNode*)BLI_memarena_alloc( arena, sizeof(VBVHNode) ); + assert( RE_rayobject_isAligned(node) ); + + node->sibling = NULL; + node->child = NULL; + + return node; + } + + int rtbuild_split(RTBuilder *builder) + { + return ::rtbuild_heuristic_object_split(builder, 2); + } + + VBVHNode *transform(RTBuilder *builder) + { + + int size = rtbuild_size(builder); + if(size == 1) + { + VBVHNode *node = create_node(); + INIT_MINMAX(node->bb, node->bb+3); + rtbuild_merge_bb(builder, node->bb, node->bb+3); + node->child = (VBVHNode*) rtbuild_get_primitive( builder, 0 ); + return node; + } + else + { + VBVHNode *node = create_node(); + + INIT_MINMAX(node->bb, node->bb+3); + rtbuild_merge_bb(builder, node->bb, node->bb+3); + + VBVHNode **child = &node->child; + + int nc = rtbuild_split(builder); + assert(nc == 2); + for(int i=0; isibling); + } + + *child = 0; + return node; + } + } +}; + +/* +template +struct Reorganize_VBVH +{ + Tree *tree; + + Reorganize_VBVH(Tree *t) + { + tree = t; + } + + VBVHNode *create_node() + { + VBVHNode *node = (VBVHNode*)BLI_memarena_alloc(tree->node_arena, sizeof(VBVHNode)); + return node; + } + + void copy_bb(VBVHNode *node, OldNode *old) + { + std::copy( old->bb, old->bb+6, node->bb ); + } + + VBVHNode *transform(OldNode *old) + { + if(is_leaf(old)) + return (VBVHNode*)old; + + VBVHNode *node = create_node(); + VBVHNode **child_ptr = &node->child; + node->sibling = 0; + + copy_bb(node,old); + + for(OldNode *o_child = old->child; o_child; o_child = o_child->sibling) + { + VBVHNode *n_child = transform(o_child); + *child_ptr = n_child; + if(is_leaf(n_child)) return node; + child_ptr = &n_child->sibling; + } + *child_ptr = 0; + + return node; + } +}; +*/ \ No newline at end of file diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index af2c0f99174..928083620e1 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -75,7 +75,7 @@ RayObject * RE_rayobject_tree_create(int type, int size) __attribute__((noinlin RayObject * RE_rayobject_tree_create(int type, int size) { // if(type == R_RAYTRACE_TREE_BIH) - return RE_rayobject_vbvh_create(size); + return RE_rayobject_svbvh_create(size); if(type == R_RAYTRACE_TREE_BVH) return RE_rayobject_bvh_create(size);