Blender V4.3
sort.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
2 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Adapted code from NVIDIA Corporation. */
7
8#include "bvh/sort.h"
9
10#include "bvh/build.h"
11
12#include "util/algorithm.h"
13#include "util/task.h"
14
16
17static const int BVH_SORT_THRESHOLD = 4096;
18
20 public:
21 int dim;
24
31
38
39 /* Compare two references.
40 *
41 * Returns value is similar to return value of `strcmp()`.
42 */
43 __forceinline int compare(const BVHReference &ra, const BVHReference &rb) const
44 {
45 BoundBox ra_bounds = get_prim_bounds(ra), rb_bounds = get_prim_bounds(rb);
46 float ca = ra_bounds.min[dim] + ra_bounds.max[dim];
47 float cb = rb_bounds.min[dim] + rb_bounds.max[dim];
48
49 if (ca < cb) {
50 return -1;
51 }
52 else if (ca > cb) {
53 return 1;
54 }
55 else if (ra.prim_object() < rb.prim_object()) {
56 return -1;
57 }
58 else if (ra.prim_object() > rb.prim_object()) {
59 return 1;
60 }
61 else if (ra.prim_index() < rb.prim_index()) {
62 return -1;
63 }
64 else if (ra.prim_index() > rb.prim_index()) {
65 return 1;
66 }
67 else if (ra.prim_type() < rb.prim_type()) {
68 return -1;
69 }
70 else if (ra.prim_type() > rb.prim_type()) {
71 return 1;
72 }
73
74 return 0;
75 }
76
77 bool operator()(const BVHReference &ra, const BVHReference &rb)
78 {
79 return (compare(ra, rb) < 0);
80 }
81};
82
84 BVHReference *data,
85 const int job_start,
86 const int job_end,
87 const BVHReferenceCompare &compare);
88
89/* Multi-threaded reference sort. */
91 BVHReference *data,
92 const int job_start,
93 const int job_end,
94 const BVHReferenceCompare &compare)
95{
96 int start = job_start, end = job_end;
97 bool have_work = (start < end);
98 while (have_work) {
99 const int count = job_end - job_start;
101 /* Number of reference low enough, faster to finish the job
102 * in one thread rather than to spawn more threads.
103 */
104 sort(data + job_start, data + job_end + 1, compare);
105 break;
106 }
107 /* Single QSort step.
108 * Use median-of-three method for the pivot point.
109 */
110 int left = start, right = end;
111 int center = (left + right) >> 1;
112 if (compare.compare(data[left], data[center]) > 0) {
113 swap(data[left], data[center]);
114 }
115 if (compare.compare(data[left], data[right]) > 0) {
116 swap(data[left], data[right]);
117 }
118 if (compare.compare(data[center], data[right]) > 0) {
119 swap(data[center], data[right]);
120 }
121 swap(data[center], data[right - 1]);
122 BVHReference median = data[right - 1];
123 do {
124 while (compare.compare(data[left], median) < 0) {
125 ++left;
126 }
127 while (compare.compare(data[right], median) > 0) {
128 --right;
129 }
130 if (left <= right) {
131 swap(data[left], data[right]);
132 ++left;
133 --right;
134 }
135 } while (left <= right);
136 /* We only create one new task here to reduce downside effects of
137 * latency in TaskScheduler.
138 * So generally current thread keeps working on the left part of the
139 * array, and we create new task for the right side.
140 * However, if there's nothing to be done in the left side of the array
141 * we don't create any tasks and make it so current thread works on the
142 * right side.
143 */
144 have_work = false;
145 if (left < end) {
146 if (start < right) {
148 function_bind(bvh_reference_sort_threaded, task_pool, data, left, end, compare));
149 }
150 else {
151 start = left;
152 have_work = true;
153 }
154 }
155 if (start < right) {
156 end = right;
157 have_work = true;
158 }
159 }
160}
161
162void bvh_reference_sort(int start,
163 int end,
164 BVHReference *data,
165 int dim,
166 const BVHUnaligned *unaligned_heuristic,
167 const Transform *aligned_space)
168{
169 const int count = end - start;
170 BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space);
172 /* It is important to not use any mutex if array is small enough,
173 * otherwise we end up in situation when we're going to sleep far
174 * too often.
175 */
176 sort(data + start, data + end, compare);
177 }
178 else {
180 bvh_reference_sort_threaded(&task_pool, data, start, end - 1, compare);
182 }
183}
184
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
Definition btDbvt.cpp:418
__forceinline int prim_type() const
Definition params.h:217
__forceinline int prim_object() const
Definition params.h:213
__forceinline const BoundBox & bounds() const
Definition params.h:205
__forceinline int prim_index() const
Definition params.h:209
BoundBox compute_aligned_prim_boundbox(const BVHReference &prim, const Transform &aligned_space) const
Definition unaligned.cpp:76
#define function_bind
#define CCL_NAMESPACE_END
#define NULL
#define __forceinline
TaskPool * task_pool
int count
static int left
#define swap(a, b)
Definition sort.c:55
void bvh_reference_sort(int start, int end, BVHReference *data, int dim, const BVHUnaligned *unaligned_heuristic, const Transform *aligned_space)
Definition sort.cpp:162
static CCL_NAMESPACE_BEGIN const int BVH_SORT_THRESHOLD
Definition sort.cpp:17
static void bvh_reference_sort_threaded(TaskPool *task_pool, BVHReference *data, const int job_start, const int job_end, const BVHReferenceCompare &compare)
Definition sort.cpp:90
const Transform * aligned_space
Definition sort.cpp:23
const BVHUnaligned * unaligned_heuristic
Definition sort.cpp:22
__forceinline BoundBox get_prim_bounds(const BVHReference &prim) const
Definition sort.cpp:32
__forceinline int compare(const BVHReference &ra, const BVHReference &rb) const
Definition sort.cpp:43
bool operator()(const BVHReference &ra, const BVHReference &rb)
Definition sort.cpp:77
BVHReferenceCompare(int dim, const BVHUnaligned *unaligned_heuristic, const Transform *aligned_space)
Definition sort.cpp:25
float3 max
Definition boundbox.h:21
float3 min
Definition boundbox.h:21
void push(TaskRunFunction &&task)
Definition task.cpp:22
void wait_work(Summary *stats=NULL)
Definition task.cpp:28