Compare commits

...
6 Commits
14 changed files with 2563 additions and 189 deletions
+17 -17
View File
@@ -23,22 +23,22 @@ namespace embree
#if defined(VECTOR_INIT_ALLOCATOR)
template<typename M>
vector_t (M alloc)
vector_t (M alloc)
: alloc(alloc), size_active(0), size_alloced(0), items(nullptr) {}
template<typename M>
vector_t (M alloc, size_t sz)
vector_t (M alloc, size_t sz)
: alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { resize(sz); }
#else
vector_t ()
vector_t ()
: size_active(0), size_alloced(0), items(nullptr) {}
vector_t (size_t sz)
vector_t (size_t sz)
: size_active(0), size_alloced(0), items(nullptr) { resize(sz); }
#endif
~vector_t() {
clear();
}
@@ -51,7 +51,7 @@ namespace embree
for (size_t i=0; i<size_active; i++) items[i] = other.items[i];
}
vector_t& operator=(const vector_t& other)
vector_t& operator=(const vector_t& other)
{
resize(other.size_active);
for (size_t i=0; i<size_active; i++) items[i] = other.items[i];
@@ -75,10 +75,10 @@ namespace embree
internal_resize(new_size,size_alloced < new_size ? new_size : size_alloced);
}
void reserve(size_t new_alloced)
void reserve(size_t new_alloced)
{
/* do nothing if container already large enough */
if (new_alloced <= size_alloced)
if (new_alloced <= size_alloced)
return;
/* resize exact otherwise */
@@ -103,10 +103,10 @@ namespace embree
__forceinline T* data() { return items; };
__forceinline const T* data() const { return items; };
/******************** Modifiers **************************/
__forceinline void push_back(const T& nt)
__forceinline void push_back(const T& nt)
{
const T v = nt; // need local copy as input reference could point to this vector
internal_grow(size_active+1);
@@ -118,12 +118,12 @@ namespace embree
size_active--;
}
void clear()
void clear()
{
/* destroy elements */
for (size_t i=0; i<size_active; i++)
alloc.destroy(&items[i]);
/* free memory */
alloc.deallocate(items,size_alloced); items = nullptr;
size_active = size_alloced = 0;
@@ -133,7 +133,7 @@ namespace embree
void internal_resize(size_t new_active, size_t new_alloced)
{
assert(new_active <= new_alloced);
assert(new_active <= new_alloced);
/* destroy elements */
for (size_t i=new_active; i<size_active; i++)
@@ -143,9 +143,9 @@ namespace embree
size_active = new_active;
/* only reallocate if necessary */
if (new_alloced == size_alloced)
if (new_alloced == size_alloced)
return;
/* reallocate and copy items */
T* old_items = items;
items = alloc.allocate(new_alloced);
@@ -157,7 +157,7 @@ namespace embree
void internal_grow(size_t new_alloced)
{
/* do nothing if container already large enough */
if (new_alloced <= size_alloced)
if (new_alloced <= size_alloced)
return;
/* resize to next power of 2 otherwise */
+366
View File
@@ -0,0 +1,366 @@
//
// IndexSort.cpp
// RayAccelerator
//
// Created by Rasmus Barringer on 2014-09-03.
// Copyright (c) 2014 Rasmus Barringer. All rights reserved.
//
#include "IndexSort.h"
#include <immintrin.h>
#include <algorithm>
void sortedIndicesFromFloats(float* __restrict values, unsigned* __restrict indices, unsigned count) {
long long* keys = reinterpret_cast<long long*>(indices);
__m256i i0 = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7);
__m256i i1 = _mm256_setr_epi32(8, 9, 10, 11, 12, 13, 14, 15);
__m256i i2 = _mm256_setr_epi32(16, 17, 18, 19, 20, 21, 22, 23);
__m256i i3 = _mm256_setr_epi32(24, 25, 26, 27, 28, 29, 30, 31);
__m256i increment = _mm256_set1_epi32(32);
__m256i signMask = _mm256_set1_epi32(0x80000000);
unsigned i = 0;
for (; i+31 < count; i += 32) {
const __m256i* input = reinterpret_cast<const __m256i*>(values + i);
__m256i* output = reinterpret_cast<__m256i*>(keys + i);
__m256i value0 = _mm256_load_si256(input + 0);
__m256i value1 = _mm256_load_si256(input + 1);
__m256i value2 = _mm256_load_si256(input + 2);
__m256i value3 = _mm256_load_si256(input + 3);
__m256i absValue0 = _mm256_andnot_si256(signMask, value0);
__m256i absValue1 = _mm256_andnot_si256(signMask, value1);
__m256i absValue2 = _mm256_andnot_si256(signMask, value2);
__m256i absValue3 = _mm256_andnot_si256(signMask, value3);
__m256i encodedValue0 = _mm256_sign_epi32(absValue0, value0);
__m256i encodedValue1 = _mm256_sign_epi32(absValue1, value1);
__m256i encodedValue2 = _mm256_sign_epi32(absValue2, value2);
__m256i encodedValue3 = _mm256_sign_epi32(absValue3, value3);
__m256i key00 = _mm256_unpacklo_epi32(i0, encodedValue0);
__m256i key01 = _mm256_unpackhi_epi32(i0, encodedValue0);
__m256i key10 = _mm256_unpacklo_epi32(i1, encodedValue1);
__m256i key11 = _mm256_unpackhi_epi32(i1, encodedValue1);
__m256i key20 = _mm256_unpacklo_epi32(i2, encodedValue2);
__m256i key21 = _mm256_unpackhi_epi32(i2, encodedValue2);
__m256i key30 = _mm256_unpacklo_epi32(i3, encodedValue3);
__m256i key31 = _mm256_unpackhi_epi32(i3, encodedValue3);
_mm256_store_si256(output + 0, key00);
_mm256_store_si256(output + 1, key01);
_mm256_store_si256(output + 2, key10);
_mm256_store_si256(output + 3, key11);
_mm256_store_si256(output + 4, key20);
_mm256_store_si256(output + 5, key21);
_mm256_store_si256(output + 6, key30);
_mm256_store_si256(output + 7, key31);
i0 = _mm256_add_epi32(i0, increment);
i1 = _mm256_add_epi32(i1, increment);
i2 = _mm256_add_epi32(i2, increment);
i3 = _mm256_add_epi32(i3, increment);
}
for (; i < count; ++i) {
int input = *reinterpret_cast<const int*>(values + i);
int absInput = input & 0x7fffffff;
if (input < 0)
absInput = -absInput;
keys[i] = ((long long)absInput << 32) | i;
}
std::sort(keys, keys + count);
for (unsigned i = 0; i < count; i += 32) {
const float* input = reinterpret_cast<const float*>(keys + i);
float* output = reinterpret_cast<float*>(indices + i);
__m256 value0 = _mm256_load_ps(input + 0);
__m256 value1 = _mm256_load_ps(input + 8);
__m256 value2 = _mm256_load_ps(input + 16);
__m256 value3 = _mm256_load_ps(input + 24);
__m256 value4 = _mm256_load_ps(input + 32);
__m256 value5 = _mm256_load_ps(input + 40);
__m256 value6 = _mm256_load_ps(input + 48);
__m256 value7 = _mm256_load_ps(input + 56);
__m256 i0 = _mm256_shuffle_ps(value0, value1, _MM_SHUFFLE(2,0,2,0));
__m256 i1 = _mm256_shuffle_ps(value2, value3, _MM_SHUFFLE(2,0,2,0));
__m256 i2 = _mm256_shuffle_ps(value4, value5, _MM_SHUFFLE(2,0,2,0));
__m256 i3 = _mm256_shuffle_ps(value6, value7, _MM_SHUFFLE(2,0,2,0));
i0 = _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(i0), (0) | ((2) << 2) | ((1) << 4) | ((3) << 6)));
i1 = _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(i1), (0) | ((2) << 2) | ((1) << 4) | ((3) << 6)));
i2 = _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(i2), (0) | ((2) << 2) | ((1) << 4) | ((3) << 6)));
i3 = _mm256_castpd_ps(_mm256_permute4x64_pd(_mm256_castps_pd(i3), (0) | ((2) << 2) | ((1) << 4) | ((3) << 6)));
_mm256_store_ps(output + 0, i0);
_mm256_store_ps(output + 8, i1);
_mm256_store_ps(output + 16, i2);
_mm256_store_ps(output + 24, i3);
}
}
inline void radixSortUint64High32X3(unsigned long long* __restrict dataA, unsigned long long* __restrict dataB, unsigned long long* __restrict dataC,
unsigned long long* __restrict tempA, unsigned long long* __restrict tempB, unsigned long long* __restrict tempC, unsigned count) {
unsigned bucketsA0[257];
unsigned bucketsA1[257];
unsigned bucketsA2[257];
unsigned bucketsA3[257];
unsigned bucketsB0[257];
unsigned bucketsB1[257];
unsigned bucketsB2[257];
unsigned bucketsB3[257];
unsigned bucketsC0[257];
unsigned bucketsC1[257];
unsigned bucketsC2[257];
unsigned bucketsC3[257];
for (unsigned i = 0; i < 257; ++i) {
bucketsA0[i] = 0;
bucketsA1[i] = 0;
bucketsA2[i] = 0;
bucketsA3[i] = 0;
bucketsB0[i] = 0;
bucketsB1[i] = 0;
bucketsB2[i] = 0;
bucketsB3[i] = 0;
bucketsC0[i] = 0;
bucketsC1[i] = 0;
bucketsC2[i] = 0;
bucketsC3[i] = 0;
}
unsigned* histogramA0 = bucketsA0+1;
unsigned* histogramA1 = bucketsA1+1;
unsigned* histogramA2 = bucketsA2+1;
unsigned* histogramA3 = bucketsA3+1;
unsigned* histogramB0 = bucketsB0+1;
unsigned* histogramB1 = bucketsB1+1;
unsigned* histogramB2 = bucketsB2+1;
unsigned* histogramB3 = bucketsB3+1;
unsigned* histogramC0 = bucketsC0+1;
unsigned* histogramC1 = bucketsC1+1;
unsigned* histogramC2 = bucketsC2+1;
unsigned* histogramC3 = bucketsC3+1;
for (unsigned i = 0; i < count; ++i) {
unsigned long long da = dataA[i];
unsigned long long db = dataB[i];
unsigned long long dc = dataC[i];
++histogramA0[(da >> (4 << 3)) & 0xff];
++histogramA1[(da >> (5 << 3)) & 0xff];
++histogramA2[(da >> (6 << 3)) & 0xff];
++histogramA3[(da >> (7 << 3)) & 0xff];
++histogramB0[(db >> (4 << 3)) & 0xff];
++histogramB1[(db >> (5 << 3)) & 0xff];
++histogramB2[(db >> (6 << 3)) & 0xff];
++histogramB3[(db >> (7 << 3)) & 0xff];
++histogramC0[(dc >> (4 << 3)) & 0xff];
++histogramC1[(dc >> (5 << 3)) & 0xff];
++histogramC2[(dc >> (6 << 3)) & 0xff];
++histogramC3[(dc >> (7 << 3)) & 0xff];
}
for (unsigned i = 1; i < 256; ++i) {
bucketsA0[i] += bucketsA0[i-1];
bucketsA1[i] += bucketsA1[i-1];
bucketsA2[i] += bucketsA2[i-1];
bucketsA3[i] += bucketsA3[i-1];
bucketsB0[i] += bucketsB0[i-1];
bucketsB1[i] += bucketsB1[i-1];
bucketsB2[i] += bucketsB2[i-1];
bucketsB3[i] += bucketsB3[i-1];
bucketsC0[i] += bucketsC0[i-1];
bucketsC1[i] += bucketsC1[i-1];
bucketsC2[i] += bucketsC2[i-1];
bucketsC3[i] += bucketsC3[i-1];
}
for (unsigned i = 0; i < count; ++i) {
unsigned long long da = dataA[i];
unsigned long long db = dataB[i];
unsigned long long dc = dataC[i];
unsigned indexA = bucketsA0[(da >> (4 << 3)) & 0xff]++;
unsigned indexB = bucketsB0[(db >> (4 << 3)) & 0xff]++;
unsigned indexC = bucketsC0[(dc >> (4 << 3)) & 0xff]++;
tempA[indexA] = da;
tempB[indexB] = db;
tempC[indexC] = dc;
}
for (unsigned i = 0; i < count; ++i) {
unsigned long long da = tempA[i];
unsigned long long db = tempB[i];
unsigned long long dc = tempC[i];
unsigned indexA = bucketsA1[(da >> (5 << 3)) & 0xff]++;
unsigned indexB = bucketsB1[(db >> (5 << 3)) & 0xff]++;
unsigned indexC = bucketsC1[(dc >> (5 << 3)) & 0xff]++;
dataA[indexA] = da;
dataB[indexB] = db;
dataC[indexC] = dc;
}
for (unsigned i = 0; i < count; ++i) {
unsigned long long da = dataA[i];
unsigned long long db = dataB[i];
unsigned long long dc = dataC[i];
unsigned indexA = bucketsA2[(da >> (6 << 3)) & 0xff]++;
unsigned indexB = bucketsB2[(db >> (6 << 3)) & 0xff]++;
unsigned indexC = bucketsC2[(dc >> (6 << 3)) & 0xff]++;
tempA[indexA] = da;
tempB[indexB] = db;
tempC[indexC] = dc;
}
for (unsigned i = 0; i < count; ++i) {
unsigned long long da = tempA[i];
unsigned long long db = tempB[i];
unsigned long long dc = tempC[i];
unsigned indexA = bucketsA3[(da >> (7 << 3)) & 0xff]++;
unsigned indexB = bucketsB3[(db >> (7 << 3)) & 0xff]++;
unsigned indexC = bucketsC3[(dc >> (7 << 3)) & 0xff]++;
dataA[indexA] = da;
dataB[indexB] = db;
dataC[indexC] = dc;
}
}
inline void packFloatsAndIndicesInUint64(float* __restrict values, unsigned long long* __restrict keys, unsigned count, int offset) {
__m256i offset256 = _mm256_set1_epi32(offset);
__m256i i0 = _mm256_add_epi32(_mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7), offset256);
__m256i i1 = _mm256_add_epi32(_mm256_setr_epi32(8, 9, 10, 11, 12, 13, 14, 15), offset256);
__m256i i2 = _mm256_add_epi32(_mm256_setr_epi32(16, 17, 18, 19, 20, 21, 22, 23), offset256);
__m256i i3 = _mm256_add_epi32(_mm256_setr_epi32(24, 25, 26, 27, 28, 29, 30, 31), offset256);
__m256i increment = _mm256_set1_epi32(32);
__m256 signMask = _mm256_castps_si256(_mm256_set1_epi32(0x80000000));
__m256 fullMask = _mm256_castps_si256(_mm256_set1_epi32(0xffffffff));
unsigned i = 0;
for (; i+31 < count; i += 32) {
const float* input = reinterpret_cast<const float*>(values + i);
float* output = reinterpret_cast<float*>(keys + i);
__m256 value0 = _mm256_load_ps(input + 0*8);
__m256 value1 = _mm256_load_ps(input + 1*8);
__m256 value2 = _mm256_load_ps(input + 2*8);
__m256 value3 = _mm256_load_ps(input + 3*8);
__m256 mask0 = _mm256_blendv_ps(signMask, fullMask, value0);
__m256 mask1 = _mm256_blendv_ps(signMask, fullMask, value1);
__m256 mask2 = _mm256_blendv_ps(signMask, fullMask, value2);
__m256 mask3 = _mm256_blendv_ps(signMask, fullMask, value3);
__m256 encodedValue0 = _mm256_xor_ps(mask0, value0);
__m256 encodedValue1 = _mm256_xor_ps(mask1, value1);
__m256 encodedValue2 = _mm256_xor_ps(mask2, value2);
__m256 encodedValue3 = _mm256_xor_ps(mask3, value3);
__m256 key00 = _mm256_unpacklo_ps(i0, encodedValue0);
__m256 key01 = _mm256_unpackhi_ps(i0, encodedValue0);
__m256 key10 = _mm256_unpacklo_ps(i1, encodedValue1);
__m256 key11 = _mm256_unpackhi_ps(i1, encodedValue1);
__m256 key20 = _mm256_unpacklo_ps(i2, encodedValue2);
__m256 key21 = _mm256_unpackhi_ps(i2, encodedValue2);
__m256 key30 = _mm256_unpacklo_ps(i3, encodedValue3);
__m256 key31 = _mm256_unpackhi_ps(i3, encodedValue3);
_mm256_store_ps(output + 0*8, key00);
_mm256_store_ps(output + 1*8, key01);
_mm256_store_ps(output + 2*8, key10);
_mm256_store_ps(output + 3*8, key11);
_mm256_store_ps(output + 4*8, key20);
_mm256_store_ps(output + 5*8, key21);
_mm256_store_ps(output + 6*8, key30);
_mm256_store_ps(output + 7*8, key31);
i0 = _mm256_add_epi32(i0, increment);
i1 = _mm256_add_epi32(i1, increment);
i2 = _mm256_add_epi32(i2, increment);
i3 = _mm256_add_epi32(i3, increment);
}
for (; i < count; ++i) {
int input = *reinterpret_cast<const int*>(values + i);
input ^= input < 0 ? 0xffffffff : 0x80000000;
keys[i] = ((unsigned long long)input << 32) | (i + offset);
}
}
inline void inPlaceUnpackIndicesFromLowUin64ToUint32(unsigned long long* keys, unsigned count) {
for (unsigned i = 0; i < count; i += 32) {
const float* input = reinterpret_cast<const float*>(keys + i);
float* output = reinterpret_cast<float*>(keys) + i;
__m256 value0 = _mm256_load_ps(input + 0);
__m256 value1 = _mm256_load_ps(input + 8);
__m256 value2 = _mm256_load_ps(input + 16);
__m256 value3 = _mm256_load_ps(input + 24);
__m256 value4 = _mm256_load_ps(input + 32);
__m256 value5 = _mm256_load_ps(input + 40);
__m256 value6 = _mm256_load_ps(input + 48);
__m256 value7 = _mm256_load_ps(input + 56);
__m256 i0 = _mm256_shuffle_ps(value0, value1, _MM_SHUFFLE(2,0,2,0));
__m256 i1 = _mm256_shuffle_ps(value2, value3, _MM_SHUFFLE(2,0,2,0));
__m256 i2 = _mm256_shuffle_ps(value4, value5, _MM_SHUFFLE(2,0,2,0));
__m256 i3 = _mm256_shuffle_ps(value6, value7, _MM_SHUFFLE(2,0,2,0));
i0 = _mm256_permute4x64_pd(i0, (0) | ((2) << 2) | ((1) << 4) | ((3) << 6));
i1 = _mm256_permute4x64_pd(i1, (0) | ((2) << 2) | ((1) << 4) | ((3) << 6));
i2 = _mm256_permute4x64_pd(i2, (0) | ((2) << 2) | ((1) << 4) | ((3) << 6));
i3 = _mm256_permute4x64_pd(i3, (0) | ((2) << 2) | ((1) << 4) | ((3) << 6));
_mm256_store_ps(output + 0, i0);
_mm256_store_ps(output + 8, i1);
_mm256_store_ps(output + 16, i2);
_mm256_store_ps(output + 24, i3);
}
}
void sortedIndicesFromFloatsX3(float* __restrict valuesA, float* __restrict valuesB, float* __restrict valuesC, unsigned* __restrict indicesA, unsigned* __restrict indicesB, unsigned* __restrict indicesC, unsigned count, int offset) {
unsigned long long* keysA = reinterpret_cast<unsigned long long*>(indicesA);
unsigned long long* keysB = reinterpret_cast<unsigned long long*>(indicesB);
unsigned long long* keysC = reinterpret_cast<unsigned long long*>(indicesC);
packFloatsAndIndicesInUint64(valuesA, keysA, count, offset);
packFloatsAndIndicesInUint64(valuesB, keysB, count, offset);
packFloatsAndIndicesInUint64(valuesC, keysC, count, offset);
radixSortUint64High32X3(keysA, keysB, keysC, keysA + count, keysB + count, keysC + count, count);
inPlaceUnpackIndicesFromLowUin64ToUint32(keysA, count);
inPlaceUnpackIndicesFromLowUin64ToUint32(keysB, count);
inPlaceUnpackIndicesFromLowUin64ToUint32(keysC, count);
}
+24
View File
@@ -0,0 +1,24 @@
//
// IndexSort.h
// RayAccelerator
//
// Created by Rasmus Barringer on 2014-09-03.
// Copyright (c) 2014 Rasmus Barringer. All rights reserved.
//
#ifndef RayAccelerator_IndexSort_h
#define RayAccelerator_IndexSort_h
// Note: indices needs to be 2x in size for temporary storage.
// Everything needs to be aligned and padded:
// values - pad with 128 bytes
// indices - pad with 256 bytes
void sortedIndicesFromFloats(float* __restrict values, unsigned* __restrict indices, unsigned count);
// Note: indices needs to be 4x in size for temporary storage.
// Everything needs to be aligned and padded:
// values - pad with 128 bytes
// indices - pad with 256 bytes
void sortedIndicesFromFloatsX3(float* __restrict valuesA, float* __restrict valuesB, float* __restrict valuesC, unsigned* __restrict indicesA, unsigned* __restrict indicesB, unsigned* __restrict indicesC, unsigned count, int offset);
#endif
+64 -63
View File
@@ -24,7 +24,7 @@
#include "../xeonphi/bvh4mb/bvh4mb.h"
#include "../xeonphi/bvh4hair/bvh4hair.h"
#endif
namespace embree
{
/* error raising rtcIntersect and rtcOccluded functions */
@@ -34,26 +34,26 @@ namespace embree
void invalid_rtcIntersect8() { throw_RTCError(RTC_INVALID_OPERATION,"rtcIntersect8 and rtcOccluded8 not enabled"); }
void invalid_rtcIntersect16() { throw_RTCError(RTC_INVALID_OPERATION,"rtcIntersect16 and rtcOccluded16 not enabled"); }
/* number of created scene */
AtomicCounter Scene::numScenes = 0;
Scene::Scene (Device* device, RTCSceneFlags sflags, RTCAlgorithmFlags aflags)
: device(device),
: device(device),
Accel(AccelData::TY_UNKNOWN),
flags(sflags), aflags(aflags), numMappedBuffers(0), is_build(false), modified(true),
needTriangleIndices(false), needTriangleVertices(false),
flags(sflags), aflags(aflags), numMappedBuffers(0), is_build(false), modified(true),
needTriangleIndices(false), needTriangleVertices(false),
needBezierIndices(false), needBezierVertices(false),
needSubdivIndices(false), needSubdivVertices(false),
numTriangles(0), numTriangles2(0),
numBezierCurves(0), numBezierCurves2(0),
numSubdivPatches(0), numSubdivPatches2(0),
numTriangles(0), numTriangles2(0),
numBezierCurves(0), numBezierCurves2(0),
numSubdivPatches(0), numSubdivPatches2(0),
numUserGeometries1(0), numSubdivEnableDisableEvents(0),
numIntersectionFilters4(0), numIntersectionFilters8(0), numIntersectionFilters16(0),
commitCounter(0), commitCounterSubdiv(0),
commitCounter(0), commitCounterSubdiv(0),
progress_monitor_function(nullptr), progress_monitor_ptr(nullptr), progress_monitor_counter(0)
{
#if defined(TASKING_LOCKSTEP)
#if defined(TASKING_LOCKSTEP)
lockstep_scheduler.taskBarrier.init(MAX_MIC_THREADS);
#elif defined(TASKING_TBB_INTERNAL)
scheduler = nullptr;
@@ -88,16 +88,16 @@ namespace embree
{
std::cout << "scene flags: static " << isStatic() << " compact = " << isCompact() << " high quality = " << isHighQuality() << " robust = " << isRobust() << std::endl;
}
if (device->tri_accel == "default" || device->tri_accel == "bvh4i")
if (device->tri_accel == "default" || device->tri_accel == "bvh4i")
{
if (device->tri_builder == "default")
if (device->tri_builder == "default")
{
if (isStatic())
{
if (device->verbosity(1)) std::cout << "STATIC BUILDER MODE" << std::endl;
if ( isCompact() )
accels.add(BVH4i::BVH4iTriangle1MemoryConservativeBinnedSAH(this,isRobust()));
accels.add(BVH4i::BVH4iTriangle1MemoryConservativeBinnedSAH(this,isRobust()));
else if ( isHighQuality() )
accels.add(BVH4i::BVH4iTriangle1ObjectSplitBinnedSAH(this,isRobust()));
else
@@ -130,12 +130,12 @@ namespace embree
else if (device->tri_builder == "morton64") {
accels.add(BVH4i::BVH4iTriangle1ObjectSplitMorton64Bit(this,isRobust()));
}
else THROW_RUNTIME_ERROR("unknown builder "+device->tri_builder+" for BVH4i<Triangle1>");
}
}
else THROW_RUNTIME_ERROR("unknown accel "+device->tri_accel);
#else
createTriangleAccel();
accels.add(BVH4::BVH4Triangle4vMB(this));
@@ -153,32 +153,32 @@ namespace embree
void Scene::createTriangleAccel()
{
if (device->tri_accel == "default")
if (device->tri_accel == "default")
{
if (isStatic()) {
int mode = 2*(int)isCompact() + 1*(int)isRobust();
int mode = 2*(int)isCompact() + 1*(int)isRobust();
switch (mode) {
case /*0b00*/ 0:
case /*0b00*/ 0:
#if defined (__TARGET_AVX__)
if (hasISA(AVX))
{
// FIXME: there appears to be a bug in the spatial split builder, performance and SAH is lower than for standard builder
//if (isHighQuality()) accels.add(BVH8::BVH8Triangle4SpatialSplit(this));
/*else*/ accels.add(BVH8::BVH8Triangle4ObjectSplit(this));
//if (isHighQuality()) accels.add(BVH8::BVH8Triangle4SpatialSplit(this));
/*else*/ accels.add(BVH8::BVH8Triangle4ObjectSplit(this));
}
else
else
#endif
{
// FIXME: there appears to be a bug in the spatial split builder, performance and SAH is lower than for standard builder
//if (isHighQuality()) accels.add(BVH4::BVH4Triangle4SpatialSplit(this));
/*else*/ accels.add(BVH4::BVH4Triangle4ObjectSplit(this));
//if (isHighQuality()) accels.add(BVH4::BVH4Triangle4SpatialSplit(this));
/*else*/ accels.add(BVH4::BVH4Triangle4ObjectSplit(this));
}
break;
case /*0b01*/ 1:
case /*0b01*/ 1:
//#if defined (__TARGET_AVX2__) && !defined(__WIN32__) // FIXME: have to disable under Windows as watertightness tests fail
// if (hasISA(AVX2))
// accels.add(BVH8::BVH8Triangle8vObjectSplit(this));
// accels.add(BVH8::BVH8Triangle8vObjectSplit(this));
// else
//#endif
accels.add(BVH4::BVH4Triangle4vObjectSplit(this));
@@ -187,8 +187,8 @@ namespace embree
case /*0b10*/ 2: accels.add(BVH4::BVH4Triangle4iObjectSplit(this)); break;
case /*0b11*/ 3: accels.add(BVH4::BVH4Triangle4iObjectSplit(this)); break;
}
}
else
}
else
{
int mode = 2*(int)isCompact() + 1*(int)isRobust();
switch (mode) {
@@ -209,6 +209,7 @@ namespace embree
else if (device->tri_accel == "bvh4.bvh4.triangle8") accels.add(BVH4::BVH4BVH4Triangle8ObjectSplit(this));
else if (device->tri_accel == "bvh4.triangle8") accels.add(BVH4::BVH4Triangle8(this));
else if (device->tri_accel == "bvh8.triangle4") accels.add(BVH8::BVH8Triangle4(this));
else if (device->tri_accel == "bvh8.triangle4.bonsai") accels.add(BVH8::BVH8Triangle4Bonsai(this));
else if (device->tri_accel == "bvh8.triangle8") accels.add(BVH8::BVH8Triangle8(this));
else if (device->tri_accel == "bvh8.trianglepairs8") accels.add(BVH8::BVH8TrianglePairs8(this));
//else if (device->tri_accel == "bvh8.triangle8v") accels.add(BVH8::BVH8Triangle8v(this));
@@ -219,18 +220,18 @@ namespace embree
void Scene::createHairAccel()
{
if (device->hair_accel == "default")
if (device->hair_accel == "default")
{
if (isStatic()) {
int mode = 2*(int)isCompact() + 1*(int)isRobust();
int mode = 2*(int)isCompact() + 1*(int)isRobust();
switch (mode) {
case /*0b00*/ 0: accels.add(BVH4::BVH4OBBBezier1v(this,isHighQuality())); break;
case /*0b01*/ 1: accels.add(BVH4::BVH4OBBBezier1v(this,isHighQuality())); break;
case /*0b10*/ 2: accels.add(BVH4::BVH4OBBBezier1i(this,isHighQuality())); break;
case /*0b11*/ 3: accels.add(BVH4::BVH4OBBBezier1i(this,isHighQuality())); break;
}
}
else
}
else
{
int mode = 2*(int)isCompact() + 1*(int)isRobust();
switch (mode) {
@@ -239,7 +240,7 @@ namespace embree
case /*0b10*/ 2: accels.add(BVH4::BVH4Bezier1i(this)); break;
case /*0b11*/ 3: accels.add(BVH4::BVH4Bezier1i(this)); break;
}
}
}
}
else if (device->hair_accel == "bvh4.bezier1v" ) accels.add(BVH4::BVH4Bezier1v(this));
else if (device->hair_accel == "bvh4.bezier1i" ) accels.add(BVH4::BVH4Bezier1i(this));
@@ -250,7 +251,7 @@ namespace embree
void Scene::createSubdivAccel()
{
if (device->subdiv_accel == "default")
if (device->subdiv_accel == "default")
{
if (isIncoherent(flags) && isStatic())
accels.add(BVH4::BVH4SubdivGridEager(this));
@@ -265,7 +266,7 @@ namespace embree
#endif
Scene::~Scene ()
Scene::~Scene ()
{
for (size_t i=0; i<geometries.size(); i++)
delete geometries[i];
@@ -281,18 +282,18 @@ namespace embree
void Scene::clear() {
}
unsigned Scene::newUserGeometry (size_t items)
unsigned Scene::newUserGeometry (size_t items)
{
Geometry* geom = new UserGeometry(this,items);
return geom->id;
}
unsigned Scene::newInstance (Scene* scene) {
Geometry* geom = new Instance(this,scene);
return geom->id;
}
unsigned Scene::newTriangleMesh (RTCGeometryFlags gflags, size_t numTriangles, size_t numVertices, size_t numTimeSteps)
unsigned Scene::newTriangleMesh (RTCGeometryFlags gflags, size_t numTriangles, size_t numVertices, size_t numTimeSteps)
{
if (isStatic() && (gflags != RTC_GEOMETRY_STATIC)) {
throw_RTCError(RTC_INVALID_OPERATION,"static scenes can only contain static geometries");
@@ -303,12 +304,12 @@ namespace embree
throw_RTCError(RTC_INVALID_OPERATION,"only 1 or 2 time steps supported");
return -1;
}
Geometry* geom = new TriangleMesh(this,gflags,numTriangles,numVertices,numTimeSteps);
return geom->id;
}
unsigned Scene::newSubdivisionMesh (RTCGeometryFlags gflags, size_t numFaces, size_t numEdges, size_t numVertices, size_t numEdgeCreases, size_t numVertexCreases, size_t numHoles, size_t numTimeSteps)
unsigned Scene::newSubdivisionMesh (RTCGeometryFlags gflags, size_t numFaces, size_t numEdges, size_t numVertices, size_t numEdgeCreases, size_t numVertexCreases, size_t numHoles, size_t numTimeSteps)
{
if (isStatic() && (gflags != RTC_GEOMETRY_STATIC)) {
throw_RTCError(RTC_INVALID_OPERATION,"static scenes can only contain static geometries");
@@ -324,14 +325,14 @@ namespace embree
#if defined(__TARGET_AVX__)
if (hasISA(AVX))
geom = new SubdivMeshAVX(this,gflags,numFaces,numEdges,numVertices,numEdgeCreases,numVertexCreases,numHoles,numTimeSteps);
else
else
#endif
geom = new SubdivMesh(this,gflags,numFaces,numEdges,numVertices,numEdgeCreases,numVertexCreases,numHoles,numTimeSteps);
return geom->id;
}
unsigned Scene::newBezierCurves (RTCGeometryFlags gflags, size_t numCurves, size_t numVertices, size_t numTimeSteps)
unsigned Scene::newBezierCurves (RTCGeometryFlags gflags, size_t numCurves, size_t numVertices, size_t numTimeSteps)
{
if (isStatic() && (gflags != RTC_GEOMETRY_STATIC)) {
throw_RTCError(RTC_INVALID_OPERATION,"static scenes can only contain static geometries");
@@ -342,17 +343,17 @@ namespace embree
throw_RTCError(RTC_INVALID_OPERATION,"only 1 or 2 time steps supported");
return -1;
}
Geometry* geom = new BezierCurves(this,gflags,numCurves,numVertices,numTimeSteps);
return geom->id;
}
unsigned Scene::add(Geometry* geometry)
unsigned Scene::add(Geometry* geometry)
{
Lock<AtomicMutex> lock(geometriesMutex);
if (usedIDs.size()) {
int id = usedIDs.back();
int id = usedIDs.back();
usedIDs.pop_back();
geometries[id] = geometry;
return id;
@@ -361,8 +362,8 @@ namespace embree
return geometries.size()-1;
}
}
void Scene::remove(Geometry* geometry)
void Scene::remove(Geometry* geometry)
{
Lock<AtomicMutex> lock(geometriesMutex);
usedIDs.push_back(geometry->id);
@@ -399,12 +400,12 @@ namespace embree
/* select fast code path if no intersection filter is present */
accels.select(numIntersectionFilters4,numIntersectionFilters8,numIntersectionFilters16);
/* build all hierarchies of this scene */
accels.build(0,0);
/* make static geometry immutable */
if (isStatic())
if (isStatic())
{
accels.immutable();
for (size_t i=0; i<geometries.size(); i++)
@@ -428,19 +429,19 @@ namespace embree
std::cout << "selected scene intersector" << std::endl;
intersectors.print(2);
}
setModified(false);
}
#if defined(TASKING_LOCKSTEP)
void Scene::task_build_parallel(size_t threadIndex, size_t threadCount, size_t taskIndex, size_t taskCount, TaskScheduler::Event* event)
void Scene::task_build_parallel(size_t threadIndex, size_t threadCount, size_t taskIndex, size_t taskCount, TaskScheduler::Event* event)
{
LockStepTaskScheduler::Init init(threadIndex,threadCount,&lockstep_scheduler);
if (threadIndex == 0) accels.build(threadIndex,threadCount);
}
void Scene::build (size_t threadIndex, size_t threadCount)
void Scene::build (size_t threadIndex, size_t threadCount)
{
LockStepTaskScheduler::Init init(threadIndex,threadCount,&lockstep_scheduler);
if (threadIndex != 0) return;
@@ -477,7 +478,7 @@ namespace embree
}
/* make static geometry immutable */
if (isStatic())
if (isStatic())
{
accels.immutable();
for (size_t i=0; i<geometries.size(); i++)
@@ -508,13 +509,13 @@ namespace embree
#if defined(TASKING_TBB_INTERNAL)
void Scene::build (size_t threadIndex, size_t threadCount)
void Scene::build (size_t threadIndex, size_t threadCount)
{
AutoUnlock<MutexSys> buildLock(buildMutex);
/* allocates own taskscheduler for each build */
Ref<TaskSchedulerTBB> scheduler = nullptr;
{
{
Lock<MutexSys> lock(schedulerMutex);
scheduler = this->scheduler;
if (scheduler == null) {
@@ -553,7 +554,7 @@ namespace embree
#if defined(TASKING_TBB)
void Scene::build (size_t threadIndex, size_t threadCount)
void Scene::build (size_t threadIndex, size_t threadCount)
{
/* let threads wait for build to finish in rtcCommitThread mode */
if (threadCount != 0) {
@@ -603,10 +604,10 @@ namespace embree
unsigned int mxcsr = _mm_getcsr();
_mm_setcsr(mxcsr | /* FTZ */ (1<<15) | /* DAZ */ (1<<6));
#endif
try {
#if TBB_INTERFACE_VERSION_MAJOR < 8
#if TBB_INTERFACE_VERSION_MAJOR < 8
tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits);
#else
tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits | tbb::task_group_context::fp_settings );
@@ -622,14 +623,14 @@ namespace embree
if (threadCount) group_barrier.wait(threadCount);
group->wait();
#if USE_TASK_ARENA
});
});
#endif
/* reset MXCSR register again */
#if !defined(__MIC__)
_mm_setcsr(mxcsr);
#endif
}
}
catch (...) {
/* reset MXCSR register again */
@@ -656,7 +657,7 @@ namespace embree
}
}
void Scene::setProgressMonitorFunction(RTCProgressMonitorFunc func, void* ptr)
void Scene::setProgressMonitorFunction(RTCProgressMonitorFunc func, void* ptr)
{
static MutexSys mutex;
mutex.lock();
+3 -3
View File
@@ -35,17 +35,17 @@ namespace embree
typedef std::size_t size_type; // FIXME: also use std::size_t type under windows if available
typedef std::ptrdiff_t difference_type;
__forceinline aligned_monitored_allocator(MemoryMonitorInterface* device)
__forceinline aligned_monitored_allocator(MemoryMonitorInterface* device)
: device(device) {}
__forceinline pointer allocate( size_type n )
__forceinline pointer allocate( size_type n )
{
assert(device);
device->memoryMonitor(n*sizeof(T),false);
return (pointer) alignedMalloc(n*sizeof(value_type),alignment);
}
__forceinline void deallocate( pointer p, size_type n )
__forceinline void deallocate( pointer p, size_type n )
{
assert(device);
alignedFree(p);
+15 -7
View File
@@ -53,12 +53,13 @@ IF (TASKING_TBB)
ENDIF()
SET(EMBREE_LIBRARY_FILES
embree.rc
../../common/tasking/taskscheduler_tbb.cpp
../../common/tasking/tasksys.cpp
../algorithms/parallel_for.cpp
../algorithms/parallel_reduce.cpp
../algorithms/parallel_prefix_sum.cpp
@@ -93,7 +94,7 @@ SET(EMBREE_LIBRARY_FILES
geometry/instance_intersector1.cpp
geometry/instance_intersector4.cpp
geometry/subdivpatch1_intersector1.cpp
geometry/grid_soa.cpp
geometry/grid_soa.cpp
builders/primrefgen.cpp
bvh4/bvh4.cpp
@@ -137,12 +138,12 @@ IF (RTCORE_RAY_PACKETS)
ENDIF()
SET(EMBREE_LIBRARY_FILES_AVX
../common/scene_subdiv_mesh_avx.cpp
geometry/primitive.cpp
geometry/instance_intersector1.cpp
geometry/subdivpatch1_intersector1.cpp
geometry/grid_soa.cpp
builders/primrefgen.avx.cpp
@@ -155,10 +156,11 @@ SET(EMBREE_LIBRARY_FILES_AVX
bvh4/bvh4_builder_twolevel.avx.cpp
bvh4/bvh4_builder_subdiv.avx.cpp
bvh4/bvh4_intersector1.cpp
bvh8/bvh8.cpp
bvh8/bvh8_statistics.cpp
bvh8/bvh8_builder_sah.avx.cpp
bvh8/bvh8_intersector1.cpp
)
@@ -182,13 +184,19 @@ ENDIF()
SET(EMBREE_LIBRARY_FILES_AVX2
geometry/instance_intersector1.cpp
geometry/subdivpatch1_intersector1.cpp
geometry/grid_soa.cpp
bvh4/bvh4_intersector1.cpp
bvh8/bvh8_intersector1.cpp)
bvh8/bvh8_intersector1.cpp
builders/primrefgen.avx.cpp
../algorithms/IndexSort.cpp
bvh8/bvh8_builder_bonsai.cpp
)
IF (RTCORE_RAY_PACKETS)
SET(EMBREE_LIBRARY_FILES_AVX2 ${EMBREE_LIBRARY_FILES_AVX2}
+908
View File
@@ -0,0 +1,908 @@
// ======================================================================== //
// Copyright 2009-2015 Intel Corporation //
// //
// 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 //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// 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 //
// limitations under the License. //
// ======================================================================== //
#pragma once
#include "heuristic_bonsai.h"
#include "../../common/scene.h"
#include <chrono>
namespace embree
{
namespace isa
{
template<typename Set, typename Split>
struct GeneralBuildRecord
{
public:
__forceinline GeneralBuildRecord () {}
__forceinline GeneralBuildRecord (size_t depth)
: depth(depth), pinfo(empty) {}
__forceinline GeneralBuildRecord (const PrimInfo& pinfo, size_t depth, size_t* parent)
: pinfo(pinfo), depth(depth), parent(parent) {}
__forceinline GeneralBuildRecord (const PrimInfo& pinfo, size_t depth, size_t* parent, const Set &prims)
: pinfo(pinfo), depth(depth), parent(parent), prims(prims) {}
__forceinline GeneralBuildRecord (const PrimInfo& pinfo, size_t depth, size_t* parent, const Set &prims, const Set &indexRange)
: pinfo(pinfo), depth(depth), parent(parent), prims(prims), indexRange(indexRange) {}
__forceinline friend bool operator< (const GeneralBuildRecord& a, const GeneralBuildRecord& b) { return a.pinfo.size() < b.pinfo.size(); }
__forceinline friend bool operator> (const GeneralBuildRecord& a, const GeneralBuildRecord& b) { return a.pinfo.size() > b.pinfo.size(); }
__forceinline BBox3fa bounds() const { return pinfo.geomBounds; }
__forceinline size_t size() const { return this->pinfo.size(); }
public:
size_t* parent; //!< Pointer to the parent node's reference to us
size_t depth; //!< Depth of the root of this subtree.
Set prims; //!< The list of primitives.
PrimInfo pinfo; //!< Bounding info of primitives.
Split split;
Set indexRange; //!< In memory available space for split partitioning
};
template<typename BuildRecord,
typename Heuristic,
typename ReductionTy,
typename Allocator,
typename CreateAllocFunc,
typename CreateNodeFunc,
typename UpdateNodeFunc,
typename CreateLeafFunc,
typename ProgressMonitor>
class GeneralBVHBuilder
{
static const size_t MAX_BRANCHING_FACTOR = 16; //!< maximal supported BVH branching factor
static const size_t MIN_LARGE_LEAF_LEVELS = 8; //!< create balanced tree of we are that many levels before the maximal tree depth
static const size_t SINGLE_THREADED_THRESHOLD = 4096; //!< threshold to switch to single threaded build
size_t MAX_MINI_TREE_SIZE = 8192; //!< maximum size of a mini tree
float PRUNING_THRESHOLD = 0.95f; //!< a pruning treshold in the range ]0,1[, anything else results in no pruning
const bool splitTriangles = false;
const int numberOfTriangles;
volatile int miniTreeCount;
volatile int splitIndex;
int underFilledNodes;
mvector<unsigned> ttIndicesX;
mvector<unsigned> ttIndicesY;
mvector<unsigned> ttIndicesZ;
mvector<float> ttMidpointsX;
mvector<float> ttMidpointsY;
mvector<float> ttMidpointsZ;
float* __restrict ttMidPoints[3];
unsigned* __restrict ttIndices[3];
mvector<PrimRef> ttBounds;
mvector<unsigned> ttTemporaryIndices;
mvector<unsigned char> ttLeftPartition;
mvector<float> ttAccumulatedArea;
mvector<unsigned> ttAccumulatedCounts;
mvector<FastSweepData*> fsd;
public:
mvector<BuildRecord> miniTreeRecords;
mvector<BuildRecord> miniTreeRecordsPruned;
mvector<size_t*> miniTreeRoots;
GeneralBVHBuilder (Heuristic& heuristic,
const ReductionTy& identity,
CreateAllocFunc& createAlloc,
CreateNodeFunc& createNode,
UpdateNodeFunc& updateNode,
CreateLeafFunc& createLeaf,
ProgressMonitor& progressMonitor,
const PrimInfo& pinfo,
const size_t branchingFactor, const size_t maxDepth,
const size_t logBlockSize, const size_t minLeafSize, const size_t maxLeafSize,
const float travCost, const float intCost, const int numberOfTriangles, const bool splitTriangles, Scene* scene)
: heuristic(heuristic),
identity(identity),
createAlloc(createAlloc), createNode(createNode), updateNode(updateNode), createLeaf(createLeaf),
progressMonitor(progressMonitor),
pinfo(pinfo),
branchingFactor(branchingFactor), maxDepth(maxDepth),
logBlockSize(logBlockSize), minLeafSize(minLeafSize), maxLeafSize(maxLeafSize),
travCost(travCost), intCost(intCost), numberOfTriangles(numberOfTriangles),splitTriangles(splitTriangles),
ttTemporaryIndices(scene->device), ttLeftPartition(scene->device), ttAccumulatedArea(scene->device),
fsd(scene->device), miniTreeRecords(scene->device), miniTreeRecordsPruned(scene->device), miniTreeRoots(scene->device),
ttBounds(scene->device), ttIndicesX(scene->device), ttIndicesY(scene->device), ttIndicesZ(scene->device),
ttMidpointsX(scene->device), ttMidpointsY(scene->device), ttMidpointsZ(scene->device), ttAccumulatedCounts(scene->device)
{
if (branchingFactor > MAX_BRANCHING_FACTOR)
THROW_RUNTIME_ERROR("bvh_builder: branching factor too large");
}
/*! bonsai builder */
__forceinline void partition(BuildRecord& brecord, BuildRecord& lrecord, BuildRecord& rrecord) {
heuristic.split(brecord.split,brecord.pinfo,brecord.prims,lrecord.pinfo,lrecord.prims,rrecord.pinfo, rrecord.prims);
}
__forceinline int getLargestDim(const BBox3fa& bounds) {
Vec3fa dist = bounds.upper - bounds.lower;
int dim = -1;
if (dist[0] > 0 || dist[1] > 0 || dist[2] > 0) {
dim = dist[0] > dist[1] ? 0 : 1;
dim = dist[dim] > dist[2] ? dim : 2;
}
return dim;
}
__forceinline float getLargestDist(const BBox3fa& bounds) {
Vec3fa dist = bounds.upper - bounds.lower;
float largest = dist[0] > dist[1] ? dist[0] : dist[1];
largest = largest > dist[2] ? largest : dist[2];
return largest;
}
void miniTreeSelectRescursive(BuildRecord current) {
if (getLargestDist(current.pinfo.geomBounds) == 0)
return;
if (current.prims.size() <= MAX_MINI_TREE_SIZE) {
int miniTreeIndex = atomic_add(&miniTreeCount, 1);
miniTreeRecords[miniTreeIndex] = current;
return;
}
BuildRecord left, right;
current.split.dim = getLargestDim(current.pinfo.centBounds);
current.split.pos = current.pinfo.centBounds.center()[current.split.dim];
partition(current, left, right);
if (current.size() > SINGLE_THREADED_THRESHOLD*4)
{
SPAWN_BEGIN;
SPAWN(([&] { miniTreeSelectRescursive(left); }));
SPAWN(([&] { miniTreeSelectRescursive(right); }));
SPAWN_END;
}
else {
miniTreeSelectRescursive(left);
miniTreeSelectRescursive(right);
}
}
__forceinline bool sweep(FastSweepData& data, BuildRecord& current, BuildRecord& left, BuildRecord& right, unsigned offset) {
return heuristic.fastSweep(data, current.pinfo, current.split, current.prims, left.pinfo, left.prims, left.split, right.pinfo, right.prims, right.split, maxLeafSize, offset);
}
void buildMiniTreesRecursive(FastSweepData& data, BuildRecord& current, unsigned offset, Allocator alloc, size_t& miniTreeDepth) {
if (alloc == nullptr)
Allocator alloc = createAlloc();
/*! initialize child list */
BuildRecord children[MAX_BRANCHING_FACTOR];
children[0] = current;
size_t numChildren = 1;
/*! split until node is full or SAH tells us to stop */
do {
/*! find best child to split */
float largestSAH = -1;
ssize_t largestChild = -1;
for (size_t i=0; i<numChildren; i++)
{
if (children[i].pinfo.size() <= minLeafSize || children[i].split.isLeaf()) continue;
float currentSAH = children[i].pinfo.leafSAH(logBlockSize);
if (currentSAH > largestSAH) { largestChild = i; largestSAH = currentSAH; }
}
if (largestChild == -1) break;
/* perform best found split */
BuildRecord& brecord = children[largestChild];
BuildRecord lrecord(current.depth+1);
BuildRecord rrecord(current.depth+1);
if (!sweep(data, brecord, lrecord, rrecord, offset)) {
children[largestChild] = lrecord;
children[numChildren] = rrecord;
numChildren++;
}
} while (numChildren < branchingFactor);
/*! create an inner node */
if (numChildren == 1) {
heuristic.gatherReferences(data, current.prims);
createLeaf(current, data.gatheredRefs, alloc);
return;
}
else
auto node = createNode(current,children,numChildren,alloc);
if (numChildren < 8) {
for (ssize_t i=numChildren-1; i>=0; i--) {
heuristic.gatherReferences(data, children[i].prims);
createLeaf(children[i], data.gatheredRefs, alloc);
}
return;
}
/* spawn tasks */
for (ssize_t i=numChildren-1; i>=0; i--) {
if (children[i].depth > miniTreeDepth)
miniTreeDepth = children[i].depth;
buildMiniTreesRecursive(data, children[i], offset, alloc, miniTreeDepth);
}
}
void setupIndices(unsigned** indices, const size_t first, const size_t count) {
for (int i = 0; i < count; i++)
indices[0][i] = indices[1][i] = indices[2][i] = i;// + first;
}
void buildMiniTrees(mvector<size_t*>& miniTreeRoots) {
if (miniTreeCount == 1) {
FastSweepData data((int)(MAX_MINI_TREE_SIZE), maxLeafSize);
size_t depth = 0;
Allocator alloc = createAlloc();
BuildRecord& br = miniTreeRecords[0];
br.prims = range<size_t>(0, br.prims.size());
heuristic.sortIndices(data, br.prims.size(), 0);
buildMiniTreesRecursive(data, br, 0, alloc, depth);
br.depth = depth;
}
else {
#if 0
FastSweepData data((int)(MAX_MINI_TREE_SIZE), maxLeafSize);
Allocator alloc = createAlloc();
for (int i = 0; i < miniTreeCount; ++i) {
BuildRecord& br = miniTreeRecords[i];
data.setOffset(br.prims.begin());
size_t depth = 0;
unsigned offset = br.prims.begin();
br.parent = (size_t*)&(miniTreeRoots.data()[i]);
br.depth = 0;
br.prims = range<size_t>(0, br.prims.size());
br.pinfo.begin = 0;
br.pinfo.end = br.prims.size();
heuristic.sortIndices(data, br.prims.size(), offset);
buildMiniTreesRecursive(data, br, offset, alloc, depth);
br.depth = depth;
}
#else
int threadCount = TaskSchedulerTBB::threadCount();
fsd.resize(threadCount);
FastSweepData** __restrict fastSweepDataPtr = fsd.data();
for (int i = 0; i < threadCount; i++) {
fastSweepDataPtr[i] = new FastSweepData(MAX_MINI_TREE_SIZE, maxLeafSize);
}
unsigned granularity = miniTreeCount/512;// / 128;
if (granularity < 1) {
granularity = miniTreeCount/128;
}
if (granularity < 1) {
granularity = 1;
}
size_t** __restrict miniTreeRootsPtr = miniTreeRoots.data();
//std::sort(miniTreeRecords.data(), miniTreeRecords.data() + miniTreeCount, [](BuildRecord& a, BuildRecord& b) { return a.prims.size() > b.prims.size(); });
SPAWN_BEGIN;
int treeID = 0;
for (; treeID < miniTreeCount - granularity + 1; treeID += granularity) {
SPAWN(([this, treeID, miniTreeRootsPtr, fastSweepDataPtr, granularity] {
int threadIndex = TaskSchedulerTBB::threadIndex();
FastSweepData& data = *(fastSweepDataPtr[threadIndex]);
Allocator alloc = createAlloc();
for (int i = treeID; i < treeID + granularity; ++i) {
BuildRecord& br = miniTreeRecords[i];
size_t depth = 0;
int offset = br.prims.begin();
br.parent = (size_t*)&(miniTreeRootsPtr[i]);
br.depth = 0;
br.prims = range<size_t>(0, br.prims.size());
br.pinfo.begin = 0;
br.pinfo.end = br.prims.size();
heuristic.sortIndices(data, br.prims.size(), offset);
buildMiniTreesRecursive(data, br, offset, alloc, depth);
br.depth = depth;
}
}));
}
if (treeID < miniTreeCount) {
SPAWN(([this, treeID, miniTreeRootsPtr, fastSweepDataPtr] {
int threadIndex = TaskSchedulerTBB::threadIndex();
FastSweepData& data = *(fastSweepDataPtr[threadIndex]);
Allocator alloc = createAlloc();
for (int i = treeID; i < miniTreeCount; ++i) {
BuildRecord& br = miniTreeRecords[i];
//data.setOffset(br.prims.begin());
size_t depth = 0;
int offset = br.prims.begin();
br.parent = (size_t*)&(miniTreeRootsPtr[i]);
br.depth = 0;
br.prims = range<size_t>(0, br.prims.size());
br.pinfo.begin = 0;
br.pinfo.end = br.prims.size();
heuristic.sortIndices(data, br.prims.size(), offset);
buildMiniTreesRecursive(data, br, offset, alloc, depth);
br.depth = depth;
}}));
}
SPAWN_END;
#endif
}
}
void partitionAccordingToRef(unsigned axis, unsigned first, unsigned last) {
unsigned* __restrict temporaryIndices = ttTemporaryIndices.data();
unsigned char* __restrict leftPartition = ttLeftPartition.data();
//unsigned* __restrict indices = ttIndices[axis].data();
unsigned* __restrict indices = ttIndices[axis];
unsigned* source = indices + first;
unsigned* end = indices + last;
unsigned* left = source;
unsigned* right = temporaryIndices + first;
while (source < end) {
unsigned index = *source;
unsigned l = leftPartition[index];
*left = index;
*right = index;
left += l;
right += 1-l;
++source;
}
std::copy(temporaryIndices + first, right, left);
}
void ttPartition(unsigned axis, unsigned first, unsigned last, unsigned pivot) {
//unsigned* __restrict ref = (ttIndices[axis]).data();
unsigned* __restrict ref = (ttIndices[axis]);
unsigned char* __restrict leftPartition = ttLeftPartition.data();
for (unsigned i = first; i < pivot; ++i)
leftPartition[ref[i]] = 1;
for (unsigned i = pivot; i < last; ++i)
leftPartition[ref[i]] = 0;
partitionAccordingToRef((axis+1)%3, first, last);
partitionAccordingToRef((axis+2)%3, first, last);
}
void topTreeSweep(BuildRecord& current, BuildRecord& lrecord, BuildRecord& rrecord) {
int block_shift = 3;
unsigned first = current.prims.begin();
unsigned last = current.prims.end();
float bestSah = std::numeric_limits<float>::infinity();
unsigned bestDim = 0xffffffff;
unsigned pivot = 0xffffffff;
BBox3fa bestBounds;
unsigned bestLeftCounts = 0;
unsigned bestRightCounts = 0;
for (unsigned dim = 0; dim < 3; ++dim) {
//unsigned* __restrict sortedIndices = ttIndices[dim].data();
unsigned* __restrict sortedIndices = ttIndices[dim];
float* __restrict accumulatedArea = ttAccumulatedArea.data();
unsigned* __restrict accumulatedCounts = ttAccumulatedCounts.data();
BBox3fa bounds = miniTreeRecordsPruned[sortedIndices[first]].pinfo.geomBounds;
{
int i = (int)first;
size_t lCounts = 0;
for(; (int)i < (int)last-1; i++) {
bounds.extend(miniTreeRecordsPruned[sortedIndices[i]].pinfo.geomBounds);
float sa = halfArea(bounds);
//lCounts += miniTreeRecordsPruned[sortedIndices[i]].pinfo.size();
lCounts = miniTreeRecordsPruned[sortedIndices[i]].depth > lCounts ? miniTreeRecordsPruned[sortedIndices[i]].depth : lCounts;
accumulatedArea[i] = sa * sa * (float)((int)(i - first + 1));
//accumulatedArea[i] = sa * float((size_t(i - first + 1)+(size_t(1)<<block_shift)-1) >> block_shift);
accumulatedCounts[i] = lCounts;
}
}
bounds = miniTreeRecordsPruned[sortedIndices[last - 1]].pinfo.geomBounds;
{
int i = (int)last - 1;
size_t rCounts = 0;
for (; (int)i > (int)first; i--) {
bounds.extend(miniTreeRecordsPruned[sortedIndices[i]].pinfo.geomBounds);
//rCounts += miniTreeRecordsPruned[sortedIndices[i]].pinfo.size();
rCounts = miniTreeRecordsPruned[sortedIndices[i]].depth > rCounts ? miniTreeRecordsPruned[sortedIndices[i]].depth : rCounts;
float sa = halfArea(bounds);
float sah = (accumulatedArea[i - 1] + sa * sa * (float)((int)(last - i)));
//float sah = accumulatedArea[i - 1] + sa * float((size_t(last-i)+(size_t(1)<<block_shift)-1) >> block_shift);
if (sah < bestSah) {
bestSah = sah;
bestDim = dim;
pivot = i;
bestBounds = bounds;
bestLeftCounts = accumulatedCounts[i];
bestRightCounts = rCounts;
}
}
}
}
lrecord.prims = range<size_t>(first, pivot);
rrecord.prims = range<size_t>(pivot, last);
ttPartition(bestDim, first, last, pivot);
rrecord.pinfo = PrimInfo(pivot, last, bestBounds, bestBounds);
rrecord.depth = bestRightCounts;
//bestBounds = miniTreeRecordsPruned[ttIndices[0].data()[first]].pinfo.geomBounds;
bestBounds = miniTreeRecordsPruned[ttIndices[0][first]].pinfo.geomBounds;
size_t index = first + 1;
for (; index < pivot; index++) {
//bestBounds.extend(miniTreeRecordsPruned[ttIndices[0].data()[index]].pinfo.geomBounds);
bestBounds.extend(miniTreeRecordsPruned[ttIndices[0][index]].pinfo.geomBounds);
}
lrecord.pinfo = PrimInfo(first, pivot, bestBounds, bestBounds);
lrecord.depth = bestLeftCounts;
}
void buildTopTreeRecursive(BuildRecord& current, Allocator alloc) {
if (alloc == nullptr)
alloc = createAlloc();
/* call memory monitor function to signal progress */
//if (toplevel && current.size() <= SINGLE_THREADED_THRESHOLD)
// progressMonitor(current.size());
assert(current.pinfo.size() > 0);// || leafSAH >= 0 && splitSAH >= 0);
BuildRecord children[MAX_BRANCHING_FACTOR];
/*! create a leaf node when threshold reached or SAH tells us to stop */
if (current.pinfo.size() <= branchingFactor) {
size_t count = current.pinfo.size();
for (int i = 0; i < count; i++) {
children[i] = miniTreeRecordsPruned[ttIndices[0][i + current.prims.begin()]];
}
if (count == 1) {
*current.parent = *children[0].parent;
}
else {
createNode(current, children, count, alloc, underFilledNodes);
}
return;
}
/*! initialize child list */
children[0] = current;
size_t numChildren = 1;
/*! split until node is full or SAH tells us to stop */
do {
/*! find best child to split */
float largestSAH = -1;
ssize_t largestChild = -1;
for (size_t i=0; i<numChildren; i++)
{
float currentSAH = children[i].pinfo.leafSAH(3);
if (children[i].pinfo.size() == 1) continue;
if (currentSAH > largestSAH) { largestChild = i; largestSAH = currentSAH; }
}
if (largestChild == -1) break;
/* perform best found split */
BuildRecord& brecord = children[largestChild];
BuildRecord lrecord(current.depth+1);
BuildRecord rrecord(current.depth+1);
topTreeSweep(brecord, lrecord, rrecord);
children[largestChild] = lrecord;
children[numChildren] = rrecord;
numChildren++;
} while (numChildren < branchingFactor);
/*! create an inner node */
if (numChildren == 8)
auto node = createNode(current,children,numChildren,alloc);
/* spawn tasks */
#if 0
for (ssize_t i=numChildren-1; i>=0; i--) {
// if (children[i].size() > 1)
buildTopTreeRecursive(children[i], alloc);
}
#else
if (current.size() > SINGLE_THREADED_THRESHOLD) {
SPAWN_BEGIN;
for (ssize_t i=numChildren-1; i>=0; i--)
SPAWN(([&,i] { buildTopTreeRecursive(children[i],nullptr); }));
SPAWN_END;
}
else {
for (ssize_t i=numChildren-1; i>=0; i--) {
buildTopTreeRecursive(children[i], alloc);
}
}
#endif
}
void sortTopTree() {
//if (!ttAlloc) {
Allocator alloc;
alloc = createAlloc();
ttIndicesX.resize(2*miniTreeCount+64);
ttIndicesY.resize(2*miniTreeCount+64);
ttIndicesZ.resize(2*miniTreeCount+64);
ttMidpointsX.resize(miniTreeCount+32);
ttMidpointsY.resize(miniTreeCount+32);
ttMidpointsZ.resize(miniTreeCount+32);
ttIndices[0] = (unsigned* __restrict)ttIndicesX.data();
ttIndices[1] = (unsigned* __restrict)ttIndicesY.data();
ttIndices[2] = (unsigned* __restrict)ttIndicesZ.data();
BuildRecord* __restrict mtrp = miniTreeRecordsPruned.data();
int i = 0;
float* __restrict mpx = ttMidpointsX.data();
float* __restrict mpy = ttMidpointsY.data();
float* __restrict mpz = ttMidpointsZ.data();
for (; i < miniTreeCount - 3; i += 4) {
BBox3fa b = mtrp[i].pinfo.geomBounds;
__m128 mid0 = _mm_add_ps(b.lower, b.upper);
b = mtrp[i + 1].pinfo.geomBounds;
__m128 mid1 = _mm_add_ps(b.lower, b.upper);
b = mtrp[i + 2].pinfo.geomBounds;
__m128 mid2 = _mm_add_ps(b.lower, b.upper);
b = mtrp[i + 3].pinfo.geomBounds;
__m128 mid3 = _mm_add_ps(b.lower, b.upper);
_MM_TRANSPOSE4_PS(mid0, mid1, mid2, mid3);
_mm_store_ps(mpx + i, mid0);
_mm_store_ps(mpy + i, mid1);
_mm_store_ps(mpz + i, mid2);
}
for (; i < miniTreeCount; i++) {
//Vec3fa mid = prims[(i + offset)].center2();
BBox3fa& b = mtrp[i].pinfo.geomBounds;
__m128 mid = _mm_add_ps(b.lower, b.upper);
ALIGNED(32) float midArray[4];
_mm_store_ps(midArray, mid);
//prims[(i + offset)].lower = _mm_xor_ps(prims[(i + offset)].lower, neg);
mpx[i] = midArray[0];
mpy[i] = midArray[1];
mpz[i] = midArray[2];
}
SPAWN_BEGIN;
SPAWN(([&] {sortedIndicesFromFloats(mpx, ttIndices[0], miniTreeCount);}));
SPAWN(([&] {sortedIndicesFromFloats(mpy, ttIndices[1], miniTreeCount);}));
SPAWN(([&] {sortedIndicesFromFloats(mpz, ttIndices[2], miniTreeCount);}));
SPAWN_END;
}
void buildTopTree(BuildRecord& rootRecord) {
ttTemporaryIndices.resize(miniTreeCount);
ttLeftPartition.resize(miniTreeCount);
ttAccumulatedArea.resize(miniTreeCount);
ttAccumulatedCounts.resize(miniTreeCount);
sortTopTree();
rootRecord.prims = range<size_t>(0, miniTreeCount);
rootRecord.pinfo = PrimInfo(0, miniTreeCount, rootRecord.pinfo.geomBounds, rootRecord.pinfo.centBounds);
rootRecord.depth = 0;
buildTopTreeRecursive(rootRecord, nullptr);
}
void pruneRecursive(int& newMiniTreeCount, const float averageArea, BVH8::NodeRef& nf, size_t depth) {
depth -= 1;
for (int j = 0; j < branchingFactor; j++) {
if (nf.node()->child(j).isNode() && (area(nf.node()->bounds(j)) > averageArea)) {
pruneRecursive(newMiniTreeCount, averageArea, nf.node()->child(j), depth);
}
else if (nf.node()->child(j) != BVH8::emptyNode) {
BuildRecord br;
br.pinfo.geomBounds = nf.node()->bounds(j);
br.parent = (size_t*)&nf.node()->child(j);
br.depth = depth;
miniTreeRecordsPruned[newMiniTreeCount++] = br;
}
}
}
// digs in to mini trees and removes too large pieces, which become mini trees of their own
int prune() {
float averageArea = 0;
for (int i = 0; i < miniTreeCount; i++) {
averageArea += area(miniTreeRecords[i].pinfo.geomBounds);
}
averageArea /= (float)miniTreeCount;
//std::cout << "area: " << averageArea << std::endl;
averageArea *= PRUNING_THRESHOLD;
int newMiniTreeCount = 0;
int originalMiniTreeCount = miniTreeCount;
//std::cout << "originalMiniTreeCount: " << originalMiniTreeCount << std::endl;
for (int i = 0; i < originalMiniTreeCount; i++) {
size_t originalDepth = miniTreeRecords[i].depth;
BVH8::NodeRef nf = BVH8::NodeRef(*(miniTreeRecords[i].parent));
if (nf.isNode() && area(miniTreeRecords[i].pinfo.geomBounds) > averageArea) {
originalDepth -= 1;
for (int j = 0; j < branchingFactor; j++) {
if (nf.node()->child(j).isNode() && (area(nf.node()->bounds(j)) > averageArea)) {
pruneRecursive(newMiniTreeCount, averageArea, nf.node()->child(j), originalDepth);
}
else if (nf.node()->child(j) != BVH8::emptyNode) {
BuildRecord br;
br.pinfo.geomBounds = nf.node()->bounds(j);
br.parent = (size_t*)&nf.node()->child(j);
br.depth = originalDepth;
//std::cout << originalDepth << std::endl;
miniTreeRecordsPruned[newMiniTreeCount++] = br;
}
}
}
else if (nf != BVH8::emptyNode){
miniTreeRecordsPruned[newMiniTreeCount++] = miniTreeRecords[i];
}
}
return newMiniTreeCount;
}
__forceinline void printTime(std::string s, std::chrono::high_resolution_clock::time_point& t0) const {
std::chrono::duration<float> time = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::high_resolution_clock::now()
- t0);
std::cout << s << ": " << time.count() * 1000.f << "ms" << std::endl;
}
__forceinline std::chrono::high_resolution_clock::time_point startTime() {
return std::chrono::high_resolution_clock::now();
}
/*! builder entry function */
__forceinline const ReductionTy operator() (BuildRecord& record)
{
// should be more sofisticated, top tree sweep is performed
// on an array of buildrecords, but should only be on BBoxes and indices
int maxMiniTrees = (numberOfTriangles/MAX_MINI_TREE_SIZE) > 0 ? (numberOfTriangles/MAX_MINI_TREE_SIZE) : 1;
miniTreeRecords.resize(maxMiniTrees*4);
miniTreeRecordsPruned.resize(maxMiniTrees*4*64);
miniTreeCount = 0;
underFilledNodes = 0;
//auto t = startTime();
miniTreeSelectRescursive(record);
//printTime("\nMini tree select", t);
//std::cout << "Mini tree count: " << miniTreeCount << std::endl;
miniTreeRoots.resize(miniTreeCount);
// t = startTime();
buildMiniTrees(miniTreeRoots);
// printTime("Build mini trees", t);
// t = startTime();
if (PRUNING_THRESHOLD < 1.f && PRUNING_THRESHOLD > 0.f) {
int newMiniTreeCount = prune();
while (float(newMiniTreeCount) / float(miniTreeCount) < 10.f) {
PRUNING_THRESHOLD *= 0.4f;
newMiniTreeCount = prune();
}
miniTreeCount = newMiniTreeCount;
}
// printTime("Pruning", t);
//std::cout << "Mini tree count after pruning: " << miniTreeCount << std::endl;
// t = startTime();
if (miniTreeCount > 1)
buildTopTree(record);
else
record = miniTreeRecords[0];
// printTime("Build top tree", t);
//std::cout << "Underfilled nodes: " << underFilledNodes << std::endl;
return 0;
}
private:
Heuristic& heuristic;
const ReductionTy identity;
CreateAllocFunc& createAlloc;
CreateNodeFunc& createNode;
UpdateNodeFunc& updateNode;
CreateLeafFunc& createLeaf;
ProgressMonitor& progressMonitor;
private:
const PrimInfo& pinfo;
const size_t branchingFactor;
const size_t maxDepth;
const size_t logBlockSize;
const size_t minLeafSize;
const size_t maxLeafSize;
const float travCost;
const float intCost;
};
/* SAH builder that operates on an array of BuildRecords */
struct BVHBuilderBonsai
{
typedef range<size_t> Set;
typedef HeuristicBonsai<PrimRef> Heuristic;
typedef GeneralBuildRecord<Set, typename Heuristic::Split> BuildRecord;
/*! standard build without reduction */
template<typename NodeRef,
typename CreateAllocFunc,
typename CreateNodeFunc,
typename CreateLeafFunc,
typename ProgressMonitor>
static void build(NodeRef& root,
CreateAllocFunc createAlloc,
CreateNodeFunc createNode,
CreateLeafFunc createLeaf,
ProgressMonitor progressMonitor,
PrimRef* prims, const PrimInfo& pinfo,
const size_t branchingFactor, const size_t maxDepth, const size_t blockSize,
const size_t minLeafSize, const size_t maxLeafSize,
const float travCost, const float intCost, Scene* scene, const bool splitTriangles, int numOfPrimitives)
{
/* use dummy reduction over integers */
int identity = 0;
auto updateNode = [] (int node, int*, size_t) -> int { return 0; };
/* initiate builder */
build_reduce(root,
createAlloc,
identity,
createNode,
updateNode,
createLeaf,
progressMonitor,
prims,
pinfo,
branchingFactor,maxDepth,blockSize,
minLeafSize,maxLeafSize,travCost,intCost, scene, splitTriangles, numOfPrimitives);
}
/*! special builder that propagates reduction over the tree */
template<typename NodeRef,
typename CreateAllocFunc,
typename ReductionTy,
typename CreateNodeFunc,
typename UpdateNodeFunc,
typename CreateLeafFunc,
typename ProgressMonitor>
static ReductionTy build_reduce(NodeRef& root,
CreateAllocFunc createAlloc,
const ReductionTy& identity,
CreateNodeFunc createNode, UpdateNodeFunc updateNode, CreateLeafFunc createLeaf,
ProgressMonitor progressMonitor,
PrimRef* prims, const PrimInfo& pinfo,
const size_t branchingFactor, const size_t maxDepth, const size_t blockSize,
const size_t minLeafSize, const size_t maxLeafSize,
const float travCost, const float intCost, Scene* scene, const bool splitTriangles, int numOfPrimitives)
{
/* builder wants log2 of blockSize as input */
const size_t logBlockSize = __bsr(blockSize);
//assert((blockSize ^ (size_t(1) << logBlockSize)) == 0);
/* instantiate array binning heuristic */
Heuristic heuristic(prims, scene, numOfPrimitives);
typedef GeneralBVHBuilder<
BuildRecord,
Heuristic,
ReductionTy,
decltype(createAlloc()),
CreateAllocFunc,
CreateNodeFunc,
UpdateNodeFunc,
CreateLeafFunc,
ProgressMonitor> Builder;
/* instantiate builder */
Builder builder(heuristic,
identity,
createAlloc,
createNode,
updateNode,
createLeaf,
progressMonitor,
pinfo,
branchingFactor,maxDepth,logBlockSize,
minLeafSize,maxLeafSize,travCost,intCost, numOfPrimitives, splitTriangles, scene);
/* build hierarchy */
//BuildRecord br(pinfo,1,(size_t*)&root,Set(0,pinfo.size()));
BuildRecord br(pinfo,1,(size_t*)&root,Set(0,pinfo.size()), Set(0,pinfo.size()*2));
return builder(br);
}
};
}
}
+750
View File
@@ -0,0 +1,750 @@
// ======================================================================== //
// Copyright 2009-2015 Intel Corporation //
// //
// 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 //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// 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 //
// limitations under the License. //
// ======================================================================== //
#pragma once
#include "heuristic_binning.h"
#include "../../algorithms/IndexSort.h"
#include "../../common/scene.h"
#include "presplit.h"
#include <immintrin.h>
#ifdef _WIN32
#define ALIGNED(n) __declspec(align(n))
#else
#define ALIGNED(n) __attribute__((aligned(n)))
#endif
#define _MM256_TRANSPOSE4_PS(row0, row1, row2, row3) \
do {\
__m256 tmp3, tmp2, tmp1, tmp0;\
tmp0 = _mm256_unpacklo_ps((row0), (row1));\
tmp2 = _mm256_unpacklo_ps((row2), (row3));\
tmp1 = _mm256_unpackhi_ps((row0), (row1));\
tmp3 = _mm256_unpackhi_ps((row2), (row3));\
(row0) = _mm256_movelh_ps(tmp0, tmp2);\
(row1) = _mm256_movehl_ps(tmp2, tmp0);\
(row2) = _mm256_movelh_ps(tmp1, tmp3);\
(row3) = _mm256_movehl_ps(tmp3, tmp1);\
} while (0)
inline __m256 combine(__m128 a, __m128 b) {
return _mm256_insertf128_ps(_mm256_castps128_ps256(a), b, 1);
}
inline __m256 _mm256_movelh_ps(__m256 a, __m256 b) {
return _mm256_shuffle_ps(a, b, _MM_SHUFFLE(1, 0, 1, 0));
}
inline __m256 _mm256_movehl_ps(__m256 a, __m256 b) {
return _mm256_shuffle_ps(b, a, _MM_SHUFFLE(3, 2, 3, 2));
}
inline float surfaceArea(__m256 bounds) {
__m128 d = _mm_add_ps(_mm256_castps256_ps128(bounds), _mm256_extractf128_ps(bounds, 1));
d = _mm_mul_ps(_mm_shuffle_ps(d, d, _MM_SHUFFLE(3,1,0,0)), _mm_shuffle_ps(d, d, _MM_SHUFFLE(3,2,2,1)));
return _mm_cvtss_f32(_mm_add_ss(_mm_add_ss(d, _mm_shuffle_ps(d, d, _MM_SHUFFLE(2,2,2,2))), _mm_shuffle_ps(d, d, _MM_SHUFFLE(1,1,1,1))));
}
namespace embree
{
namespace isa
{
struct FastSweepData {
unsigned* __restrict indices[3];
float* __restrict midX;
float* __restrict midY;
float* __restrict midZ;
float* __restrict accumulatedArea;
unsigned* __restrict temporaryIndices;
unsigned char* __restrict leftPartition;
PrimRef* __restrict gatheredRefs;
unsigned offset;
bool isAllocated;
FastSweepData() {
isAllocated = false;
}
FastSweepData(unsigned size, size_t maxLeafSize) {
fastSweepDataAllocate(size, maxLeafSize);
}
void setOffset(unsigned offset) {
this->offset = offset;
}
void fastSweepDataAllocate(unsigned size, size_t maxLeafSize) {
indices[0] = static_cast<unsigned*>(_mm_malloc(4 * size * sizeof(unsigned) + 256, 64));
indices[1] = static_cast<unsigned*>(_mm_malloc(4 * size * sizeof(unsigned) + 256, 64));
indices[2] = static_cast<unsigned*>(_mm_malloc(4 * size * sizeof(unsigned) + 256, 64));
midX = static_cast<float*>(_mm_malloc(size*sizeof(float) + 256, 64));
midY = static_cast<float*>(_mm_malloc(size*sizeof(float) + 256, 64));
midZ = static_cast<float*>(_mm_malloc(size*sizeof(float) + 256, 64));
accumulatedArea = static_cast<float*>(_mm_malloc(size * sizeof(float), 64)); //new float[size];
temporaryIndices = new unsigned[size];
leftPartition = new unsigned char[size];
gatheredRefs = static_cast<PrimRef*>(_mm_malloc(maxLeafSize * 2 * sizeof(PrimRef), 64));
isAllocated = true;
}
~FastSweepData() {
_mm_free(indices[0]);
_mm_free(indices[1]);
_mm_free(indices[2]);
_mm_free(midX);
_mm_free(midY);
_mm_free(midZ);
_mm_free(accumulatedArea);
_mm_free(gatheredRefs);
delete [] temporaryIndices;
delete [] leftPartition;
}
};
/*! stores all information to perform some split */
struct BonsaiSplit
{
/*! construct an invalid split by default */
__forceinline BonsaiSplit()
: dim(-1), pos(0.f), minimalLeafFound(false) {}
/*! tests if this split is valid */
__forceinline bool valid() const { return dim != -1; }
/*! sets leafFound to true */
__forceinline void leafFound() { minimalLeafFound = true; }
/*! */
__forceinline bool isLeaf() const { return minimalLeafFound; }
/*! stream output */
friend std::ostream& operator<<(std::ostream& cout, const BonsaiSplit& split) {
return cout << "BinSplit { dim = " << split.dim << ", pos = " << split.pos << "}";
}
public:
int dim; //!< split dimension
float pos; //!< split plane at dim dimension
int index; //!< split index
bool minimalLeafFound; //!< true if a local SAH minimum has been found and size is less than maxLeafSize
};
/*! Performs standard object binning */
template<typename PrimRef>
struct HeuristicBonsai
{
typedef BonsaiSplit Split;
typedef range<size_t> Set;
static const size_t PARALLEL_THRESHOLD = 10000;
static const size_t PARALLEL_FIND_BLOCK_SIZE = 4096;
static const size_t PARALLEL_PARITION_BLOCK_SIZE = 64;
volatile int newIndex = 0;
FastSweepData** __restrict ThreadLocal;
__forceinline HeuristicBonsai ()
: prims(nullptr) {}
/*! remember prim array */
__forceinline HeuristicBonsai (PrimRef* prims, Scene* scene, int splitIndex)
: prims(prims), scene(scene), splitIndex(splitIndex) {}
/*! array partitioning */
void split(const Split& split, const PrimInfo& pinfo, const Set& set, PrimInfo& left, Set& lset, PrimInfo& right, Set& rset)
{
if (likely(pinfo.size() < PARALLEL_THRESHOLD))
sequential_split(split,set,left,lset,right,rset);
//sequential_partition(split,set,left,lset,right,rset);
else
parallel_split(split,set,left,lset,right,rset);
}
void sequential_partition(const Split& split, const Set& set, PrimInfo& left, Set& lset, PrimInfo& right, Set& rset) {
const size_t begin = set.begin();
const size_t end = set.end();
CentGeomBBox3fa local_left(empty);
CentGeomBBox3fa local_right(empty);
const float splitPos = split.pos;
const unsigned int splitDim = split.dim;
int i = begin;
int j = end - 1;
while (prims[i].center2()[splitDim] <= splitPos) {
local_left.extend(prims[i].bounds());
++i;
}
while (prims[j].center2()[splitDim] > splitPos) {
local_right.extend(prims[j].bounds());
--j;
}
while (i < j) {
xchg(prims[i], prims[j]);
local_left.extend(prims[i].bounds());
local_right.extend(prims[j].bounds());
++i;
--j;
while (prims[i].center2()[splitDim] <= splitPos) {
local_left.extend(prims[i].bounds());
++i;
}
while (prims[j].center2()[splitDim] > splitPos) {
local_right.extend(prims[j].bounds());
--j;
}
}
size_t center = i;
new (&left ) PrimInfo(begin,center,local_left.geomBounds,local_left.centBounds);
new (&right) PrimInfo(center,end,local_right.geomBounds,local_right.centBounds);
new (&lset) range<size_t>(begin,center);
new (&rset) range<size_t>(center,end);
}
/*! array partitioning */
void sequential_split(const Split& split, const Set& set, PrimInfo& left, Set& lset, PrimInfo& right, Set& rset)
{
/*
if (!split.valid()) {
deterministic_order(set);
return splitFallback(set,left,lset,right,rset);
}
*/
const size_t begin = set.begin();
const size_t end = set.end();
CentGeomBBox3fa local_left(empty);
CentGeomBBox3fa local_right(empty);
const float splitPos = split.pos;
const unsigned int splitDim = split.dim;
const unsigned int splitDimMask = (unsigned int)1 << splitDim; // FIXME: also use in unaligned and spatial binner
size_t center = serial_partitioning(prims,begin,end,local_left,local_right,
[&] (const PrimRef& ref) { return ref.center2()[splitDim] < splitPos; },
[] (CentGeomBBox3fa& pinfo,const PrimRef& ref) { pinfo.extend(ref.bounds()); });
new (&left ) PrimInfo(begin,center,local_left.geomBounds,local_left.centBounds);
new (&right) PrimInfo(center,end,local_right.geomBounds,local_right.centBounds);
new (&lset) range<size_t>(begin,center);
new (&rset) range<size_t>(center,end);
assert(area(left.geomBounds) >= 0.0f);
assert(area(right.geomBounds) >= 0.0f);
}
/*! array partitioning */
void parallel_split(const Split& split, const Set& set, PrimInfo& left, Set& lset, PrimInfo& right, Set& rset)
{
/*
if (!split.valid()) {
deterministic_order(set);
return splitFallback(set,left,lset,right,rset);
}
*/
const size_t begin = set.begin();
const size_t end = set.end();
left.reset();
right.reset();
PrimInfo init; init.reset();
const float splitPos = split.pos;
const unsigned int splitDim = split.dim;
const size_t mid = parallel_in_place_partitioning<PARALLEL_PARITION_BLOCK_SIZE,PrimRef,PrimInfo>
(&prims[begin],end-begin,init,left,right,
[&] (const PrimRef &ref) { return ref.center2()[splitDim] < splitPos; },
[] (PrimInfo &pinfo,const PrimRef &ref) { pinfo.add(ref.bounds()); },
[] (PrimInfo &pinfo0,const PrimInfo &pinfo1) { pinfo0.merge(pinfo1); });
const size_t center = begin+mid;
left.begin = begin; left.end = center; // FIXME: remove?
right.begin = center; right.end = end;
new (&lset) range<size_t>(begin,center);
new (&rset) range<size_t>(center,end);
}
void sortIndices(FastSweepData& data, const int count, unsigned offset) {
__m128 neg = _mm_set_ps(0.0f, -0.0f, -0.0f, -0.f); // shouldn't it be (-0, -0, -0, 0) ?
int i = 0;
for (; i < count - 3; i += 4) {
// crashes if prims[(i + 0 + offset)].center2() are used
// __m128 mid0 = prims[(i + 0 + offset)].center2();
__m128 mid0 = _mm_add_ps(prims[(i + 0 + offset)].lower, prims[(i + 0 + offset)].upper);
prims[(i + 0 + offset)].lower = _mm_xor_ps(prims[(i + 0 + offset)].lower, neg);
//__m128 mid1 = prims[(i + 1 + data.offset)].center2();
__m128 mid1 = _mm_add_ps(prims[(i + 1 + offset)].lower, prims[(i + 1 + offset)].upper);
prims[(i + 1 + offset)].lower = _mm_xor_ps(prims[(i + 1 + offset)].lower, neg);
//__m128 mid2 = prims[(i + 2 + data.offset)].center2();
__m128 mid2 = _mm_add_ps(prims[(i + 2 + offset)].lower, prims[(i + 2 + offset)].upper);
prims[(i + 2 + offset)].lower = _mm_xor_ps(prims[(i + 2 + offset)].lower, neg);
//__m128 mid3 = prims[(i + 3 + data.offset)].center2();
__m128 mid3 = _mm_add_ps(prims[(i + 3 + offset)].lower, prims[(i + 3 + offset)].upper);
prims[(i + 3 + offset)].lower = _mm_xor_ps(prims[(i + 3 + offset)].lower, neg);
_MM_TRANSPOSE4_PS(mid0, mid1, mid2, mid3);
_mm_store_ps(data.midX + i, mid0);
_mm_store_ps(data.midY + i, mid1);
_mm_store_ps(data.midZ + i, mid2);
//#define STD_SORT
#ifdef STD_SORT
data.indices[0][i+0] = data.indices[1][i+0] = data.indices[2][i+0] = i + offset + 0;
data.indices[0][i+1] = data.indices[1][i+1] = data.indices[2][i+1] = i + offset + 1;
data.indices[0][i+2] = data.indices[1][i+2] = data.indices[2][i+2] = i + offset + 2;
data.indices[0][i+3] = data.indices[1][i+3] = data.indices[2][i+3] = i + offset + 3;
#endif
}
for (; i < count; i++) {
//Vec3fa mid = prims[(i + offset)].center2();
__m128 mid = _mm_add_ps(prims[(i + offset)].lower, prims[(i + offset)].upper);
prims[(i + offset)].lower = _mm_xor_ps(prims[(i + offset)].lower, neg);
ALIGNED(32) float midArray[4];
_mm_store_ps(midArray, mid);
data.midX[i] = midArray[0];
data.midY[i] = midArray[1];
data.midZ[i] = midArray[2];
#ifdef STD_SORT
data.indices[0][i+0] = data.indices[1][i+0] = data.indices[2][i+0] = i + offset + 0;
#endif
}
float* mmx = data.midX;
float* mmy = data.midY;
float* mmz = data.midZ;
#ifdef STD_SORT
std::sort(data.indices[0], data.indices[0] + count, [mmx, offset](unsigned& a, unsigned& b) { return mmx[a-offset] < mmx[b-offset]; });
std::sort(data.indices[1], data.indices[1] + count, [mmy, offset](unsigned& a, unsigned& b) { return mmy[a-offset] < mmy[b-offset]; });
std::sort(data.indices[2], data.indices[2] + count, [mmz, offset](unsigned& a, unsigned& b) { return mmz[a-offset] < mmz[b-offset]; });
#else
sortedIndicesFromFloatsX3(data.midX, data.midY, data.midZ, data.indices[0], data.indices[1], data.indices[2], count, offset);
#endif
for (int i = 0; i < count-1; i++) {
assert(mmx[data.indices[0][i]-offset] <= mmx[data.indices[0][i+1]-offset]);
assert(mmy[data.indices[1][i]-offset] <= mmy[data.indices[1][i+1]-offset]);
assert(mmz[data.indices[2][i]-offset] <= mmz[data.indices[2][i+1]-offset]);
}
}
__forceinline __m256 computeBounds(const float* __restrict leafBounds, const unsigned* __restrict remap, unsigned first, unsigned last) {
__m256 bounds0 = _mm256_load_ps(leafBounds + remap[first]*8);
__m256 bounds1 = bounds0;
__m256 bounds2 = bounds0;
__m256 bounds3 = bounds0;
unsigned i = first;
for (; i+7 < last; i += 8) {
unsigned i0 = remap[i+0];
unsigned i1 = remap[i+1];
unsigned i2 = remap[i+2];
unsigned i3 = remap[i+3];
__m256 a0 = _mm256_load_ps(leafBounds + i0*8);
__m256 a1 = _mm256_load_ps(leafBounds + i1*8);
__m256 a2 = _mm256_load_ps(leafBounds + i2*8);
__m256 a3 = _mm256_load_ps(leafBounds + i3*8);
unsigned i4 = remap[i+4];
unsigned i5 = remap[i+5];
unsigned i6 = remap[i+6];
unsigned i7 = remap[i+7];
__m256 a4 = _mm256_load_ps(leafBounds + i4*8);
__m256 a5 = _mm256_load_ps(leafBounds + i5*8);
__m256 a6 = _mm256_load_ps(leafBounds + i6*8);
__m256 a7 = _mm256_load_ps(leafBounds + i7*8);
a1 = _mm256_max_ps(a1, a0);
a3 = _mm256_max_ps(a3, a2);
a5 = _mm256_max_ps(a5, a4);
a7 = _mm256_max_ps(a7, a6);
bounds0 = _mm256_max_ps(bounds0, a1);
bounds1 = _mm256_max_ps(bounds1, a3);
bounds2 = _mm256_max_ps(bounds2, a5);
bounds3 = _mm256_max_ps(bounds3, a7);
}
for (; i < last; ++i)
bounds0 = _mm256_max_ps(bounds0, _mm256_load_ps(leafBounds + remap[i]*8));
return _mm256_max_ps(_mm256_max_ps(bounds0, bounds1), _mm256_max_ps(bounds2, bounds3));
}
inline BBox3fa avxBoundsToEmbreeBounds(__m256 bounds) {
__m128 neg = _mm_set_ps(0.0f, -0.0f, -0.0f, -0.f);
Vec3fa lower(_mm_xor_ps(_mm256_extractf128_ps(bounds, 0), neg));
Vec3fa upper(_mm256_extractf128_ps(bounds, 1));
return BBox3fa(lower, upper);
}
bool fastSweep(FastSweepData& data, PrimInfo& current, Split& csplit, Set& cprims, PrimInfo& left, Set& lprims, Split& lsplit, PrimInfo& right, Set& rprims, Split& rsplit, const size_t maxLeafSize, unsigned offset) {
int block_shift = 2;
const int mult = 1;//1000000;
const float traversalCost = 0.5f;
const float intersectionCost = 1.0f;
unsigned first = cprims.begin();
unsigned last = cprims.end();
float* __restrict__ leafBounds = reinterpret_cast<float*>(prims);
/*
if (depth == 0) {
__m256 cb = computeBounds(leafBounds, data.indices[0], first, last);
current.geomBounds = avxBoundsToEmbreeBounds(cb);
float divPsa = intersectionCost / surfaceArea(cb);
}
*/
float divPsa = intersectionCost / surfaceArea(combine(_mm_xor_ps(current.geomBounds.lower, _mm_set_ps(-0.0f, -0.0f, -0.0f, -0.f)), current.geomBounds.upper));
float bestSah = std::numeric_limits<float>::infinity();
unsigned bestDim = 0xffffffff;
unsigned pivot = 0xffffffff;
__m256 bestBounds;
//std::cout << "first: " << first << " pivot: " << pivot << " last: " << last << std::endl;
if (divPsa != std::numeric_limits<float>::infinity()) {
for (unsigned dim = 0; dim < 3; ++dim) {
unsigned* __restrict sortedIndices = data.indices[dim];
float* __restrict accumulatedArea = data.accumulatedArea;
/* left to right accumulate sweep */
__m256 bounds = _mm256_load_ps(leafBounds + sortedIndices[first]*8);
{
int i = (int)first;
for(; (int)i < (int)last - 8; i+=8) {
__m256 bb0 = _mm256_load_ps(leafBounds + sortedIndices[i+0]*8);
__m256 bb1 = _mm256_load_ps(leafBounds + sortedIndices[i+1]*8);
__m256 bb2 = _mm256_load_ps(leafBounds + sortedIndices[i+2]*8);
__m256 bb3 = _mm256_load_ps(leafBounds + sortedIndices[i+3]*8);
bb0 = _mm256_max_ps(bb0, bounds);
__m256 bb4 = _mm256_load_ps(leafBounds + sortedIndices[i+4]*8);
__m256 bb5 = _mm256_load_ps(leafBounds + sortedIndices[i+5]*8);
__m256 bb6 = _mm256_load_ps(leafBounds + sortedIndices[i+6]*8);
__m256 bb7 = _mm256_load_ps(leafBounds + sortedIndices[i+7]*8);
bb1 = _mm256_max_ps(bb1, bb0);
bb3 = _mm256_max_ps(bb3, bb2);
bb5 = _mm256_max_ps(bb5, bb4);
bb7 = _mm256_max_ps(bb7, bb6);
bb3 = _mm256_max_ps(bb3, bb1);
bb7 = _mm256_max_ps(bb7, bb5);
bb7 = _mm256_max_ps(bb7, bb3);
bb5 = _mm256_max_ps(bb5, bb3);
bb4 = _mm256_max_ps(bb4, bb3);
bb2 = _mm256_max_ps(bb2, bb1);
bb6 = _mm256_max_ps(bb6, bb5);
bounds = bb7;
__m256 d0 = _mm256_add_ps(_mm256_permute2f128_ps(bb0, bb4, (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb0, bb4, (1) | ((3) << 4)));
__m256 d1 = _mm256_add_ps(_mm256_permute2f128_ps(bb1, bb5, (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb1, bb5, (1) | ((3) << 4)));
__m256 d2 = _mm256_add_ps(_mm256_permute2f128_ps(bb2, bb6, (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb2, bb6, (1) | ((3) << 4)));
__m256 d3 = _mm256_add_ps(_mm256_permute2f128_ps(bb3, bb7, (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb3, bb7, (1) | ((3) << 4)));
_MM256_TRANSPOSE4_PS(d0, d1, d2, d3);
__m256 area = _mm256_fmadd_ps(d0, d1, _mm256_fmadd_ps(d0, d2, _mm256_mul_ps(d1, d2)));
_mm256_storeu_ps(accumulatedArea + i, area);
}
for (; i < last-1; ++i) {
bounds = _mm256_max_ps(bounds, _mm256_load_ps(leafBounds + sortedIndices[i]*8));
accumulatedArea[i] = surfaceArea(bounds);
}
}
/* right to left sah cost computation sweep */
bounds = _mm256_load_ps(leafBounds + sortedIndices[last-1]*8);
{
__m256 bb[8];
int i = (int)last - 1;
for (; i > (int)first+7; i -= 8) {
bb[0] = _mm256_load_ps(leafBounds + sortedIndices[i-0]*8);
bb[1] = _mm256_load_ps(leafBounds + sortedIndices[i-1]*8);
bb[2] = _mm256_load_ps(leafBounds + sortedIndices[i-2]*8);
bb[3] = _mm256_load_ps(leafBounds + sortedIndices[i-3]*8);
bb[0] = _mm256_max_ps(bb[0], bounds);
bb[4] = _mm256_load_ps(leafBounds + sortedIndices[i-4]*8);
bb[5] = _mm256_load_ps(leafBounds + sortedIndices[i-5]*8);
bb[6] = _mm256_load_ps(leafBounds + sortedIndices[i-6]*8);
bb[7] = _mm256_load_ps(leafBounds + sortedIndices[i-7]*8);
bb[1] = _mm256_max_ps(bb[1], bb[0]);
bb[3] = _mm256_max_ps(bb[3], bb[2]);
bb[5] = _mm256_max_ps(bb[5], bb[4]);
bb[7] = _mm256_max_ps(bb[7], bb[6]);
bb[3] = _mm256_max_ps(bb[3], bb[1]);
__m256 lsa = _mm256_loadu_ps(accumulatedArea + (i - 8));
bb[7] = _mm256_max_ps(bb[7], bb[5]);
lsa = _mm256_shuffle_ps(lsa, lsa, _MM_SHUFFLE(0,1,2,3));
lsa = _mm256_permute2f128_ps(lsa, lsa, (1) | ((0) << 4));
bb[7] = _mm256_max_ps(bb[7], bb[3]);
bb[5] = _mm256_max_ps(bb[5], bb[3]);
bb[4] = _mm256_max_ps(bb[4], bb[3]);
bb[2] = _mm256_max_ps(bb[2], bb[1]);
bb[6] = _mm256_max_ps(bb[6], bb[5]);
bounds = bb[7];
__m256 d0 = _mm256_add_ps(_mm256_permute2f128_ps(bb[0], bb[4], (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb[0], bb[4], (1) | ((3) << 4)));
__m256 d1 = _mm256_add_ps(_mm256_permute2f128_ps(bb[1], bb[5], (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb[1], bb[5], (1) | ((3) << 4)));
__m256 d2 = _mm256_add_ps(_mm256_permute2f128_ps(bb[2], bb[6], (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb[2], bb[6], (1) | ((3) << 4)));
__m256 d3 = _mm256_add_ps(_mm256_permute2f128_ps(bb[3], bb[7], (0) | ((2) << 4)),
_mm256_permute2f128_ps(bb[3], bb[7], (1) | ((3) << 4)));
_MM256_TRANSPOSE4_PS(d0, d1, d2, d3);
__m256 rsa = _mm256_fmadd_ps(d0, d1, _mm256_fmadd_ps(d0, d2, _mm256_mul_ps(d1, d2)));
__m256i leftIndices;
__m256i rightIndices;
if (last - first <= maxLeafSize*mult) {
int lbi[8];
int rbi[8];
for (int bi = 0; bi < 8; bi++) {
lbi[bi] = ((size_t((i - bi) - first)+(size_t(1)<<block_shift)-1) >> block_shift);
rbi[bi] = ((size_t(last - (i - bi))+(size_t(1)<<block_shift)-1) >> block_shift);
}
//std::cout << "first: " << first << " pivot: " << pivot << " last: " << last << std::endl;
leftIndices = _mm256_setr_epi32(lbi[0], lbi[1], lbi[2], lbi[3], lbi[4], lbi[5], lbi[6], lbi[7]);
rightIndices = _mm256_setr_epi32(rbi[0], rbi[1], rbi[2], rbi[3], rbi[4], rbi[5], rbi[6], rbi[7]);
}
/*
__m256 sah = _mm256_add_ps(_mm256_mul_ps(lsa, leftIndices),
_mm256_mul_ps(rsa, rightIndices));
*/
else {
__m256i indices = _mm256_sub_epi32(_mm256_set1_epi32(i), _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7));
leftIndices = _mm256_sub_epi32(indices, _mm256_set1_epi32(first));
rightIndices = _mm256_sub_epi32(_mm256_set1_epi32(last), indices);
}
/*
__m256 sah = _mm256_fmadd_ps(_mm256_set1_ps(intersectionCost * divPsa),
_mm256_fmadd_ps(lsa, _mm256_cvtepi32_ps(leftIndices),
_mm256_mul_ps(rsa, _mm256_cvtepi32_ps(rightIndices))), _mm256_set1_ps(traversalCost));
*/
__m256 sah = _mm256_add_ps(_mm256_mul_ps(lsa, _mm256_cvtepi32_ps(leftIndices)),
_mm256_mul_ps(rsa, _mm256_cvtepi32_ps(rightIndices)));
if (_mm256_movemask_ps(_mm256_cmp_ps(sah, _mm256_set1_ps(bestSah), _CMP_LT_OQ))) {
__m256 minSah = _mm256_min_ps(sah, _mm256_shuffle_ps(sah, sah, _MM_SHUFFLE(2,3,0,1)));
minSah = _mm256_min_ps(minSah, _mm256_shuffle_ps(minSah, minSah, _MM_SHUFFLE(1,0,3,2)));
minSah = _mm256_min_ps(minSah, _mm256_permute2f128_ps(minSah, minSah, (1) << ((0) << 4)));
unsigned mask = _mm256_movemask_ps(_mm256_cmp_ps(minSah, sah, _CMP_EQ_OQ));
ALIGNED(32) float sahArray[8];
_mm256_store_ps(sahArray, sah);
unsigned index = __builtin_ctz(mask);
bestBounds = bb[index];
bestSah = sahArray[index];
bestDim = dim;
pivot = i-(int)index;
}
}
for (; i > (int)first; --i) {
bounds = _mm256_max_ps(bounds, _mm256_load_ps(leafBounds + sortedIndices[i]*8));
float lsa = accumulatedArea[i - 1];
float rsa = surfaceArea(bounds);
if (last - first <= maxLeafSize*mult) {
lsa *= float((size_t(i-first)+(size_t(1)<<block_shift)-1) >> block_shift);
rsa *= float((size_t(last-i)+(size_t(1)<<block_shift)-1) >> block_shift);
}
else {
lsa *= ((float)(i - (int)first)); // Left child.
rsa *= ((float)((int)last - i)); // Right child.
}
//std::cout << lcount << ", " << rcount << std::endl;
float sah = //traversalCost + intersectionCost * divPsa * // Constant cost.
//(lsa * ((float)(i - (int)first)) + // Left child.
//rsa * ((float)((int)last - i))); // Right child.
lsa +
rsa;
if (sah < bestSah) {
bestBounds = bounds;
bestSah = sah;
bestDim = dim;
pivot = i;
}
}
}
}
}
else {
divPsa = 1.f;
bestDim = 0;
}
//std::cout << "first: " << first << " pivot: " << pivot << " last: " << last << std::endl;
float leafBlocks = (last - first);//float((size_t(last-first)+(size_t(1)<<block_shift)-1) >> block_shift);
if (last - first <= maxLeafSize*mult)
leafBlocks = float((size_t(last-first)+(size_t(1)<<block_shift)-1) >> block_shift);
//float blockBestSah = surfaceArea(bestBounds) * leafBlocks;
//if (bestSah > leafBlocks * intersectionCost) {
if (traversalCost + intersectionCost * divPsa * bestSah > leafBlocks * intersectionCost) {
if (last - first > maxLeafSize) {
//if (bestSah == std::numeric_limits<float>::infinity()) {
pivot = (first + last) >> 1;
bestBounds = computeBounds(leafBounds, data.indices[bestDim], pivot, last);
//}
}
else {
csplit.leafFound();
return true;
}
}
lprims = Set(first, pivot);
rprims = Set(pivot, last);
partition(data, bestDim, first, last, pivot, offset);
BBox3fa finalBounds = avxBoundsToEmbreeBounds(bestBounds);
right = PrimInfo(pivot, last, finalBounds, finalBounds);
bestBounds = computeBounds(leafBounds, data.indices[bestDim], first, pivot);
finalBounds = avxBoundsToEmbreeBounds(bestBounds);
left = PrimInfo(first, pivot, finalBounds, finalBounds);
return false;
}
void partition(FastSweepData& data, unsigned axis, unsigned first, unsigned last, unsigned pivot, unsigned offset) const {
unsigned* __restrict ref = data.indices[axis];
unsigned char* __restrict leftPartition = data.leftPartition;
for (unsigned i = first; i < pivot; ++i)
leftPartition[ref[i] - offset] = 1;
for (unsigned i = pivot; i < last; ++i)
leftPartition[ref[i] - offset] = 0;
partitionAccordingToRef(data, (axis+1)%3, first, last, offset);
partitionAccordingToRef(data, (axis+2)%3, first, last, offset);
}
void partitionAccordingToRef(FastSweepData& data, unsigned axis, unsigned first, unsigned last, unsigned offset) const {
unsigned* __restrict temporaryIndices = data.temporaryIndices;
unsigned char* __restrict leftPartition = data.leftPartition;
unsigned* __restrict indices = data.indices[axis];
unsigned* source = indices + first;
unsigned* end = indices + last;
unsigned* left = source;
unsigned* right = temporaryIndices + first;
while (source < end) {
unsigned index = *source;
unsigned l = leftPartition[index - offset];
*left = index;
*right = index;
left += l;
right += 1-l;
++source;
}
std::copy(temporaryIndices + first, right, left);
}
void gatherReferences(FastSweepData& data, const Set& current) {
PrimRef* localPrims = data.gatheredRefs;
for (int i = 0; i < current.size(); i++) {
localPrims[i] = prims[data.indices[0][i + current.begin()]];
}
}
private:
PrimRef* prims;
Scene* scene;
volatile int splitIndex; // not currently used
};
}
}
+14 -15
View File
@@ -28,22 +28,22 @@ namespace embree
{
namespace isa
{
__forceinline void splitTriangle(const PrimRef& prim, int dim, float pos,
__forceinline void splitTriangle(const PrimRef& prim, int dim, float pos,
const Vec3fa& a, const Vec3fa& b, const Vec3fa& c, PrimRef& left_o, PrimRef& right_o)
{
BBox3fa left = empty, right = empty;
const Vec3fa v[3] = { a,b,c };
/* clip triangle to left and right box by processing all edges */
Vec3fa v1 = v[2];
for (size_t i=0; i<3; i++)
{
Vec3fa v0 = v1; v1 = v[i];
float v0d = v0[dim], v1d = v1[dim];
if (v0d <= pos) left. extend(v0); // this point is on left side
if (v0d >= pos) right.extend(v0); // this point is on right side
if ((v0d < pos && pos < v1d) || (v1d < pos && pos < v0d)) // the edge crosses the splitting location
{
assert((v1d-v0d) != 0.0f);
@@ -54,12 +54,12 @@ namespace embree
}
//assert(!left.empty()); // happens if split does not hit triangle
//assert(!right.empty()); // happens if split does not hit triangle
/* clip against current bounds */
BBox3fa bounds = prim.bounds();
BBox3fa cleft (max(left .lower,bounds.lower),min(left .upper,bounds.upper));
BBox3fa cright(max(right.lower,bounds.lower),min(right.upper,bounds.upper));
new (&left_o ) PrimRef(cleft, prim.geomID(), prim.primID());
new (&right_o) PrimRef(cright,prim.geomID(), prim.primID());
}
@@ -84,11 +84,11 @@ namespace embree
auto order = [] (const Item& a, const Item& b) {
return halfArea(a.sceneBounds) < halfArea(b.sceneBounds);
};
while (i < N)
{
/* pop item with largest scene bounds */
std::pop_heap (&items[0],&items[i],order);
std::pop_heap (&items[0],&items[i],order);
const Item item = items[--i];
/* split scene bounds into two halfes along largest dimension */
@@ -108,7 +108,7 @@ namespace embree
items[i++] = Item(rsceneBounds,item.prim);
std::push_heap (&items[0],&items[i],order);
}
/* if split is on the right side of primitive, continue with left half of scene bounds */
else if (center > upper)
{
@@ -137,7 +137,7 @@ namespace embree
for (size_t i=1; i<N; i++)
prims_o[i-1] = items[i].prim;
}
template<typename Area, typename Split>
inline const PrimInfo presplit(const PrimInfo& pinfo, mvector<PrimRef>& prims, const Area& area, const Split& split)
{
@@ -155,7 +155,7 @@ namespace embree
do {
f *= 0.9f;
N = pinfo.size() + parallel_prefix_sum (state, size_t(0), pinfo.size(), size_t(1024), size_t(0), [&] (const range<size_t>& r, const size_t sum) -> size_t
{
{
size_t N=0;
for (size_t i=r.begin(); i<r.end(); i++) {
const float nf = ceil(f*pinfo.size()*area(prims[i])/A);
@@ -164,7 +164,7 @@ namespace embree
}
return N;
},std::plus<size_t>());
if (iter++ == 10) // to avoid infinite loop, e.g. for pinfo.size()==1 and prims.size()==1
if (iter++ == 100) // to avoid infinite loop, e.g. for pinfo.size()==1 and prims.size()==1
return pinfo;
} while (pinfo.size()+N > prims.size());
@@ -209,8 +209,8 @@ namespace embree
template<>
inline const PrimInfo presplit<TriangleMesh>(Scene* scene, const PrimInfo& pinfo, mvector<PrimRef>& prims)
{
return presplit(pinfo,prims,
[&] (const PrimRef& prim) -> float {
return presplit(pinfo,prims,
[&] (const PrimRef& prim) -> float {
const size_t geomID = prim.geomID();
const size_t primID = prim.primID();
const TriangleMesh* mesh = scene->getTriangleMesh(geomID);
@@ -240,4 +240,3 @@ namespace embree
}
}
}
+36 -28
View File
@@ -58,13 +58,14 @@ namespace embree
DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle4SceneBuilderSAH);
DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle8SceneBuilderSAH);
DECLARE_BUILDER(void,Scene,size_t,BVH8TrianglePairs8SceneBuilderSAH);
DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle4SceneBuilderBonsai);
//DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle8vSceneBuilderSAH);
DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle4SceneBuilderSpatialSAH);
DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle8SceneBuilderSpatialSAH);
//DECLARE_BUILDER(void,Scene,size_t,BVH8Triangle8vSceneBuilderSpatialSAH);
void BVH8Register ()
void BVH8Register ()
{
int features = getCPUFeatures();
@@ -73,11 +74,11 @@ namespace embree
SELECT_SYMBOL_AVX(features,BVH8Triangle8SceneBuilderSAH);
//SELECT_SYMBOL_AVX(features,BVH8Triangle8vSceneBuilderSAH);
SELECT_SYMBOL_AVX(features,BVH8TrianglePairs8SceneBuilderSAH);
SELECT_SYMBOL_AVX(features,BVH8Triangle4SceneBuilderSpatialSAH);
SELECT_SYMBOL_AVX(features,BVH8Triangle8SceneBuilderSpatialSAH);
//SELECT_SYMBOL_AVX(features,BVH8Triangle8vSceneBuilderSpatialSAH);
SELECT_SYMBOL_AVX2(features,BVH8Triangle4SceneBuilderBonsai);
/* select intersectors1 */
SELECT_SYMBOL_AVX_AVX2(features,BVH8Triangle4Intersector1Moeller);
SELECT_SYMBOL_AVX_AVX2(features,BVH8Triangle8Intersector1Moeller);
@@ -122,29 +123,29 @@ namespace embree
numPrimitives(0), numVertices(0) {}
BVH8::~BVH8 () {
for (size_t i=0; i<objects.size(); i++)
for (size_t i=0; i<objects.size(); i++)
delete objects[i];
}
void BVH8::clear()
void BVH8::clear()
{
set(BVH8::emptyNode,empty,0);
alloc2.clear();
}
void BVH8::set (NodeRef root, const BBox3fa& bounds, size_t numPrimitives)
{
this->root = root;
this->bounds = bounds;
this->numPrimitives = numPrimitives;
}
void BVH8::printStatistics()
{
std::cout << BVH8Statistics(this).str();
std::cout << " "; alloc2.print_statistics();
}
}
void BVH8::clearBarrier(NodeRef& node)
{
if (node.isBarrier())
@@ -158,7 +159,7 @@ namespace embree
void BVH8::layoutLargeNodes(size_t N)
{
struct NodeArea
struct NodeArea
{
__forceinline NodeArea() {}
@@ -191,20 +192,20 @@ namespace embree
for (size_t i=0; i<lst.size(); i++)
lst[i].node->setBarrier();
root = layoutLargeNodesRecursion(root);
}
BVH8::NodeRef BVH8::layoutLargeNodesRecursion(NodeRef& node)
{
if (node.isBarrier()) {
node.clearBarrier();
return node;
}
else if (node.isNode())
else if (node.isNode())
{
Node* oldnode = node.node();
Node* newnode = (BVH8::Node*) alloc2.threadLocal2()->alloc0.malloc(sizeof(BVH8::Node)); // FIXME: optimize access to threadLocal2
Node* newnode = (BVH8::Node*) alloc2.threadLocal2()->alloc0.malloc(sizeof(BVH8::Node)); // FIXME: optimize access to threadLocal2
*newnode = *oldnode;
for (size_t c=0; c<BVH8::N; c++)
newnode->child(c) = layoutLargeNodesRecursion(oldnode->child(c));
@@ -235,7 +236,7 @@ namespace embree
intersectors.intersector4_filter = BVH8Triangle8Intersector4HybridMoeller;
intersectors.intersector4_nofilter = BVH8Triangle8Intersector4HybridMoellerNoFilter;
intersectors.intersector8_filter = BVH8Triangle8Intersector8HybridMoeller;
intersectors.intersector8_nofilter = BVH8Triangle8Intersector8HybridMoellerNoFilter;
intersectors.intersector8_nofilter = BVH8Triangle8Intersector8HybridMoellerNoFilter;
intersectors.intersector16_filter = BVH8Triangle8Intersector16HybridMoeller;
intersectors.intersector16_nofilter = BVH8Triangle8Intersector16HybridMoellerNoFilter;
return intersectors;
@@ -270,17 +271,17 @@ namespace embree
}
Accel* BVH8::BVH8Triangle4(Scene* scene)
{
{
BVH8* accel = new BVH8(Triangle4::type,scene);
Accel::Intersectors intersectors= BVH8Triangle4Intersectors(accel);
Builder* builder = nullptr;
if (scene->device->tri_builder == "default" ) builder = BVH8Triangle4SceneBuilderSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2" ) builder = BVH8Triangle4SceneBuilderSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2_spatial" ) builder = BVH8Triangle4SceneBuilderSpatialSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2_presplit" ) builder = BVH8Triangle4SceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
else THROW_RUNTIME_ERROR("unknown builder "+scene->device->tri_builder+" for BVH8<Triangle4>");
return new AccelInstance(accel,builder,intersectors);
}
@@ -300,24 +301,32 @@ namespace embree
return new AccelInstance(accel,builder,intersectors);
}
Accel* BVH8::BVH8Triangle4Bonsai(Scene* scene)
{
BVH8* accel = new BVH8(Triangle4::type,scene);
Accel::Intersectors intersectors = BVH8Triangle4Intersectors(accel);
Builder* builder = BVH8Triangle4SceneBuilderBonsai(accel,scene,0);
return new AccelInstance(accel,builder,intersectors);
}
Accel* BVH8::BVH8Triangle8(Scene* scene)
{
{
BVH8* accel = new BVH8(Triangle8::type,scene);
Accel::Intersectors intersectors= BVH8Triangle8Intersectors(accel);
Builder* builder = nullptr;
if (scene->device->tri_builder == "default" ) builder = BVH8Triangle8SceneBuilderSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2" ) builder = BVH8Triangle8SceneBuilderSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2_spatial" ) builder = BVH8Triangle8SceneBuilderSpatialSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2_presplit" ) builder = BVH8Triangle8SceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
else THROW_RUNTIME_ERROR("unknown builder "+scene->device->tri_builder+" for BVH8<Triangle8>");
return new AccelInstance(accel,builder,intersectors);
}
/*Accel* BVH8::BVH8Triangle8v(Scene* scene)
{
{
BVH8* accel = new BVH8(Triangle8v::type,scene);
Accel::Intersectors intersectors= BVH8Triangle8vIntersectors(accel);
Builder* builder = nullptr;
@@ -325,20 +334,20 @@ namespace embree
else if (scene->device->tri_builder == "binned_sah2" ) builder = BVH8Triangle8vSceneBuilderSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2_spatial" ) builder = BVH8Triangle8vSceneBuilderSpatialSAH(accel,scene,0);
else if (scene->device->tri_builder == "binned_sah2_presplit" ) builder = BVH8Triangle8vSceneBuilderSAH(accel,scene,MODE_HIGH_QUALITY);
else
THROW_RUNTIME_ERROR("unknown builder "+scene->device->tri_builder+" for BVH8<Triangle8v>");
else
THROW_RUNTIME_ERROR("unknown builder "+scene->device->tri_builder+" for BVH8<Triangle8v>");
return new AccelInstance(accel,builder,intersectors);
}*/
Accel* BVH8::BVH8TrianglePairs8(Scene* scene)
{
{
BVH8* accel = new BVH8(TrianglePairs8::type,scene);
Accel::Intersectors intersectors = BVH8TrianglePairs8Intersectors(accel);
Builder* builder = nullptr;
if (scene->device->tri_builder == "default" ) builder = BVH8TrianglePairs8SceneBuilderSAH(accel,scene,0);
else THROW_RUNTIME_ERROR("unknown builder "+scene->device->tri_builder+" for BVH8<Triangle8>");
return new AccelInstance(accel,builder,intersectors);
}
@@ -375,4 +384,3 @@ namespace embree
}*/
}
+19 -19
View File
@@ -31,7 +31,7 @@ namespace embree
{
ALIGNED_CLASS;
public:
/*! forward declaration of node type */
struct Node;
@@ -44,20 +44,20 @@ namespace embree
static const size_t alignment = 5;
/*! Masks the bits that store the number of items per leaf. */
static const size_t align_mask = (1 << alignment)-1;
static const size_t items_mask = (1 << (alignment-1))-1;
static const size_t align_mask = (1 << alignment)-1;
static const size_t items_mask = (1 << (alignment-1))-1;
/*! Empty node */
static const size_t emptyNode = 1;
/*! Invalid node, used as marker in traversal */
static const size_t invalidNode = (((size_t)-1) & (~items_mask)) | 1;
/*! Maximal depth of the BVH. */
static const size_t maxBuildDepth = 32;
static const size_t maxBuildDepthLeaf = maxBuildDepth+16;
static const size_t maxDepth = maxBuildDepthLeaf+maxBuildDepthLeaf+maxBuildDepth;
/*! Maximal number of primitive blocks in a leaf. */
static const size_t maxLeafBlocks = 6; //items_mask-1;
@@ -94,7 +94,7 @@ namespace embree
/*! Sets the barrier bit. */
__forceinline void setBarrier() { ptr |= (size_t)(1 << (alignment-1)); }
/*! Clears the barrier bit. */
__forceinline void clearBarrier() { ptr &= ~(size_t)(1 << (alignment-1)); }
@@ -103,14 +103,14 @@ namespace embree
/*! checks if this is a leaf */
__forceinline int isLeaf() const { return (ptr & (size_t)align_mask) != 0; }
/*! checks if this is a node */
__forceinline int isNode() const { return (ptr & (size_t)align_mask) == 0; }
/*! returns node pointer */
__forceinline Node* node() { assert(isNode()); return ( Node*)ptr; }
__forceinline const Node* node() const { assert(isNode()); return (const Node*)ptr; }
/*! returns leaf pointer */
__forceinline char* leaf(size_t& num) const {
assert(isLeaf());
@@ -129,13 +129,13 @@ namespace embree
{
/*! Clears the node. */
__forceinline void clear() {
lower_x = lower_y = lower_z = pos_inf;
lower_x = lower_y = lower_z = pos_inf;
upper_x = upper_y = upper_z = neg_inf;
for (size_t i=0; i<N; i++) children[i] = emptyNode;
}
/*! Sets bounding box of child. */
__forceinline void set(size_t i, const BBox3fa& bounds)
__forceinline void set(size_t i, const BBox3fa& bounds)
{
assert(i < N);
lower_x[i] = bounds.lower.x; lower_y[i] = bounds.lower.y; lower_z[i] = bounds.lower.z;
@@ -156,7 +156,7 @@ namespace embree
}
/*! Returns bounds of specified child. */
__forceinline BBox3fa bounds(size_t i) const
__forceinline BBox3fa bounds(size_t i) const
{
assert(i < N);
const Vec3fa lower(lower_x[i],lower_y[i],lower_z[i]);
@@ -219,7 +219,7 @@ namespace embree
}
}
#endif
public:
/*! BVH8 default constructor. */
@@ -232,7 +232,7 @@ namespace embree
static Accel* BVH8Triangle4(Scene* scene);
static Accel* BVH8Triangle4ObjectSplit(Scene* scene);
static Accel* BVH8Triangle4SpatialSplit(Scene* scene);
static Accel* BVH8Triangle4Bonsai(Scene* scene);
static Accel* BVH8Triangle8(Scene* scene);
//static Accel* BVH8Triangle8v(Scene* scene);
static Accel* BVH8TrianglePairs8(Scene* scene);
@@ -260,19 +260,19 @@ namespace embree
#if defined (__AVX__)
/*! Encodes a node */
__forceinline NodeRef encodeNode(Node* node) {
__forceinline NodeRef encodeNode(Node* node) {
return NodeRef((size_t) node);
}
/*! Encodes a leaf */
__forceinline NodeRef encodeLeaf(void* tri, size_t num) {
assert(!((size_t)tri & align_mask));
assert(!((size_t)tri & align_mask));
return NodeRef((size_t)tri | (1+min(num,(size_t)maxLeafBlocks)));
}
#endif
public:
/*! calculates the amount of bytes allocated */
size_t bytesAllocated() {
return alloc2.getAllocatedBytes();
@@ -305,7 +305,7 @@ namespace embree
for (size_t i=0;i<BVH8::N;i++) o << n.children[i] << " ";
o << std::endl;
return o;
}
}
#endif
}
@@ -0,0 +1,25 @@
// ======================================================================== //
// Copyright 2009-2015 Intel Corporation //
// //
// 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 //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// 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 //
// limitations under the License. //
// ======================================================================== //
// We cannot compile the same file containing lambda functions for two
// ISAs, as a lambda name mangling bug of ICC under Windows causes
// symbols to conflict.
//created by Per Ganestam
#include "bvh8_builder_bonsai.cpp"
+285
View File
@@ -0,0 +1,285 @@
// ======================================================================== //
// Copyright 2009-2015 Intel Corporation //
// //
// 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 //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// 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 //
// limitations under the License. //
// ======================================================================== //
#include "bvh8.h"
#include "bvh8_statistics.h"
//#include "common/profile.h"
#include "../builders/primrefgen.h"
#include "../builders/presplit.h"
#include "../builders/bvh_builder_bonsai.h"
#include "../geometry/triangle4.h"
#include "../geometry/triangle8.h"
#define PROFILE 0
namespace embree
{
namespace isa
{
typedef FastAllocator::ThreadLocal2 Allocator;
struct CreateBVH8Alloc
{
__forceinline CreateBVH8Alloc (BVH8* bvh) : bvh(bvh) {}
__forceinline Allocator* operator() () const { return bvh->alloc2.threadLocal2(); }
BVH8* bvh;
};
struct CreateBVH8Node
{
__forceinline CreateBVH8Node (BVH8* bvh) : bvh(bvh) {}
__forceinline int operator() (const isa::BVHBuilderBonsai::BuildRecord& current, BVHBuilderBonsai::BuildRecord* children, const size_t N, Allocator* alloc)
{
BVH8::Node* node = nullptr;
node = (BVH8::Node*) alloc->alloc0.malloc(sizeof(BVH8::Node), 1 << BVH8::alignment);
node->clear();
for (size_t i=0; i<N; i++) {
node->set(i,children[i].pinfo.geomBounds);
children[i].parent = (size_t*) &node->child(i);
}
*current.parent = bvh->encodeNode(node);
return 0;
}
__forceinline int operator() (const isa::BVHBuilderBonsai::BuildRecord& current, BVHBuilderBonsai::BuildRecord* children, const size_t N, Allocator* alloc, int& underFilledNodes)
{
BVH8::Node* node = nullptr;
node = (BVH8::Node*) alloc->alloc0.malloc(sizeof(BVH8::Node), 1 << BVH8::alignment);
node->clear();
for (size_t i=0; i<N; i++) {
node->set(i,children[i].pinfo.geomBounds);
node->child(i) = BVH8::NodeRef(*children[i].parent);
}
*current.parent = bvh->encodeNode(node);
return 0;
}
BVH8* bvh;
};
template<typename Primitive>
struct CreateBVH8Leaf
{
__forceinline CreateBVH8Leaf (BVH8* bvh, PrimRef* prims) : bvh(bvh), prims(prims) {}
__forceinline int operator() (const BVHBuilderBonsai::BuildRecord& current, Allocator* alloc)
{
size_t items = Primitive::blocks(current.prims.size());
size_t start = current.prims.begin();
Primitive* accel = (Primitive*) alloc->alloc1.malloc(items*sizeof(Primitive), 1 << BVH8::alignment);
BVH8::NodeRef node = bvh->encodeLeaf((char*)accel,items);
for (size_t i=0; i<items; i++) {
accel[i].fill(prims,start,current.prims.end(),bvh->scene,false);
}
*current.parent = node;
return 1;
}
__forceinline int operator() (const BVHBuilderBonsai::BuildRecord& current, PrimRef* gatheredRefs, Allocator* alloc)
{
size_t items = Primitive::blocks(current.prims.size());
size_t start = 0; //< gathered refs start at 0 instead of current.prims.begin();
Primitive* accel = (Primitive*) alloc->alloc1.malloc(items*sizeof(Primitive), 1 << BVH8::alignment);
BVH8::NodeRef node = bvh->encodeLeaf((char*)accel,items);
for (size_t i=0; i<items; i++) {
accel[i].fill(gatheredRefs,start,current.prims.size(),bvh->scene,false); //< last ref is prims.size() instead of prims.end()
}
*current.parent = node;
return 1;
}
BVH8* bvh;
PrimRef* prims;
};
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
template<typename Mesh, typename Primitive>
struct BVH8BuilderBonsai : public Builder
{
BVH8* bvh;
Scene* scene;
Mesh* mesh;
mvector<PrimRef> prims;
const size_t sahBlockSize;
const float intCost;
const size_t minLeafSize;
const size_t maxLeafSize;
const float presplitFactor;
BVH8BuilderBonsai (BVH8* bvh, Scene* scene, const size_t leafBlockSize, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
: bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,leafBlockSize*BVH8::maxLeafBlocks)),
presplitFactor((mode & MODE_HIGH_QUALITY) ? 1.5f : 1.0f) {}
BVH8BuilderBonsai (BVH8* bvh, Mesh* mesh, const size_t leafBlockSize, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
: bvh(bvh), scene(nullptr), mesh(mesh), prims(scene->device), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,leafBlockSize*BVH8::maxLeafBlocks)),
presplitFactor((mode & MODE_HIGH_QUALITY) ? 1.5f : 1.0f) {}
void build(size_t, size_t)
{
/* skip build for empty scene */
const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives<Mesh,1>();
if (numPrimitives == 0) {
prims.resize(numPrimitives);
bvh->set(BVH8::emptyNode,empty,0);
return;
}
const size_t numSplitPrimitives = max(numPrimitives,size_t(presplitFactor*numPrimitives));
/* verbose mode */
if (bvh->device->verbosity(1) && mesh == nullptr)
std::cout << "building BVH8<" << bvh->primTy.name << "> with " << TOSTRING(isa) "::BVH8BuilderBonsai " << (presplitFactor != 1.0f ? "presplit" : "") << " ... " << std::flush;
bool splitTriangles = false; // not currently used
double t0 = 0.0f, dt = 0.0f;
#if PROFILE
profile(2,20,numPrimitives,[&] (ProfileTimer& timer)
{
#endif
if ((bvh->device->benchmark || bvh->device->verbosity(1)) && mesh == nullptr) t0 = getSeconds();
auto progress = [&] (size_t dn) { bvh->scene->progressMonitor(dn); };
auto virtualprogress = BuildProgressMonitorFromClosure(progress);
bvh->alloc2.init_estimate(numSplitPrimitives*sizeof(PrimRef));
if (splitTriangles)
prims.resize(numSplitPrimitives*4);
else
prims.resize(numSplitPrimitives);
PrimInfo pinfo = mesh ? createPrimRefArray<Mesh>(mesh,prims,virtualprogress) : createPrimRefArray<Mesh,1>(scene,prims,virtualprogress);
if (presplitFactor > 1.0f)
pinfo = presplit<Mesh>(scene, pinfo, prims);
BVH8::NodeRef root;
BVHBuilderBonsai::build<BVH8::NodeRef>
(root,CreateBVH8Alloc(bvh),CreateBVH8Node(bvh),CreateBVH8Leaf<Primitive>(bvh,prims.data()), progress,
prims.data(),pinfo,BVH8::N,BVH8::maxBuildDepthLeaf,sahBlockSize,minLeafSize,maxLeafSize,BVH8::travCost,intCost, bvh->scene, splitTriangles, pinfo.size());
bvh->set(root,pinfo.geomBounds,pinfo.size());
//bvh->layoutLargeNodes(numSplitPrimitives*0.005f);
if ((bvh->device->benchmark || bvh->device->verbosity(1)) && mesh == nullptr) dt = getSeconds()-t0;
#if PROFILE
dt = timer.avg();
});
#endif
// exit(0);
/* clear temporary data for static geometry */
bool staticGeom = mesh ? mesh->isStatic() : scene->isStatic();
if (staticGeom) prims.clear();
bvh->alloc2.cleanup();
/* verbose mode */
if (bvh->device->verbosity(1) && mesh == nullptr)
std::cout << "[DONE] " << 1000.0f*dt << "ms (" << numPrimitives/dt*1E-6 << " Mtris/s)" << std::endl;
if (bvh->device->verbosity(2) && mesh == nullptr)
bvh->printStatistics();
/* benchmark mode */
if (bvh->device->benchmark) {
BVH8Statistics stat(bvh);
std::cout << "BENCHMARK_BUILD " << dt << " " << double(numPrimitives)/dt << " " << stat.sah() << " " << stat.bytesUsed() << std::endl;
}
}
void clear() {
prims.clear();
}
};
/* entry functions for the scene builder */
Builder* BVH8Triangle4SceneBuilderBonsai (void* bvh, Scene* scene, size_t mode) { return new BVH8BuilderBonsai<TriangleMesh,Triangle4>((BVH8*)bvh,scene,4,4,1.0f,4,inf,mode); }
Builder* BVH8Triangle8SceneBuilderBonsai (void* bvh, Scene* scene, size_t mode) { return new BVH8BuilderBonsai<TriangleMesh,Triangle8>((BVH8*)bvh,scene,8,4,1.0f,8,inf,mode); }
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
#if 0
struct CreateListBVH8Node // FIXME: merge with above class
{
__forceinline CreateListBVH8Node (BVH8* bvh) : bvh(bvh) {}
__forceinline BVH8::Node* operator() (const isa::BVHBuilderBinnedSpatialSAH::BuildRecord& current, BVHBuilderBinnedSpatialSAH::BuildRecord* children, const size_t N, Allocator* alloc)
{
BVH8::Node* node = (BVH8::Node*) alloc->alloc0.malloc(sizeof(BVH8::Node), 1 << BVH8::alignment); node->clear();
for (size_t i=0; i<N; i++) {
node->set(i,children[i].pinfo.geomBounds);
children[i].parent = (size_t*) &node->child(i);
}
*current.parent = bvh->encodeNode(node);
return node;
}
BVH8* bvh;
};
template<typename Primitive>
struct CreateBVH8ListLeaf
{
__forceinline CreateBVH8ListLeaf (BVH8* bvh) : bvh(bvh) {}
__forceinline size_t operator() (BVHBuilderBinnedSpatialSAH::BuildRecord& current, Allocator* alloc) // FIXME: why are prims passed here but not for createNode
{
size_t n = current.pinfo.size();
size_t N = Primitive::blocks(n);
Primitive* leaf = (Primitive*) alloc->alloc1.malloc(N*sizeof(Primitive), 1 << BVH8::alignment);
BVH8::NodeRef node = bvh->encodeLeaf((char*)leaf,N);
/*PrimRefList::block_iterator_unsafe iter1(current.prims);
while (iter1) {
const int i = iter1->lower.a;
iter1->lower.a = geomIDprimID[i].first;
iter1->upper.a = geomIDprimID[i].second;
iter1++;
}*/
PrimRefList::block_iterator_unsafe iter1(current.prims);
while (iter1) {
iter1->lower.a &= 0x00FFFFFF; // FIXME: hack
iter1++;
}
/* insert all triangles */
PrimRefList::block_iterator_unsafe iter(current.prims);
for (size_t i=0; i<N; i++) leaf[i].fill(iter,bvh->scene,false);
assert(!iter);
/* free all primitive blocks */
while (PrimRefList::item* block = current.prims.take())
delete block;
*current.parent = node;
return n;
}
BVH8* bvh;
};
#endif
}
}
+37 -37
View File
@@ -26,7 +26,7 @@
#include "../geometry/triangle8v.h"
#include "../geometry/trianglepairs8.h"
#define PROFILE 0
#define PROFILE 1
namespace embree
{
@@ -45,13 +45,13 @@ namespace embree
struct CreateBVH8Node
{
__forceinline CreateBVH8Node (BVH8* bvh) : bvh(bvh) {}
__forceinline int operator() (const isa::BVHBuilderBinnedSAH::BuildRecord& current, BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, Allocator* alloc)
__forceinline int operator() (const isa::BVHBuilderBinnedSAH::BuildRecord& current, BVHBuilderBinnedSAH::BuildRecord* children, const size_t N, Allocator* alloc)
{
BVH8::Node* node = nullptr;
//if (current.pinfo.size() > 4096) node = (BVH8::Node*) bvh->alloc2.malloc(sizeof(BVH8::Node),sizeof(BVH8::Node));
//else
node = (BVH8::Node*) alloc->alloc0.malloc(sizeof(BVH8::Node), 1 << BVH8::alignment);
node = (BVH8::Node*) alloc->alloc0.malloc(sizeof(BVH8::Node), 1 << BVH8::alignment);
node->clear();
for (size_t i=0; i<N; i++) {
node->set(i,children[i].pinfo.geomBounds);
@@ -68,7 +68,7 @@ namespace embree
struct CreateBVH8Leaf
{
__forceinline CreateBVH8Leaf (BVH8* bvh, PrimRef* prims) : bvh(bvh), prims(prims) {}
__forceinline int operator() (const BVHBuilderBinnedSAH::BuildRecord& current, Allocator* alloc)
{
size_t items = Primitive::blocks(current.prims.size());
@@ -85,8 +85,8 @@ namespace embree
BVH8* bvh;
PrimRef* prims;
};
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
@@ -106,13 +106,13 @@ namespace embree
BVH8BuilderSAH (BVH8* bvh, Scene* scene, const size_t leafBlockSize, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
: bvh(bvh), scene(scene), mesh(nullptr), prims(scene->device), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,leafBlockSize*BVH8::maxLeafBlocks)),
presplitFactor((mode & MODE_HIGH_QUALITY) ? 1.5f : 1.0f) {}
presplitFactor((mode & MODE_HIGH_QUALITY) ? 2.5f : 1.0f) {}
BVH8BuilderSAH (BVH8* bvh, Mesh* mesh, const size_t leafBlockSize, const size_t sahBlockSize, const float intCost, const size_t minLeafSize, const size_t maxLeafSize, const size_t mode)
: bvh(bvh), scene(nullptr), mesh(mesh), prims(bvh->device), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,leafBlockSize*BVH8::maxLeafBlocks)),
presplitFactor((mode & MODE_HIGH_QUALITY) ? 1.5f : 1.0f) {}
presplitFactor((mode & MODE_HIGH_QUALITY) ? 2.5f : 1.0f) {}
void build(size_t, size_t)
void build(size_t, size_t)
{
/* skip build for empty scene */
const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives<Mesh,1>();
@@ -122,7 +122,7 @@ namespace embree
return;
}
const size_t numSplitPrimitives = max(numPrimitives,size_t(presplitFactor*numPrimitives));
/* verbose mode */
if (bvh->device->verbosity(1) && mesh == nullptr)
std::cout << "building BVH8<" << bvh->primTy.name << "> with " << TOSTRING(isa) "::BVH8BuilderSAH " << (presplitFactor != 1.0f ? "presplit" : "") << " ... " << std::flush;
@@ -132,18 +132,18 @@ namespace embree
profile(2,20,numPrimitives,[&] (ProfileTimer& timer)
{
#endif
if ((bvh->device->benchmark || bvh->device->verbosity(1)) && mesh == nullptr) t0 = getSeconds();
auto progress = [&] (size_t dn) { bvh->scene->progressMonitor(dn); };
auto virtualprogress = BuildProgressMonitorFromClosure(progress);
bvh->alloc2.init_estimate(numSplitPrimitives*sizeof(PrimRef));
prims.resize(numSplitPrimitives);
PrimInfo pinfo = mesh ? createPrimRefArray<Mesh>(mesh,prims,virtualprogress) : createPrimRefArray<Mesh,1>(scene,prims,virtualprogress);
if (presplitFactor > 1.0f)
pinfo = presplit<Mesh>(scene, pinfo, prims);
BVH8::NodeRef root;
BVH8::NodeRef root;
BVHBuilderBinnedSAH::build<BVH8::NodeRef>
(root,CreateBVH8Alloc(bvh),CreateBVH8Node(bvh),CreateBVH8Leaf<Primitive>(bvh,prims.data()), progress,
prims.data(),pinfo,BVH8::N,BVH8::maxBuildDepthLeaf,sahBlockSize,minLeafSize,maxLeafSize,BVH8::travCost,intCost);
@@ -155,8 +155,8 @@ namespace embree
#if PROFILE
dt = timer.avg();
});
#endif
});
#endif
/* clear temporary data for static geometry */
bool staticGeom = mesh ? mesh->isStatic() : scene->isStatic();
@@ -193,7 +193,7 @@ namespace embree
Builder* BVH8TrianglePairs8SceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVH8BuilderSAH<TriangleMesh,Triangle8>((BVH8*)bvh,scene,8,4,1.0f,8,inf,mode); }
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
/************************************************************************************/
@@ -201,8 +201,8 @@ namespace embree
struct CreateListBVH8Node // FIXME: merge with above class
{
__forceinline CreateListBVH8Node (BVH8* bvh) : bvh(bvh) {}
__forceinline BVH8::Node* operator() (const isa::BVHBuilderBinnedSpatialSAH::BuildRecord& current, BVHBuilderBinnedSpatialSAH::BuildRecord* children, const size_t N, Allocator* alloc)
__forceinline BVH8::Node* operator() (const isa::BVHBuilderBinnedSpatialSAH::BuildRecord& current, BVHBuilderBinnedSpatialSAH::BuildRecord* children, const size_t N, Allocator* alloc)
{
BVH8::Node* node = (BVH8::Node*) alloc->alloc0.malloc(sizeof(BVH8::Node), 1 << BVH8::alignment); node->clear();
for (size_t i=0; i<N; i++) {
@@ -220,7 +220,7 @@ namespace embree
struct CreateBVH8ListLeaf
{
__forceinline CreateBVH8ListLeaf (BVH8* bvh) : bvh(bvh) {}
__forceinline size_t operator() (BVHBuilderBinnedSpatialSAH::BuildRecord& current, Allocator* alloc) // FIXME: why are prims passed here but not for createNode
{
size_t n = current.pinfo.size();
@@ -245,7 +245,7 @@ namespace embree
PrimRefList::block_iterator_unsafe iter(current.prims);
for (size_t i=0; i<N; i++) leaf[i].fill(iter,bvh->scene,false);
assert(!iter);
/* free all primitive blocks */
while (PrimRefList::item* block = current.prims.take())
delete block;
@@ -277,7 +277,7 @@ namespace embree
: bvh(bvh), scene(nullptr), mesh(mesh), sahBlockSize(sahBlockSize), intCost(intCost), minLeafSize(minLeafSize), maxLeafSize(min(maxLeafSize,leafBlockSize*BVH8::maxLeafBlocks)),
presplitFactor((mode & MODE_HIGH_QUALITY) ? 1.5f : 1.0f) {}
void build(size_t, size_t)
void build(size_t, size_t)
{
/* skip build for empty scene */
const size_t numPrimitives = mesh ? mesh->size() : scene->getNumPrimitives<Mesh,1>();
@@ -287,20 +287,20 @@ namespace embree
return;
}
const size_t numSplitPrimitives = max(numPrimitives,size_t(presplitFactor*numPrimitives));
/* reduction function */
auto rotate = [&] (BVH8::Node* node, const size_t* counts, const size_t N) -> size_t
{
size_t n = 0;
#if ROTATE_TREE
assert(N <= BVH8::N);
for (size_t i=0; i<N; i++)
for (size_t i=0; i<N; i++)
n += counts[i];
if (n >= 4096) {
for (size_t i=0; i<N; i++) {
if (counts[i] < 4096) {
for (int j=0; j<ROTATE_TREE; j++)
BVH8Rotate::rotate(bvh,node->child(i));
for (int j=0; j<ROTATE_TREE; j++)
BVH8Rotate::rotate(bvh,node->child(i));
node->child(i).setBarrier();
}
}
@@ -318,9 +318,9 @@ namespace embree
profile(2,20,numPrimitives,[&] (ProfileTimer& timer)
{
#endif
if ((bvh->device->benchmark || bvh->device->verbosity(1)) && mesh == nullptr) t0 = getSeconds();
auto progress = [&] (size_t dn) { bvh->scene->progressMonitor(dn); };
auto virtualprogress = BuildProgressMonitorFromClosure(progress);
@@ -340,7 +340,7 @@ namespace embree
{
double A = 0.0f;
while (PrimRefList::item* block = iter.next()) {
for (size_t i=0; i<block->size(); i++)
for (size_t i=0; i<block->size(); i++)
A += area(block->at(i).bounds());
//A += heuristic(block->at(i));
}
@@ -372,7 +372,7 @@ namespace embree
(root,CreateBVH8Alloc(bvh),size_t(0),CreateListBVH8Node(bvh),rotate,CreateBVH8ListLeaf<Primitive>(bvh),
[&] (const PrimRef& prim, int dim, float pos, PrimRef& left_o, PrimRef& right_o)
{
TriangleMesh* mesh = (TriangleMesh*) scene->get(prim.geomID() & 0x00FFFFFF);
TriangleMesh* mesh = (TriangleMesh*) scene->get(prim.geomID() & 0x00FFFFFF);
TriangleMesh::Triangle tri = mesh->triangle(prim.primID());
const Vec3fa v0 = mesh->vertex(tri.v[0]);
const Vec3fa v1 = mesh->vertex(tri.v[1]);
@@ -382,21 +382,21 @@ namespace embree
progress,
prims,pinfo,BVH8::N,BVH8::maxBuildDepthLeaf,sahBlockSize,minLeafSize,maxLeafSize,BVH8::travCost,intCost);
bvh->set(root,pinfo.geomBounds,pinfo.size());
#if ROTATE_TREE
for (int i=0; i<ROTATE_TREE; i++)
for (int i=0; i<ROTATE_TREE; i++)
BVH8Rotate::rotate(bvh,bvh->root);
bvh->clearBarrier(bvh->root);
#endif
bvh->layoutLargeNodes(pinfo.size()*0.005f);
if ((bvh->device->benchmark || bvh->device->verbosity(1)) && mesh == nullptr) dt = getSeconds()-t0;
#if PROFILE
dt = timer.avg();
});
#endif
});
#endif
/* clear temporary data for static geometry */
bool staticGeom = mesh ? mesh->isStatic() : scene->isStatic();