mirror of
https://github.com/blender/blender
synced 2026-10-25 03:07:01 +03:00
Metal-RT backend required a bit of not-so-obvious tricks: - The LocalIntersection pointer can not be stored in the payload, so the utility function has been templated and the Metal-RT payload has been modified to match the actual LocalIntersection better. - Explicit address space is required, and the utility function which calculates the index to store the intersection at is used from multiple code-paths, some of them require LCG state to be private, others require it to be ray_data. Address space can not be a part of a template type, so a temporary copy of the lcg_state is done in the intersection function. Since the utility is foeceinline the hope is that the compiler eliminates it. - Using bit-packing for the payload fields lead to some unexpected test failures: non-deterministic render results, as if something was not properly initialized. It is unclear why it started to happen now. Using regular int fields avoids sign-comparison warning and solves the test failures. - There was actually one potentially uninitialized member in the payload: has_lcg_state was never set to false. Even with all this extra complexity it does not seem that there is negative performance impact measured on Apple M4 Max. Pull Request: https://projects.blender.org/blender/blender/pulls/151540
64 lines
2 KiB
C++
64 lines
2 KiB
C++
/* SPDX-FileCopyrightText: 2025 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
/* Common utilities for various geometry type intersections. */
|
|
|
|
#pragma once
|
|
|
|
#include "kernel/globals.h"
|
|
#include "kernel/sample/lcg.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* For an intersection with the given distance isect_t from the ray origin, increase the number
|
|
* of hits (when needed) and return an index within local_isect->hits where the intersection is to
|
|
* be stored. If the return value -1, then the intersection is to be ignored (nothing is to be
|
|
* written to the local_isect->hits, and the intersection test function is to return false.
|
|
*
|
|
* The LocalIntersection is a templated type, allowing different types that implement similar data
|
|
* layout to be passed here. This is needed for the MetalRT, where it is not possible to access the
|
|
* pointer to actual LocalIntersection from the git function. */
|
|
#ifdef __BVH_LOCAL__
|
|
template<class LocalIntersection>
|
|
ccl_device_forceinline int local_intersect_get_record_index(
|
|
ccl_private LocalIntersection *local_isect,
|
|
const float isect_t,
|
|
ccl_private uint *lcg_state,
|
|
const int max_hits)
|
|
{
|
|
if (lcg_state) {
|
|
/* Record up to max_hits intersections. */
|
|
for (int i = min(max_hits, int(local_isect->num_hits)) - 1; i >= 0; --i) {
|
|
if (local_isect->hits[i].t == isect_t) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
local_isect->num_hits++;
|
|
|
|
int hit;
|
|
if (local_isect->num_hits <= max_hits) {
|
|
hit = local_isect->num_hits - 1;
|
|
}
|
|
else {
|
|
/* Reservoir sampling: if we are at the maximum number of hits, randomly replace element or
|
|
* skip it. */
|
|
hit = lcg_step_uint(lcg_state) % local_isect->num_hits;
|
|
if (hit >= max_hits) {
|
|
return -1;
|
|
}
|
|
}
|
|
return hit;
|
|
}
|
|
|
|
/* Record closest intersection only. */
|
|
if (local_isect->num_hits && isect_t > local_isect->hits[0].t) {
|
|
return -1;
|
|
}
|
|
local_isect->num_hits = 1;
|
|
return 0;
|
|
}
|
|
#endif /* __BVH_LOCAL__ */
|
|
|
|
CCL_NAMESPACE_END
|