Add Chromium-only Blender WebEngine parity work
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(INC
|
||||
../../..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_METAL
|
||||
kernel.metal
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_METAL_HEADERS
|
||||
bvh.h
|
||||
compat.h
|
||||
context_begin.h
|
||||
context_end.h
|
||||
function_constants.h
|
||||
globals.h
|
||||
)
|
||||
|
||||
|
||||
set(LIB
|
||||
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_DEVICE_METAL)
|
||||
add_library(cycles_kernel_metal INTERFACE)
|
||||
target_sources(cycles_kernel_metal INTERFACE
|
||||
${SRC_KERNEL_DEVICE_METAL}
|
||||
${SRC_KERNEL_DEVICE_METAL_HEADERS}
|
||||
)
|
||||
cycles_set_solution_folder(cycles_kernel_metal)
|
||||
|
||||
source_group("device\\metal" FILES ${SRC_KERNEL_DEVICE_METAL} ${SRC_KERNEL_DEVICE_METAL_HEADERS})
|
||||
|
||||
add_dependencies(cycles_kernel cycles_kernel_metal)
|
||||
endif()
|
||||
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_METAL}" ${CYCLES_INSTALL_PATH}/source/kernel/device/metal)
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_METAL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/metal)
|
||||
573
blender-5.2.0/intern/cycles/kernel/device/metal/bvh.h
Normal file
573
blender-5.2.0/intern/cycles/kernel/device/metal/bvh.h
Normal file
@@ -0,0 +1,573 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* MetalRT implementation of ray-scene intersection. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/bvh/types.h"
|
||||
#include "kernel/bvh/util.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Payload types.
|
||||
*
|
||||
* Best practice is to minimize the size of MetalRT payloads to avoid heavy spilling during
|
||||
* intersection tests.
|
||||
*/
|
||||
|
||||
struct MetalRTIntersectionPayload {
|
||||
int self_prim;
|
||||
int self_object;
|
||||
uint visibility;
|
||||
};
|
||||
|
||||
struct MetalRTIntersectionLocalPayload_single_hit {
|
||||
int self_prim;
|
||||
#if defined(__METALRT_MOTION__)
|
||||
int self_object;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct MetalRTLocalHit {
|
||||
uint prim;
|
||||
float t, u, v;
|
||||
};
|
||||
|
||||
/* Payload for the local intersection queries.
|
||||
* It embeds a subset of storage that is typically found in the LocalIntersection. This is because
|
||||
* it is not possible to store a pointer to the actual LocalIntersection in the payload. So some
|
||||
* data is duplicated into the payload and then copied back to the LocalIntersection. */
|
||||
struct MetalRTIntersectionLocalPayload {
|
||||
int self_prim;
|
||||
#if defined(__METALRT_MOTION__)
|
||||
int self_object;
|
||||
#endif
|
||||
|
||||
uint lcg_state;
|
||||
MetalRTLocalHit hits[LOCAL_MAX_HITS];
|
||||
int max_hits;
|
||||
int num_hits;
|
||||
bool has_lcg_state;
|
||||
};
|
||||
|
||||
struct MetalRTIntersectionShadowPayload {
|
||||
RaySelfPrimitives self;
|
||||
uint visibility;
|
||||
};
|
||||
|
||||
#ifdef __HAIR__
|
||||
ccl_device_forceinline bool curve_ribbon_accept(KernelGlobals kg,
|
||||
const float u,
|
||||
float t,
|
||||
const ccl_private Ray *ray,
|
||||
const int object,
|
||||
const int prim,
|
||||
const int type)
|
||||
{
|
||||
KernelCurve kcurve = kernel_data_fetch(curves, prim);
|
||||
|
||||
int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
|
||||
int k1 = k0 + 1;
|
||||
int ka = max(k0 - 1, kcurve.first_key);
|
||||
int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
|
||||
|
||||
/* We can ignore motion blur here because we don't need the positions, and it doesn't affect the
|
||||
* radius. */
|
||||
const int position_offset = kernel_data_fetch(objects, object).position_offset;
|
||||
float radius[4];
|
||||
radius[0] = kernel_data_fetch(curve_keys, position_offset + ka).w;
|
||||
radius[1] = kernel_data_fetch(curve_keys, position_offset + k0).w;
|
||||
radius[2] = kernel_data_fetch(curve_keys, position_offset + k1).w;
|
||||
radius[3] = kernel_data_fetch(curve_keys, position_offset + kb).w;
|
||||
const float r = metal::catmull_rom(u, radius[0], radius[1], radius[2], radius[3]);
|
||||
|
||||
/* MPJ TODO: Can we ignore motion and/or object transforms here? Depends on scaling? */
|
||||
float3 ray_P = ray->P;
|
||||
float3 ray_D = ray->D;
|
||||
if (!(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
float3 idir;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
bvh_instance_motion_push(nullptr, object, ray, &ray_P, &ray_D, &idir);
|
||||
# else
|
||||
bvh_instance_push(nullptr, object, ray, &ray_P, &ray_D, &idir);
|
||||
# endif
|
||||
}
|
||||
|
||||
/* ignore self intersections */
|
||||
const float avoidance_factor = 2.0f;
|
||||
return t * len(ray_D) > avoidance_factor * r;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float curve_ribbon_v(KernelGlobals kg,
|
||||
const float u,
|
||||
float t,
|
||||
const ccl_private Ray *ray,
|
||||
const int object,
|
||||
const int prim,
|
||||
const int type)
|
||||
{
|
||||
# if defined(__METALRT_MOTION__)
|
||||
float time = ray->time;
|
||||
# else
|
||||
float time = 0.0f;
|
||||
# endif
|
||||
|
||||
const bool is_motion = (type & PRIMITIVE_MOTION);
|
||||
|
||||
KernelCurve kcurve = kernel_data_fetch(curves, prim);
|
||||
|
||||
int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
|
||||
int k1 = k0 + 1;
|
||||
int ka = max(k0 - 1, kcurve.first_key);
|
||||
int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
|
||||
|
||||
float4 curve[4];
|
||||
if (!is_motion) {
|
||||
const int position_offset = kernel_data_fetch(objects, object).position_offset;
|
||||
curve[0] = kernel_data_fetch(curve_keys, position_offset + ka);
|
||||
curve[1] = kernel_data_fetch(curve_keys, position_offset + k0);
|
||||
curve[2] = kernel_data_fetch(curve_keys, position_offset + k1);
|
||||
curve[3] = kernel_data_fetch(curve_keys, position_offset + kb);
|
||||
}
|
||||
else {
|
||||
motion_curve_keys(kg, object, time, ka, k0, k1, kb, curve);
|
||||
}
|
||||
|
||||
float3 ray_P = ray->P;
|
||||
float3 ray_D = ray->D;
|
||||
if (!(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
float3 idir;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
bvh_instance_motion_push(nullptr, object, ray, &ray_P, &ray_D, &idir);
|
||||
# else
|
||||
bvh_instance_push(nullptr, object, ray, &ray_P, &ray_D, &idir);
|
||||
# endif
|
||||
}
|
||||
|
||||
const float4 P_curve4 = metal::catmull_rom(u, curve[0], curve[1], curve[2], curve[3]);
|
||||
const float r_curve = P_curve4.w;
|
||||
|
||||
float3 P = ray_P + ray_D * t;
|
||||
const float3 P_curve = make_float3(P_curve4);
|
||||
|
||||
const float4 dPdu4 = metal::catmull_rom_derivative(u, curve[0], curve[1], curve[2], curve[3]);
|
||||
const float3 dPdu = make_float3(dPdu4);
|
||||
|
||||
const float3 tangent = normalize(dPdu);
|
||||
const float3 bitangent = normalize(cross(tangent, -ray_D));
|
||||
|
||||
float v = dot(P - P_curve, bitangent) / r_curve;
|
||||
return clamp(v, -1.0, 1.0f);
|
||||
}
|
||||
#endif /* __HAIR__ */
|
||||
|
||||
/* Scene intersection. */
|
||||
|
||||
ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility,
|
||||
ccl_private Intersection *isect)
|
||||
{
|
||||
metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
|
||||
metalrt_intersector_type metalrt_intersect;
|
||||
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
||||
metalrt_intersect.assume_geometry_type(
|
||||
metal::raytracing::geometry_type::triangle |
|
||||
(kernel_data.bvh.have_curves ? metal::raytracing::geometry_type::curve :
|
||||
metal::raytracing::geometry_type::none) |
|
||||
(kernel_data.bvh.have_points ? metal::raytracing::geometry_type::bounding_box :
|
||||
metal::raytracing::geometry_type::none));
|
||||
|
||||
typename metalrt_intersector_type::result_type intersection;
|
||||
|
||||
MetalRTIntersectionPayload payload;
|
||||
payload.self_prim = ray->self.prim;
|
||||
payload.self_object = ray->self.object;
|
||||
payload.visibility = visibility;
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
|
||||
#if defined(__METALRT_MOTION__)
|
||||
intersection = metalrt_intersect.intersect(r,
|
||||
metal_ancillaries->accel_struct,
|
||||
ray_mask,
|
||||
ray->time,
|
||||
metal_ancillaries->ift_default,
|
||||
payload);
|
||||
#else
|
||||
intersection = metalrt_intersect.intersect(
|
||||
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_default, payload);
|
||||
#endif
|
||||
|
||||
if (intersection.type == intersection_type::none) {
|
||||
isect->t = ray->tmax;
|
||||
isect->type = PRIMITIVE_NONE;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isect->object = intersection.instance_id;
|
||||
isect->t = intersection.distance;
|
||||
if (intersection.type == intersection_type::triangle) {
|
||||
isect->prim = intersection.primitive_id + intersection.user_instance_id;
|
||||
isect->type = kernel_data_fetch(objects, intersection.instance_id).primitive_type;
|
||||
isect->u = intersection.triangle_barycentric_coord.x;
|
||||
isect->v = intersection.triangle_barycentric_coord.y;
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if (kernel_data.bvh.have_curves && intersection.type == intersection_type::curve) {
|
||||
int prim = intersection.primitive_id + intersection.user_instance_id;
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
|
||||
isect->prim = segment.prim;
|
||||
isect->type = segment.type;
|
||||
isect->u = intersection.curve_parameter;
|
||||
|
||||
if ((segment.type & PRIMITIVE_CURVE) == PRIMITIVE_CURVE_RIBBON) {
|
||||
isect->v = curve_ribbon_v(kg,
|
||||
intersection.curve_parameter,
|
||||
intersection.distance,
|
||||
ray,
|
||||
intersection.instance_id,
|
||||
segment.prim,
|
||||
segment.type);
|
||||
}
|
||||
else {
|
||||
isect->v = 0.0f;
|
||||
}
|
||||
}
|
||||
#endif /* __HAIR__ */
|
||||
#ifdef __POINTCLOUD__
|
||||
else if (kernel_data.bvh.have_points && intersection.type == intersection_type::bounding_box) {
|
||||
const int object = intersection.instance_id;
|
||||
const uint prim = intersection.primitive_id + intersection.user_instance_id;
|
||||
const int prim_type = kernel_data_fetch(objects, object).primitive_type;
|
||||
|
||||
if (!(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
float3 idir;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
bvh_instance_motion_push(nullptr, object, ray, &r.origin, &r.direction, &idir);
|
||||
# else
|
||||
bvh_instance_push(nullptr, object, ray, &r.origin, &r.direction, &idir);
|
||||
# endif
|
||||
}
|
||||
|
||||
if (prim_type & PRIMITIVE_POINT) {
|
||||
if (!point_intersect(nullptr,
|
||||
isect,
|
||||
r.origin,
|
||||
r.direction,
|
||||
ray->tmin,
|
||||
ray->tmax,
|
||||
object,
|
||||
prim,
|
||||
ray->time,
|
||||
prim_type))
|
||||
{
|
||||
/* Shouldn't get here */
|
||||
kernel_assert(!"Intersection mismatch");
|
||||
isect->t = ray->tmax;
|
||||
isect->type = PRIMITIVE_NONE;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif /* __POINTCLOUD__ */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ccl_device_intersect bool scene_intersect_shadow(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility)
|
||||
{
|
||||
metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
|
||||
metalrt_intersector_type metalrt_intersect;
|
||||
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
||||
metalrt_intersect.assume_geometry_type(
|
||||
metal::raytracing::geometry_type::triangle |
|
||||
(kernel_data.bvh.have_curves ? metal::raytracing::geometry_type::curve :
|
||||
metal::raytracing::geometry_type::none) |
|
||||
(kernel_data.bvh.have_points ? metal::raytracing::geometry_type::bounding_box :
|
||||
metal::raytracing::geometry_type::none));
|
||||
|
||||
typename metalrt_intersector_type::result_type intersection;
|
||||
|
||||
metalrt_intersect.accept_any_intersection(true);
|
||||
|
||||
MetalRTIntersectionShadowPayload payload;
|
||||
payload.self = ray->self;
|
||||
payload.visibility = visibility;
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
|
||||
#if defined(__METALRT_MOTION__)
|
||||
intersection = metalrt_intersect.intersect(r,
|
||||
metal_ancillaries->accel_struct,
|
||||
ray_mask,
|
||||
ray->time,
|
||||
metal_ancillaries->ift_shadow,
|
||||
payload);
|
||||
#else
|
||||
intersection = metalrt_intersect.intersect(
|
||||
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_shadow, payload);
|
||||
#endif
|
||||
return (intersection.type != intersection_type::none);
|
||||
}
|
||||
|
||||
#ifdef __BVH_LOCAL__
|
||||
template<bool single_hit = false>
|
||||
ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private LocalIntersection *local_isect,
|
||||
const int local_object,
|
||||
ccl_private uint *lcg_state,
|
||||
const int max_hits)
|
||||
{
|
||||
uint primitive_id_offset = kernel_data_fetch(object_prim_offset, local_object);
|
||||
|
||||
metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
|
||||
|
||||
# if defined(__METALRT_MOTION__)
|
||||
metalrt_intersector_type metalrt_intersect;
|
||||
typename metalrt_intersector_type::result_type intersection;
|
||||
# else
|
||||
metalrt_blas_intersector_type metalrt_intersect;
|
||||
typename metalrt_blas_intersector_type::result_type intersection;
|
||||
|
||||
if (!(kernel_data_fetch(object_flag, local_object) & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
/* Transform the ray into object's local space. */
|
||||
Transform itfm = kernel_data_fetch(objects, local_object).itfm;
|
||||
r.origin = transform_point(&itfm, r.origin);
|
||||
r.direction = transform_direction(&itfm, r.direction);
|
||||
}
|
||||
# endif
|
||||
|
||||
metalrt_intersect.assume_geometry_type(metal::raytracing::geometry_type::triangle);
|
||||
|
||||
if (single_hit) {
|
||||
MetalRTIntersectionLocalPayload_single_hit payload;
|
||||
payload.self_prim = ray->self.prim - primitive_id_offset;
|
||||
|
||||
# if defined(__METALRT_MOTION__)
|
||||
/* We can't skip over the top-level BVH in the motion blur case, so still need to do
|
||||
* the self-object check. */
|
||||
payload.self_object = local_object;
|
||||
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
||||
intersection = metalrt_intersect.intersect(r,
|
||||
metal_ancillaries->accel_struct,
|
||||
~0,
|
||||
ray->time,
|
||||
metal_ancillaries->ift_local_single_hit_mblur,
|
||||
payload);
|
||||
# else
|
||||
/* We only need custom intersection filtering (i.e. non_opaque) if we are performing a
|
||||
* self-primitive intersection check. */
|
||||
metalrt_intersect.force_opacity((ray->self.prim == PRIM_NONE) ?
|
||||
metal::raytracing::forced_opacity::opaque :
|
||||
metal::raytracing::forced_opacity::non_opaque);
|
||||
intersection = metalrt_intersect.intersect(
|
||||
r,
|
||||
metal_ancillaries->blas_accel_structs[local_object].blas,
|
||||
metal_ancillaries->ift_local_single_hit,
|
||||
payload);
|
||||
# endif
|
||||
|
||||
if (intersection.type == intersection_type::none) {
|
||||
local_isect->num_hits = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint prim = intersection.primitive_id + primitive_id_offset;
|
||||
int prim_type = kernel_data_fetch(objects, local_object).primitive_type;
|
||||
|
||||
local_isect->num_hits = 1;
|
||||
local_isect->hits[0].prim = prim;
|
||||
local_isect->hits[0].type = prim_type;
|
||||
local_isect->hits[0].object = local_object;
|
||||
local_isect->hits[0].u = intersection.triangle_barycentric_coord.x;
|
||||
local_isect->hits[0].v = intersection.triangle_barycentric_coord.y;
|
||||
local_isect->hits[0].t = intersection.distance;
|
||||
|
||||
const int position_offset = kernel_data_fetch(objects, local_object).position_offset;
|
||||
const packed_uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
|
||||
const float3 tri_a = float3(kernel_data_fetch(tri_verts, position_offset + tri_vindex.x));
|
||||
const float3 tri_b = float3(kernel_data_fetch(tri_verts, position_offset + tri_vindex.y));
|
||||
const float3 tri_c = float3(kernel_data_fetch(tri_verts, position_offset + tri_vindex.z));
|
||||
local_isect->Ng[0] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
MetalRTIntersectionLocalPayload payload;
|
||||
payload.self_prim = ray->self.prim - primitive_id_offset;
|
||||
payload.max_hits = max_hits;
|
||||
payload.num_hits = 0;
|
||||
if (lcg_state) {
|
||||
payload.has_lcg_state = true;
|
||||
payload.lcg_state = *lcg_state;
|
||||
}
|
||||
else {
|
||||
payload.has_lcg_state = false;
|
||||
}
|
||||
|
||||
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
||||
|
||||
# if defined(__METALRT_MOTION__)
|
||||
/* We can't skip over the top-level BVH in the motion blur case, so still need to do
|
||||
* the self-object check. */
|
||||
payload.self_object = local_object;
|
||||
intersection = metalrt_intersect.intersect(r,
|
||||
metal_ancillaries->accel_struct,
|
||||
~0,
|
||||
ray->time,
|
||||
metal_ancillaries->ift_local_mblur,
|
||||
payload);
|
||||
# else
|
||||
intersection = metalrt_intersect.intersect(
|
||||
r,
|
||||
metal_ancillaries->blas_accel_structs[local_object].blas,
|
||||
metal_ancillaries->ift_local,
|
||||
payload);
|
||||
# endif
|
||||
|
||||
if (max_hits == 0) {
|
||||
/* Special case for when no hit information is requested, just report that something was hit
|
||||
*/
|
||||
return (intersection.type != intersection_type::none);
|
||||
}
|
||||
|
||||
if (lcg_state) {
|
||||
*lcg_state = payload.lcg_state;
|
||||
}
|
||||
|
||||
const int num_hits = payload.num_hits;
|
||||
if (local_isect) {
|
||||
|
||||
/* Record geometric normal */
|
||||
int prim_type = kernel_data_fetch(objects, local_object).primitive_type;
|
||||
|
||||
/* Number of hits counted can be higher than recorded due to reservoir sampling. */
|
||||
local_isect->num_hits = num_hits;
|
||||
const int num_recorded_hits = min(payload.num_hits, max_hits);
|
||||
for (int hit = 0; hit < num_recorded_hits; hit++) {
|
||||
const uint prim = payload.hits[hit].prim + primitive_id_offset;
|
||||
local_isect->hits[hit].prim = prim;
|
||||
local_isect->hits[hit].t = payload.hits[hit].t;
|
||||
local_isect->hits[hit].u = payload.hits[hit].u;
|
||||
local_isect->hits[hit].v = payload.hits[hit].v;
|
||||
local_isect->hits[hit].object = local_object;
|
||||
local_isect->hits[hit].type = prim_type;
|
||||
|
||||
const int position_offset = kernel_data_fetch(objects, local_object).position_offset;
|
||||
const packed_uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
|
||||
const float3 tri_a = float3(kernel_data_fetch(tri_verts, position_offset + tri_vindex.x));
|
||||
const float3 tri_b = float3(kernel_data_fetch(tri_verts, position_offset + tri_vindex.y));
|
||||
const float3 tri_c = float3(kernel_data_fetch(tri_verts, position_offset + tri_vindex.z));
|
||||
local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
|
||||
}
|
||||
}
|
||||
return num_hits > 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TRANSPARENT_SHADOWS__
|
||||
ccl_device_intersect void scene_intersect_shadow_all_metalrt(
|
||||
const ccl_private Ray *ray, ccl_private BVHShadowAllPayload &ccl_restrict payload)
|
||||
{
|
||||
metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
|
||||
metalrt_intersector_type metalrt_intersect;
|
||||
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
||||
metalrt_intersect.assume_geometry_type(
|
||||
metal::raytracing::geometry_type::triangle |
|
||||
(kernel_data.bvh.have_curves ? metal::raytracing::geometry_type::curve :
|
||||
metal::raytracing::geometry_type::none) |
|
||||
(kernel_data.bvh.have_points ? metal::raytracing::geometry_type::bounding_box :
|
||||
metal::raytracing::geometry_type::none));
|
||||
|
||||
uint ray_mask = payload.base.ray_visibility & 0xFF;
|
||||
if (0 == ray_mask && (payload.base.ray_visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
|
||||
typename metalrt_intersector_type::result_type intersection;
|
||||
|
||||
# if defined(__METALRT_MOTION__)
|
||||
intersection = metalrt_intersect.intersect(r,
|
||||
metal_ancillaries->accel_struct,
|
||||
ray_mask,
|
||||
ray->time,
|
||||
metal_ancillaries->ift_shadow_all,
|
||||
payload);
|
||||
# else
|
||||
intersection = metalrt_intersect.intersect(
|
||||
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_shadow_all, payload);
|
||||
# endif
|
||||
|
||||
(void)intersection;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
|
||||
metalrt_intersector_type metalrt_intersect;
|
||||
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
|
||||
metalrt_intersect.set_geometry_cull_mode(metal::raytracing::geometry_cull_mode::bounding_box |
|
||||
metal::raytracing::geometry_cull_mode::curve);
|
||||
metalrt_intersect.assume_geometry_type(
|
||||
metal::raytracing::geometry_type::triangle |
|
||||
(kernel_data.bvh.have_curves ? metal::raytracing::geometry_type::curve :
|
||||
metal::raytracing::geometry_type::none) |
|
||||
(kernel_data.bvh.have_points ? metal::raytracing::geometry_type::bounding_box :
|
||||
metal::raytracing::geometry_type::none));
|
||||
|
||||
MetalRTIntersectionShadowPayload payload;
|
||||
payload.self = ray->self;
|
||||
payload.visibility = visibility;
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
|
||||
typename metalrt_intersector_type::result_type intersection;
|
||||
|
||||
# if defined(__METALRT_MOTION__)
|
||||
intersection = metalrt_intersect.intersect(r,
|
||||
metal_ancillaries->accel_struct,
|
||||
ray_mask,
|
||||
ray->time,
|
||||
metal_ancillaries->ift_volume,
|
||||
payload);
|
||||
# else
|
||||
intersection = metalrt_intersect.intersect(
|
||||
r, metal_ancillaries->accel_struct, ray_mask, metal_ancillaries->ift_volume, payload);
|
||||
# endif
|
||||
|
||||
if (intersection.type == intersection_type::triangle) {
|
||||
isect->prim = intersection.primitive_id + intersection.user_instance_id;
|
||||
isect->type = kernel_data_fetch(objects, intersection.instance_id).primitive_type;
|
||||
isect->u = intersection.triangle_barycentric_coord.x;
|
||||
isect->v = intersection.triangle_barycentric_coord.y;
|
||||
isect->object = intersection.instance_id;
|
||||
isect->t = intersection.distance;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
407
blender-5.2.0/intern/cycles/kernel/device/metal/compat.h
Normal file
407
blender-5.2.0/intern/cycles/kernel/device/metal/compat.h
Normal file
@@ -0,0 +1,407 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_METAL__
|
||||
#define CCL_NAMESPACE_BEGIN
|
||||
#define CCL_NAMESPACE_END
|
||||
|
||||
#ifndef ATTR_FALLTHROUGH
|
||||
# define ATTR_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#include <metal_atomic>
|
||||
#include <metal_pack>
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
#ifdef __KERNEL_METALRT__
|
||||
using namespace metal::raytracing;
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
#pragma clang diagnostic ignored "-Wuninitialized"
|
||||
#pragma clang diagnostic ignored "-Wc++17-extensions"
|
||||
#pragma clang diagnostic ignored "-Wmacro-redefined"
|
||||
|
||||
/* Qualifiers */
|
||||
|
||||
#define ccl_device
|
||||
#define ccl_device_inline ccl_device __attribute__((always_inline))
|
||||
#define ccl_device_forceinline ccl_device __attribute__((always_inline))
|
||||
#if defined(__KERNEL_METAL_APPLE__)
|
||||
# define ccl_device_noinline ccl_device
|
||||
#else
|
||||
# define ccl_device_noinline ccl_device __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#define ccl_device_extern extern "C"
|
||||
#define ccl_device_noinline_cpu ccl_device
|
||||
#define ccl_device_inline_method ccl_device
|
||||
#define ccl_device_template_spec template<> ccl_device_inline
|
||||
#define ccl_global device
|
||||
#define ccl_inline_constant static constant constexpr
|
||||
#define ccl_device_constant constant
|
||||
#define ccl_static_constexpr static constant constexpr
|
||||
#define ccl_constant constant
|
||||
#define ccl_gpu_shared threadgroup
|
||||
#define ccl_private thread
|
||||
#ifdef __KERNEL_METALRT__
|
||||
# define ccl_ray_data ray_data
|
||||
#else
|
||||
# define ccl_ray_data ccl_private
|
||||
#endif
|
||||
#define ccl_may_alias
|
||||
#define ccl_restrict __restrict
|
||||
#define ccl_align(n) alignas(n)
|
||||
#define ccl_optional_struct_init
|
||||
#define ccl_attr_maybe_unused
|
||||
// Not supported by older MacOS versions (e.g., 13.0)
|
||||
// #define ccl_attr_maybe_unused [[maybe_unused]]
|
||||
|
||||
/* No assert supported for Metal */
|
||||
|
||||
#define kernel_assert(cond)
|
||||
|
||||
#define offsetof(t, d) __builtin_offsetof(t, d)
|
||||
|
||||
#define ccl_gpu_global_id_x() metal_global_id
|
||||
#define ccl_gpu_warp_size simdgroup_size
|
||||
#define ccl_gpu_thread_idx_x simd_group_index
|
||||
#define ccl_gpu_thread_mask(thread_warp) uint64_t((1ull << thread_warp) - 1)
|
||||
|
||||
#define ccl_gpu_ballot(predicate) ((uint64_t)((simd_vote::vote_t)simd_ballot(predicate)))
|
||||
#define ccl_gpu_syncthreads() threadgroup_barrier(mem_flags::mem_threadgroup);
|
||||
|
||||
// clang-format off
|
||||
|
||||
/* kernel.h adapters */
|
||||
|
||||
#define ccl_gpu_kernel(block_num_threads, thread_num_registers)
|
||||
#define ccl_gpu_kernel_threads(block_num_threads)
|
||||
|
||||
/* Convert a comma-separated list into a semicolon-separated list
|
||||
* (so that we can generate a struct based on kernel entry-point parameters). */
|
||||
#define FN0()
|
||||
#define FN1(p1) p1;
|
||||
#define FN2(p1, p2) p1; p2;
|
||||
#define FN3(p1, p2, p3) p1; p2; p3;
|
||||
#define FN4(p1, p2, p3, p4) p1; p2; p3; p4;
|
||||
#define FN5(p1, p2, p3, p4, p5) p1; p2; p3; p4; p5;
|
||||
#define FN6(p1, p2, p3, p4, p5, p6) p1; p2; p3; p4; p5; p6;
|
||||
#define FN7(p1, p2, p3, p4, p5, p6, p7) p1; p2; p3; p4; p5; p6; p7;
|
||||
#define FN8(p1, p2, p3, p4, p5, p6, p7, p8) p1; p2; p3; p4; p5; p6; p7; p8;
|
||||
#define FN9(p1, p2, p3, p4, p5, p6, p7, p8, p9) p1; p2; p3; p4; p5; p6; p7; p8; p9;
|
||||
#define FN10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10;
|
||||
#define FN11(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11;
|
||||
#define FN12(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12;
|
||||
#define FN13(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13;
|
||||
#define FN14(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14;
|
||||
#define FN15(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15;
|
||||
#define FN16(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16;
|
||||
#define FN17(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17;
|
||||
#define FN18(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17; p18;
|
||||
#define FN19(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17; p18; p19;
|
||||
#define FN20(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; p17; p18; p19; p20;
|
||||
#define GET_LAST_ARG(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, ...) p20
|
||||
#define PARAMS_MAKER(...) GET_LAST_ARG(__VA_ARGS__, FN20, FN19, FN18, FN17, FN16, FN15, FN14, FN13, FN12, FN11, FN10, FN9, FN8, FN7, FN6, FN5, FN4, FN3, FN2, FN1, FN0)
|
||||
|
||||
/* Generate a struct containing the entry-point parameters and a "run"
|
||||
* method which can access them implicitly via this-> */
|
||||
|
||||
#ifdef __METAL_GLOBAL_BUILTINS__
|
||||
|
||||
#define ccl_gpu_kernel_signature(name, ...) \
|
||||
struct kernel_gpu_##name \
|
||||
{ \
|
||||
PARAMS_MAKER(__VA_ARGS__)(__VA_ARGS__) \
|
||||
void run(thread MetalKernelContext& context, \
|
||||
threadgroup atomic_int *threadgroup_array) ccl_global const; \
|
||||
}; \
|
||||
kernel void cycles_metal_##name(device const kernel_gpu_##name *params_struct, \
|
||||
constant KernelParamsMetal &ccl_restrict _launch_params_metal, \
|
||||
constant MetalAncillaries *_metal_ancillaries, \
|
||||
threadgroup atomic_int *threadgroup_array[[ threadgroup(0) ]]) { \
|
||||
MetalKernelContext context(_launch_params_metal, _metal_ancillaries); \
|
||||
params_struct->run(context, threadgroup_array); \
|
||||
} \
|
||||
void kernel_gpu_##name::run(thread MetalKernelContext& context, \
|
||||
threadgroup atomic_int *threadgroup_array) ccl_global const
|
||||
|
||||
#else
|
||||
|
||||
/* On macOS versions before 14.x, builtin constants (e.g. metal_global_id) must
|
||||
* be accessed through attributed entry-point parameters. */
|
||||
|
||||
#define ccl_gpu_kernel_signature(name, ...) \
|
||||
struct kernel_gpu_##name \
|
||||
{ \
|
||||
PARAMS_MAKER(__VA_ARGS__)(__VA_ARGS__) \
|
||||
void run(thread MetalKernelContext& context, \
|
||||
threadgroup atomic_int *threadgroup_array, \
|
||||
const uint metal_global_id, \
|
||||
const ushort metal_local_id, \
|
||||
const ushort metal_local_size, \
|
||||
const uint metal_grid_id, \
|
||||
uint simdgroup_size, \
|
||||
uint simd_lane_index, \
|
||||
uint simd_group_index, \
|
||||
uint num_simd_groups) ccl_global const; \
|
||||
}; \
|
||||
kernel void cycles_metal_##name(device const kernel_gpu_##name *params_struct, \
|
||||
constant KernelParamsMetal &ccl_restrict _launch_params_metal, \
|
||||
constant MetalAncillaries *_metal_ancillaries, \
|
||||
threadgroup atomic_int *threadgroup_array[[ threadgroup(0) ]], \
|
||||
const uint metal_global_id [[thread_position_in_grid]], \
|
||||
const ushort metal_local_id [[thread_position_in_threadgroup]], \
|
||||
const ushort metal_local_size [[threads_per_threadgroup]], \
|
||||
const uint metal_grid_id [[threadgroup_position_in_grid]], \
|
||||
uint simdgroup_size [[threads_per_simdgroup]], \
|
||||
uint simd_lane_index [[thread_index_in_simdgroup]], \
|
||||
uint simd_group_index [[simdgroup_index_in_threadgroup]], \
|
||||
uint num_simd_groups [[simdgroups_per_threadgroup]]) { \
|
||||
MetalKernelContext context(_launch_params_metal, _metal_ancillaries); \
|
||||
params_struct->run(context, threadgroup_array, metal_global_id, metal_local_id, metal_local_size, metal_grid_id, simdgroup_size, simd_lane_index, simd_group_index, num_simd_groups); \
|
||||
} \
|
||||
void kernel_gpu_##name::run(thread MetalKernelContext& context, \
|
||||
threadgroup atomic_int *threadgroup_array, \
|
||||
const uint metal_global_id, \
|
||||
const ushort metal_local_id, \
|
||||
const ushort metal_local_size, \
|
||||
const uint metal_grid_id, \
|
||||
uint simdgroup_size, \
|
||||
uint simd_lane_index, \
|
||||
uint simd_group_index, \
|
||||
uint num_simd_groups) ccl_global const
|
||||
|
||||
#endif /* __METAL_GLOBAL_BUILTINS__ */
|
||||
|
||||
#define ccl_gpu_kernel_postfix
|
||||
#define ccl_gpu_kernel_call(x) context.x
|
||||
#define ccl_gpu_kernel_within_bounds(i,n) true
|
||||
|
||||
/* define a function object where "func" is the lambda body, and additional parameters are used to specify captured state. */
|
||||
#define ccl_gpu_kernel_lambda(func, ...) \
|
||||
struct KernelLambda \
|
||||
{ \
|
||||
KernelLambda(ccl_private MetalKernelContext &_context) : context(_context) {} \
|
||||
ccl_private MetalKernelContext &context; \
|
||||
__VA_ARGS__; \
|
||||
int operator()(const int state) const { return (func); } \
|
||||
} ccl_gpu_kernel_lambda_pass(context)
|
||||
|
||||
// clang-format on
|
||||
|
||||
/* make_type definitions with Metal style element initializers */
|
||||
ccl_device_forceinline float2 make_float2(const float x, const float y)
|
||||
{
|
||||
return float2(x, y);
|
||||
}
|
||||
|
||||
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
|
||||
{
|
||||
return float3(x, y, z);
|
||||
}
|
||||
|
||||
ccl_device_forceinline float4 make_float4(const float x,
|
||||
const float y,
|
||||
const float z,
|
||||
const float w)
|
||||
{
|
||||
return float4(x, y, z, w);
|
||||
}
|
||||
|
||||
ccl_device_forceinline int2 make_int2(const int x, const int y)
|
||||
{
|
||||
return int2(x, y);
|
||||
}
|
||||
|
||||
ccl_device_forceinline int3 make_int3(const int x, const int y, const int z)
|
||||
{
|
||||
return int3(x, y, z);
|
||||
}
|
||||
|
||||
ccl_device_forceinline int4 make_int4(const int x, const int y, const int z, const int w)
|
||||
{
|
||||
return int4(x, y, z, w);
|
||||
}
|
||||
|
||||
ccl_device_forceinline uint2 make_uint2(const uint x, const uint y)
|
||||
{
|
||||
return uint2(x, y);
|
||||
}
|
||||
|
||||
ccl_device_forceinline uint3 make_uint3(const uint x, const uint y, const uint z)
|
||||
{
|
||||
return uint3(x, y, z);
|
||||
}
|
||||
|
||||
ccl_device_forceinline uint4 make_uint4(const uint x, const uint y, const uint z, const uint w)
|
||||
{
|
||||
return uint4(x, y, z, w);
|
||||
}
|
||||
|
||||
ccl_device_forceinline uchar4 make_uchar4(const uchar x,
|
||||
const uchar y,
|
||||
const uchar z,
|
||||
const uchar w)
|
||||
{
|
||||
return uchar4(x, y, z, w);
|
||||
}
|
||||
|
||||
/* Math functions */
|
||||
|
||||
#define __uint_as_float(x) as_type<float>(x)
|
||||
#define __float_as_uint(x) as_type<uint>(x)
|
||||
#define __int_as_float(x) as_type<float>(x)
|
||||
#define __float_as_int(x) as_type<int>(x)
|
||||
#define __float2half(x) half(x)
|
||||
#define powf(x, y) pow(float(x), float(y))
|
||||
#define fabsf(x) fabs(float(x))
|
||||
#define copysignf(x, y) copysign(float(x), float(y))
|
||||
#define asinf(x) asin(float(x))
|
||||
#define acosf(x) acos(float(x))
|
||||
#define atanf(x) atan(float(x))
|
||||
#define floorf(x) floor(float(x))
|
||||
#define ceilf(x) ceil(float(x))
|
||||
#define roundf(x) round(float(x))
|
||||
#define hypotf(x, y) hypot(float(x), float(y))
|
||||
#define atan2f(x, y) atan2(float(x), float(y))
|
||||
#define fmaxf(x, y) fmax(float(x), float(y))
|
||||
#define fminf(x, y) fmin(float(x), float(y))
|
||||
#define fmodf(x, y) fmod(float(x), float(y))
|
||||
#define sinhf(x) sinh(float(x))
|
||||
#define coshf(x) cosh(float(x))
|
||||
#define tanhf(x) tanh(float(x))
|
||||
#define saturatef(x) saturate(float(x))
|
||||
#define ldexpf(x, y) ldexp(float(x), int(y))
|
||||
|
||||
/* Use native functions with possibly lower precision for performance,
|
||||
* no issues found so far. */
|
||||
#define trigmode fast
|
||||
#define sinf(x) trigmode::sin(float(x))
|
||||
#define cosf(x) trigmode::cos(float(x))
|
||||
#define tanf(x) trigmode::tan(float(x))
|
||||
#define expf(x) trigmode::exp(float(x))
|
||||
#define sqrtf(x) trigmode::sqrt(float(x))
|
||||
#define logf(x) trigmode::log(float(x))
|
||||
|
||||
#define __device__
|
||||
|
||||
#ifdef __KERNEL_METALRT__
|
||||
|
||||
# if defined(__METALRT_MOTION__)
|
||||
# define METALRT_TAGS instancing, instance_motion, primitive_motion
|
||||
# define METALRT_BLAS_TAGS , primitive_motion
|
||||
# else
|
||||
# define METALRT_TAGS instancing
|
||||
# define METALRT_BLAS_TAGS
|
||||
# endif /* __METALRT_MOTION__ */
|
||||
|
||||
# if defined(__METALRT_EXTENDED_LIMITS__)
|
||||
# define METALRT_LIMITS , extended_limits
|
||||
# else
|
||||
# define METALRT_LIMITS
|
||||
# endif /* __METALRT_MOTION__ */
|
||||
|
||||
typedef acceleration_structure<METALRT_TAGS> metalrt_as_type;
|
||||
typedef intersection_function_table<triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS>
|
||||
metalrt_ift_type;
|
||||
typedef metal::raytracing::intersector<triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS>
|
||||
metalrt_intersector_type;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
typedef acceleration_structure<primitive_motion> metalrt_blas_as_type;
|
||||
typedef intersection_function_table<triangle_data, curve_data, primitive_motion METALRT_LIMITS>
|
||||
metalrt_blas_ift_type;
|
||||
typedef metal::raytracing::intersector<triangle_data, curve_data, primitive_motion METALRT_LIMITS>
|
||||
metalrt_blas_intersector_type;
|
||||
# else
|
||||
typedef acceleration_structure<> metalrt_blas_as_type;
|
||||
typedef intersection_function_table<triangle_data, curve_data METALRT_LIMITS>
|
||||
metalrt_blas_ift_type;
|
||||
typedef metal::raytracing::intersector<triangle_data, curve_data METALRT_LIMITS>
|
||||
metalrt_blas_intersector_type;
|
||||
# endif
|
||||
|
||||
#endif /* __KERNEL_METALRT__ */
|
||||
|
||||
/* texture bindings and sampler setup */
|
||||
|
||||
/* TextureParamsMetal is reinterpreted as Texture2DParamsMetal. */
|
||||
struct TextureParamsMetal {
|
||||
uint64_t tex;
|
||||
};
|
||||
struct Texture2DParamsMetal {
|
||||
texture2d<float, access::sample> tex;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL_METALRT__
|
||||
struct MetalRTBlasWrapper {
|
||||
metalrt_blas_as_type blas;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Additional Metal-specific resources which aren't encoded in KernelData.
|
||||
* IMPORTANT: If this layout changes, ANCILLARY_SLOT_COUNT and the host-side encoding must change
|
||||
* to match. */
|
||||
struct MetalAncillaries {
|
||||
device TextureParamsMetal *textures;
|
||||
|
||||
#ifdef __KERNEL_METALRT__
|
||||
metalrt_as_type accel_struct;
|
||||
constant MetalRTBlasWrapper *blas_accel_structs;
|
||||
metalrt_ift_type ift_default;
|
||||
metalrt_ift_type ift_shadow;
|
||||
metalrt_ift_type ift_shadow_all;
|
||||
metalrt_ift_type ift_volume;
|
||||
metalrt_blas_ift_type ift_local;
|
||||
metalrt_ift_type ift_local_mblur;
|
||||
metalrt_blas_ift_type ift_local_single_hit;
|
||||
metalrt_ift_type ift_local_single_hit_mblur;
|
||||
#endif
|
||||
};
|
||||
|
||||
#include "util/half.h"
|
||||
#include "util/types.h"
|
||||
|
||||
enum SamplerType {
|
||||
SamplerFilterNearest_AddressRepeat,
|
||||
SamplerFilterNearest_AddressClampEdge,
|
||||
SamplerFilterNearest_AddressClampZero,
|
||||
SamplerFilterNearest_AddressMirroredRepeat,
|
||||
|
||||
SamplerFilterLinear_AddressRepeat,
|
||||
SamplerFilterLinear_AddressClampEdge,
|
||||
SamplerFilterLinear_AddressClampZero,
|
||||
SamplerFilterLinear_AddressMirroredRepeat,
|
||||
|
||||
SamplerCount
|
||||
};
|
||||
|
||||
constexpr constant array<sampler, SamplerCount> metal_samplers = {
|
||||
sampler(address::repeat, filter::nearest),
|
||||
sampler(address::clamp_to_edge, filter::nearest),
|
||||
sampler(address::clamp_to_zero, filter::nearest),
|
||||
sampler(address::mirrored_repeat, filter::nearest),
|
||||
sampler(address::repeat, filter::linear),
|
||||
sampler(address::clamp_to_edge, filter::linear),
|
||||
sampler(address::clamp_to_zero, filter::linear),
|
||||
sampler(address::mirrored_repeat, filter::linear),
|
||||
};
|
||||
|
||||
#ifdef __METAL_GLOBAL_BUILTINS__
|
||||
const uint metal_global_id [[thread_position_in_grid]];
|
||||
const ushort metal_local_id [[thread_position_in_threadgroup]];
|
||||
const ushort metal_local_size [[threads_per_threadgroup]];
|
||||
const uint metal_grid_id [[threadgroup_position_in_grid]];
|
||||
const uint simdgroup_size [[threads_per_simdgroup]];
|
||||
const uint simd_lane_index [[thread_index_in_simdgroup]];
|
||||
const uint simd_group_index [[simdgroup_index_in_threadgroup]];
|
||||
const uint num_simd_groups [[simdgroups_per_threadgroup]];
|
||||
#endif /* __METAL_GLOBAL_BUILTINS__ */
|
||||
@@ -0,0 +1,54 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
# include "kernel/util/nanovdb.h"
|
||||
#endif
|
||||
|
||||
/* Open the Metal kernel context class
|
||||
* Necessary to access resource bindings */
|
||||
class MetalKernelContext {
|
||||
public:
|
||||
constant KernelParamsMetal &launch_params_metal;
|
||||
constant MetalAncillaries *metal_ancillaries;
|
||||
|
||||
MetalKernelContext(constant KernelParamsMetal &_launch_params_metal, constant MetalAncillaries * _metal_ancillaries)
|
||||
: launch_params_metal(_launch_params_metal), metal_ancillaries(_metal_ancillaries)
|
||||
{}
|
||||
|
||||
MetalKernelContext(constant KernelParamsMetal &_launch_params_metal)
|
||||
: launch_params_metal(_launch_params_metal)
|
||||
{}
|
||||
|
||||
/* texture fetch adapter functions */
|
||||
using ccl_gpu_image_object_2D = uint64_t;
|
||||
|
||||
template<typename T>
|
||||
inline __attribute__((__always_inline__))
|
||||
T ccl_gpu_image_object_read_2D(ccl_gpu_image_object_2D tex, const float x, float y) const {
|
||||
kernel_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// texture2d
|
||||
template<>
|
||||
inline __attribute__((__always_inline__))
|
||||
float4 ccl_gpu_image_object_read_2D(ccl_gpu_image_object_2D tex, const float x, float y) const {
|
||||
const uint tid(tex);
|
||||
const uint sid(tex >> 32);
|
||||
return ((ccl_global Texture2DParamsMetal*)metal_ancillaries->textures)[tid].tex.sample(metal_samplers[sid], float2(x, y));
|
||||
}
|
||||
template<>
|
||||
inline __attribute__((__always_inline__))
|
||||
float ccl_gpu_image_object_read_2D(ccl_gpu_image_object_2D tex, const float x, float y) const {
|
||||
const uint tid(tex);
|
||||
const uint sid(tex >> 32);
|
||||
return ((ccl_global Texture2DParamsMetal*)metal_ancillaries->textures)[tid].tex.sample(metal_samplers[sid], float2(x, y)).x;
|
||||
}
|
||||
|
||||
# include "kernel/device/gpu/image.h"
|
||||
|
||||
// clang-format on
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
}
|
||||
; /* end of MetalKernelContext class definition */
|
||||
|
||||
/* Silently redirect into the MetalKernelContext instance */
|
||||
/* NOTE: These macros will need maintaining as entry-points change. */
|
||||
|
||||
#undef kernel_integrator_state
|
||||
#define kernel_integrator_state context.launch_params_metal.integrator_state
|
||||
@@ -0,0 +1,20 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
enum {
|
||||
Kernel_DummyConstant,
|
||||
#define KERNEL_STRUCT_MEMBER(parent, type, name) KernelData_##parent##_##name,
|
||||
#include "kernel/data_template.h"
|
||||
|
||||
KernelData_kernel_features
|
||||
};
|
||||
|
||||
#ifdef __KERNEL_METAL__
|
||||
# define KERNEL_STRUCT_MEMBER(parent, type, name) \
|
||||
constant type kernel_data_##parent##_##name \
|
||||
[[function_constant(KernelData_##parent##_##name)]];
|
||||
# include "kernel/data_template.h"
|
||||
|
||||
constant int kernel_data_kernel_features [[function_constant(KernelData_kernel_features)]];
|
||||
#endif
|
||||
40
blender-5.2.0/intern/cycles/kernel/device/metal/globals.h
Normal file
40
blender-5.2.0/intern/cycles/kernel/device/metal/globals.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Constant Globals */
|
||||
|
||||
#include "kernel/types.h"
|
||||
|
||||
#include "kernel/integrator/state.h"
|
||||
#include "kernel/util/profiler.h"
|
||||
|
||||
#include "util/color.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct KernelParamsMetal {
|
||||
|
||||
#define KERNEL_DATA_ARRAY(type, name) const ccl_global type *name;
|
||||
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) ccl_global type *name;
|
||||
#include "kernel/data_arrays.h"
|
||||
|
||||
const IntegratorStateGPU integrator_state;
|
||||
const KernelData data;
|
||||
};
|
||||
|
||||
struct KernelGlobalsGPU {
|
||||
int unused[1];
|
||||
};
|
||||
|
||||
using KernelGlobals = const ccl_global KernelGlobalsGPU *ccl_restrict;
|
||||
|
||||
/* Abstraction macros */
|
||||
#define kernel_data launch_params_metal.data
|
||||
#define kernel_data_fetch(name, index) launch_params_metal.name[index]
|
||||
#define kernel_data_write(name, index, value) launch_params_metal.name[index] = (value)
|
||||
#define kernel_data_array(name) launch_params_metal.name
|
||||
#define kernel_integrator_state launch_params_metal.integrator_state
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
746
blender-5.2.0/intern/cycles/kernel/device/metal/kernel.metal
Normal file
746
blender-5.2.0/intern/cycles/kernel/device/metal/kernel.metal
Normal file
@@ -0,0 +1,746 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Metal kernel entry points. */
|
||||
|
||||
/* NOTE: Must come prior to other includes. */
|
||||
#include "kernel/device/metal/compat.h"
|
||||
#include "kernel/device/metal/globals.h"
|
||||
|
||||
/* NOTE: Must come prior to the kernel.h. */
|
||||
#include "kernel/device/metal/function_constants.h"
|
||||
|
||||
/* NOTE: Must come prior to the rest of the includes. */
|
||||
#include "kernel/device/gpu/kernel.h"
|
||||
|
||||
/* The rest of the includes. */
|
||||
#include "kernel/bvh/intersect_filter.h"
|
||||
#include "kernel/geom/geom_intersect.h"
|
||||
|
||||
/* MetalRT intersection handlers. */
|
||||
|
||||
#ifdef __KERNEL_METALRT__
|
||||
|
||||
/* Intersection return types. */
|
||||
|
||||
/* For a bounding box intersection function. */
|
||||
struct BoundingBoxIntersectionResult {
|
||||
bool accept [[accept_intersection]];
|
||||
bool continue_search [[continue_search]];
|
||||
float distance [[distance]];
|
||||
};
|
||||
|
||||
/* For a primitive intersection function. */
|
||||
struct PrimitiveIntersectionResult {
|
||||
bool accept [[accept_intersection]];
|
||||
bool continue_search [[continue_search]];
|
||||
};
|
||||
|
||||
enum { METALRT_HIT_TRIANGLE, METALRT_HIT_CURVE, METALRT_HIT_BOUNDING_BOX };
|
||||
|
||||
/* Hit functions. */
|
||||
|
||||
[[intersection(triangle, triangle_data, curve_data)]] PrimitiveIntersectionResult
|
||||
__intersection__local_tri_single_hit(
|
||||
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload_single_hit &payload [[payload]],
|
||||
uint primitive_id [[primitive_id]])
|
||||
{
|
||||
PrimitiveIntersectionResult result;
|
||||
result.continue_search = true;
|
||||
result.accept = (payload.self_prim != primitive_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
triangle, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__local_tri_single_hit_mblur(
|
||||
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload_single_hit &payload [[payload]],
|
||||
# if defined(__METALRT_MOTION__)
|
||||
uint object [[instance_id]],
|
||||
# endif
|
||||
uint primitive_id [[primitive_id]])
|
||||
{
|
||||
PrimitiveIntersectionResult result;
|
||||
result.continue_search = true;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
result.accept = (payload.self_prim != primitive_id) && (payload.self_object == object);
|
||||
# else
|
||||
result.accept = (payload.self_prim != primitive_id);
|
||||
# endif
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TReturn, uint intersection_type>
|
||||
TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload,
|
||||
const uint prim,
|
||||
const float2 barycentrics,
|
||||
const float ray_tmax)
|
||||
{
|
||||
TReturn result;
|
||||
|
||||
# ifdef __BVH_LOCAL__
|
||||
if (payload.self_prim == prim) {
|
||||
/* Only intersect with matching object and skip self-intersection. */
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
const int max_hits = payload.max_hits;
|
||||
if (max_hits == 0) {
|
||||
/* Special case for when no hit information is requested, just report that something was hit.
|
||||
*/
|
||||
result.accept = true;
|
||||
result.continue_search = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Make a copy of the lcg_state in the private address space, allowing to use utility function
|
||||
* to find the hit index to write the intersection to. This function is used from both HW-RT
|
||||
* code-path and non-HW-RT, making it hard to deal with the address spaces in the function
|
||||
* signature. Hopefully, compiler is smart enough to eliminate this temporary copy. */
|
||||
uint lcg_state = payload.lcg_state;
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
const int hit_index = context.local_intersect_get_record_index(
|
||||
&payload, ray_tmax, payload.has_lcg_state ? &lcg_state : nullptr, max_hits);
|
||||
|
||||
payload.lcg_state = lcg_state;
|
||||
|
||||
if (hit_index == -1) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
payload.hits[hit_index].prim = prim;
|
||||
payload.hits[hit_index].t = ray_tmax;
|
||||
payload.hits[hit_index].u = barycentrics.x;
|
||||
payload.hits[hit_index].v = barycentrics.y;
|
||||
|
||||
/* Continue tracing (without this the trace call would return after the first hit). */
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
# endif
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(triangle, triangle_data, curve_data)]] PrimitiveIntersectionResult
|
||||
__intersection__local_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload
|
||||
[[payload]],
|
||||
uint primitive_id [[primitive_id]],
|
||||
float2 barycentrics [[barycentric_coord]],
|
||||
float ray_tmax [[distance]])
|
||||
{
|
||||
/* instance_id, aka the user_id has been removed. If we take this function we optimized the
|
||||
* SSS for starting traversal from a primitive acceleration structure instead of the root of the
|
||||
* global AS. this means we will always be intersecting the correct object no need for the
|
||||
* user-id to check */
|
||||
return metalrt_local_hit<PrimitiveIntersectionResult, METALRT_HIT_TRIANGLE>(
|
||||
launch_params_metal, payload, primitive_id, barycentrics, ray_tmax);
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
triangle, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__local_tri_mblur(
|
||||
constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload [[payload]],
|
||||
uint primitive_id [[primitive_id]],
|
||||
# if defined(__METALRT_MOTION__)
|
||||
uint object [[instance_id]],
|
||||
# endif
|
||||
float2 barycentrics [[barycentric_coord]],
|
||||
float ray_tmax [[distance]])
|
||||
{
|
||||
# if defined(__METALRT_MOTION__)
|
||||
if (payload.self_object != object) {
|
||||
PrimitiveIntersectionResult result;
|
||||
result.continue_search = true;
|
||||
result.accept = false;
|
||||
return result;
|
||||
}
|
||||
# endif
|
||||
|
||||
return metalrt_local_hit<PrimitiveIntersectionResult, METALRT_HIT_TRIANGLE>(
|
||||
launch_params_metal, payload, primitive_id, barycentrics, ray_tmax);
|
||||
}
|
||||
|
||||
inline bool metalrt_curve_skip_end_cap(const int type, const float u)
|
||||
{
|
||||
return ((u == 0.0f || u == 1.0f) && (type & PRIMITIVE_CURVE) != PRIMITIVE_CURVE_THICK_LINEAR);
|
||||
}
|
||||
|
||||
inline Intersection get_intersection(constant KernelParamsMetal &launch_params_metal,
|
||||
const float t,
|
||||
const float2 uv,
|
||||
uint object,
|
||||
uint prim)
|
||||
{
|
||||
Intersection isect;
|
||||
isect.t = t;
|
||||
isect.u = uv.x;
|
||||
isect.v = uv.y;
|
||||
isect.prim = prim;
|
||||
isect.object = object;
|
||||
isect.type = kernel_data_fetch(objects, object).primitive_type;
|
||||
|
||||
# ifdef __HAIR__
|
||||
if (isect.type & PRIMITIVE_CURVE) {
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
|
||||
isect.type = segment.type;
|
||||
isect.prim = segment.prim;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (isect.type & PRIMITIVE_POINT) {
|
||||
isect.u = 0.0f;
|
||||
isect.v = 0.0f;
|
||||
}
|
||||
|
||||
return isect;
|
||||
}
|
||||
|
||||
template<uint intersection_type>
|
||||
bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::BVHShadowAllPayload &payload,
|
||||
uint object,
|
||||
uint prim,
|
||||
const float2 uv,
|
||||
const float t,
|
||||
const ccl_private Ray *ray = nullptr)
|
||||
{
|
||||
# if defined(__TRANSPARENT_SHADOWS__)
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
|
||||
KernelGlobals kg = nullptr;
|
||||
|
||||
const Intersection isect = get_intersection(launch_params_metal, t, uv, object, prim);
|
||||
|
||||
# ifdef __HAIR__
|
||||
if constexpr (intersection_type == METALRT_HIT_CURVE) {
|
||||
/* Filter out curve end-caps. */
|
||||
if (metalrt_curve_skip_end_cap(isect.type, isect.u)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((isect.type & PRIMITIVE_CURVE) == PRIMITIVE_CURVE_RIBBON) {
|
||||
if (!context.curve_ribbon_accept(
|
||||
nullptr, isect.u, isect.t, ray, object, isect.prim, isect.type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif /* __HAIR__ */
|
||||
|
||||
constexpr uint enabled_primitive_types = (intersection_type == METALRT_HIT_CURVE) ?
|
||||
PRIMITIVE_CURVE :
|
||||
(PRIMITIVE_ALL & ~PRIMITIVE_CURVE);
|
||||
return context
|
||||
.bvh_shadow_all_anyhit_filter<MetalKernelContext::ISECT_TEST_ALL, enabled_primitive_types>(
|
||||
kg, payload.state, payload, payload.base.ray_self, payload.base.ray_visibility, isect);
|
||||
|
||||
# else /* __TRANSPARENT_SHADOWS__ */
|
||||
payload.throughput = 0.0f;
|
||||
return false;
|
||||
# endif /* __TRANSPARENT_SHADOWS__ */
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
triangle, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__tri_shadow_all(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::BVHShadowAllPayload &payload
|
||||
[[payload]],
|
||||
const unsigned int object [[instance_id]],
|
||||
const unsigned int primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const float2 uv [[barycentric_coord]],
|
||||
const float t [[distance]])
|
||||
{
|
||||
uint prim = primitive_id + primitive_id_offset;
|
||||
|
||||
PrimitiveIntersectionResult result;
|
||||
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_TRIANGLE>(
|
||||
launch_params_metal, payload, object, prim, uv, t);
|
||||
result.accept = !result.continue_search;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
triangle, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__volume_tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload
|
||||
[[payload]],
|
||||
const unsigned int object [[instance_id]],
|
||||
const unsigned int primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]])
|
||||
{
|
||||
PrimitiveIntersectionResult result;
|
||||
result.continue_search = true;
|
||||
|
||||
KernelGlobals kg = nullptr;
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
|
||||
uint prim = primitive_id + primitive_id_offset;
|
||||
|
||||
if (context.bvh_volume_anyhit_triangle_filter(
|
||||
kg, object, prim, payload.self, payload.visibility))
|
||||
{
|
||||
result.accept = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.accept = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TReturnType, uint intersection_type>
|
||||
inline TReturnType metalrt_visibility_test(
|
||||
constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload,
|
||||
const uint object,
|
||||
uint prim,
|
||||
const float u,
|
||||
const float t = 0.0f,
|
||||
const ccl_private Ray *ray = nullptr)
|
||||
{
|
||||
TReturnType result;
|
||||
|
||||
if ((kernel_data_fetch(objects, object).visibility & payload.visibility) == 0) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
# ifdef __HAIR__
|
||||
if constexpr (intersection_type == METALRT_HIT_CURVE) {
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
|
||||
int type = segment.type;
|
||||
prim = segment.prim;
|
||||
|
||||
/* Filter out curve end-caps. */
|
||||
if (metalrt_curve_skip_end_cap(type, u)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((type & PRIMITIVE_CURVE) == PRIMITIVE_CURVE_RIBBON) {
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (!context.curve_ribbon_accept(nullptr, u, t, ray, object, prim, type)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
if (payload.self_object == object && payload.self_prim == prim) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
result.accept = true;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TReturnType, uint intersection_type>
|
||||
inline TReturnType metalrt_visibility_test_shadow(
|
||||
constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload,
|
||||
const uint object,
|
||||
uint prim,
|
||||
const float u,
|
||||
const float t = 0.0f,
|
||||
const ccl_private Ray *ray = nullptr)
|
||||
{
|
||||
TReturnType result;
|
||||
|
||||
if ((kernel_data_fetch(objects, object).visibility & payload.visibility) == 0) {
|
||||
result.accept = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
# ifdef __HAIR__
|
||||
if constexpr (intersection_type == METALRT_HIT_CURVE) {
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
|
||||
int type = segment.type;
|
||||
prim = segment.prim;
|
||||
|
||||
/* Filter out curve end-caps. */
|
||||
if (metalrt_curve_skip_end_cap(type, u)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((type & PRIMITIVE_CURVE) == PRIMITIVE_CURVE_RIBBON) {
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (!context.curve_ribbon_accept(nullptr, u, t, ray, object, prim, type)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
|
||||
/* Shadow ray early termination. */
|
||||
# ifdef __SHADOW_LINKING__
|
||||
if (context.intersection_skip_shadow_link(nullptr, payload.self, object)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (context.intersection_skip_self_shadow(payload.self, object, prim)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
result.accept = true;
|
||||
result.continue_search = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.accept = true;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
triangle, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__tri(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
|
||||
const unsigned int object [[instance_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const unsigned int primitive_id [[primitive_id]])
|
||||
{
|
||||
PrimitiveIntersectionResult result;
|
||||
result.continue_search = true;
|
||||
|
||||
if ((kernel_data_fetch(objects, object).visibility & payload.visibility) == 0) {
|
||||
result.accept = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.accept = (payload.self_object != object ||
|
||||
payload.self_prim != (primitive_id + primitive_id_offset));
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
triangle, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__tri_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload
|
||||
[[payload]],
|
||||
const unsigned int object [[instance_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const unsigned int primitive_id [[primitive_id]])
|
||||
{
|
||||
uint prim = primitive_id + primitive_id_offset;
|
||||
PrimitiveIntersectionResult result =
|
||||
metalrt_visibility_test_shadow<PrimitiveIntersectionResult, METALRT_HIT_TRIANGLE>(
|
||||
launch_params_metal, payload, object, prim, 0.0f);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Primitive intersection functions. */
|
||||
|
||||
[[intersection(
|
||||
curve, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__curve(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
|
||||
const uint object [[instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
float distance [[distance]],
|
||||
const float3 ray_P [[origin]],
|
||||
const float3 ray_D [[direction]],
|
||||
float u [[curve_parameter]],
|
||||
const float ray_tmin [[min_distance]],
|
||||
const float ray_tmax [[max_distance]]
|
||||
# if defined(__METALRT_MOTION__)
|
||||
,
|
||||
const float time [[time]]
|
||||
# endif
|
||||
)
|
||||
{
|
||||
uint prim = primitive_id + primitive_id_offset;
|
||||
|
||||
Ray ray;
|
||||
ray.P = ray_P;
|
||||
ray.D = ray_D;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
ray.time = time;
|
||||
# endif
|
||||
|
||||
PrimitiveIntersectionResult result =
|
||||
metalrt_visibility_test<PrimitiveIntersectionResult, METALRT_HIT_CURVE>(
|
||||
launch_params_metal, payload, object, prim, u, distance, &ray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
curve, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__curve_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload
|
||||
[[payload]],
|
||||
const uint object [[instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
float distance [[distance]],
|
||||
const float3 ray_P [[origin]],
|
||||
const float3 ray_D [[direction]],
|
||||
float u [[curve_parameter]],
|
||||
const float ray_tmin [[min_distance]],
|
||||
const float ray_tmax [[max_distance]]
|
||||
# if defined(__METALRT_MOTION__)
|
||||
,
|
||||
const float time [[time]]
|
||||
# endif
|
||||
)
|
||||
{
|
||||
uint prim = primitive_id + primitive_id_offset;
|
||||
|
||||
Ray ray;
|
||||
ray.P = ray_P;
|
||||
ray.D = ray_D;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
ray.time = time;
|
||||
# endif
|
||||
|
||||
PrimitiveIntersectionResult result =
|
||||
metalrt_visibility_test_shadow<PrimitiveIntersectionResult, METALRT_HIT_CURVE>(
|
||||
launch_params_metal, payload, object, prim, u, distance, &ray);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(
|
||||
curve, triangle_data, curve_data, METALRT_TAGS METALRT_LIMITS)]] PrimitiveIntersectionResult
|
||||
__intersection__curve_shadow_all(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::BVHShadowAllPayload &payload
|
||||
[[payload]],
|
||||
const uint object [[instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const float3 ray_P [[origin]],
|
||||
const float3 ray_D [[direction]],
|
||||
# if defined(__METALRT_MOTION__)
|
||||
const float time [[time]],
|
||||
# endif
|
||||
float u [[curve_parameter]],
|
||||
float t [[distance]])
|
||||
{
|
||||
uint prim = primitive_id + primitive_id_offset;
|
||||
|
||||
PrimitiveIntersectionResult result;
|
||||
|
||||
Ray ray;
|
||||
ray.P = ray_P;
|
||||
ray.D = ray_D;
|
||||
# if defined(__METALRT_MOTION__)
|
||||
/* TODO(sergey): The time is not really needed.
|
||||
* Only ray direction and origin are needed in curve_ribbon_accept(), so there might be a room
|
||||
* for cleanup here. */
|
||||
ray.time = time;
|
||||
# endif
|
||||
|
||||
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_CURVE>(
|
||||
launch_params_metal, payload, object, prim, float2(u, 0), t, &ray);
|
||||
result.accept = !result.continue_search;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
# ifdef __POINTCLOUD__
|
||||
ccl_device_inline void metalrt_intersection_point_shadow_all(
|
||||
constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::BVHShadowAllPayload &payload,
|
||||
const uint object,
|
||||
const uint prim,
|
||||
const uint type,
|
||||
const float3 ray_P,
|
||||
const float3 ray_D,
|
||||
float time,
|
||||
const float ray_tmin,
|
||||
const float ray_tmax,
|
||||
thread BoundingBoxIntersectionResult &result)
|
||||
{
|
||||
Intersection isect;
|
||||
isect.t = ray_tmax;
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (context.point_intersect(
|
||||
nullptr, &isect, ray_P, ray_D, ray_tmin, isect.t, object, prim, time, type))
|
||||
{
|
||||
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
|
||||
launch_params_metal, payload, object, prim, float2(isect.u, isect.v), isect.t);
|
||||
result.accept = !result.continue_search;
|
||||
|
||||
if (result.accept) {
|
||||
result.distance = isect.t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[intersection(bounding_box,
|
||||
triangle_data,
|
||||
curve_data,
|
||||
METALRT_TAGS METALRT_LIMITS)]] BoundingBoxIntersectionResult
|
||||
__intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionPayload &payload [[payload]],
|
||||
const uint object [[instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const float3 ray_origin [[origin]],
|
||||
const float3 ray_direction [[direction]],
|
||||
# if defined(__METALRT_MOTION__)
|
||||
const float time [[time]],
|
||||
# endif
|
||||
const float ray_tmin [[min_distance]],
|
||||
const float ray_tmax [[max_distance]])
|
||||
{
|
||||
const uint prim = primitive_id + primitive_id_offset;
|
||||
const int type = kernel_data_fetch(objects, object).primitive_type;
|
||||
|
||||
BoundingBoxIntersectionResult result;
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
Intersection isect;
|
||||
isect.t = ray_tmax;
|
||||
|
||||
# ifndef __METALRT_MOTION__
|
||||
const float time = 0.0f;
|
||||
# endif
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (context.point_intersect(
|
||||
nullptr, &isect, ray_origin, ray_direction, ray_tmin, isect.t, object, prim, time, type))
|
||||
{
|
||||
result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
|
||||
launch_params_metal, payload, object, prim, isect.u);
|
||||
if (result.accept) {
|
||||
result.distance = isect.t;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
# endif /* __POINTCLOUD__ */
|
||||
|
||||
[[intersection(bounding_box,
|
||||
triangle_data,
|
||||
curve_data,
|
||||
METALRT_TAGS METALRT_LIMITS)]] BoundingBoxIntersectionResult
|
||||
__intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::MetalRTIntersectionShadowPayload &payload
|
||||
[[payload]],
|
||||
const uint object [[instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const float3 ray_origin [[origin]],
|
||||
const float3 ray_direction [[direction]],
|
||||
# if defined(__METALRT_MOTION__)
|
||||
const float time [[time]],
|
||||
# endif
|
||||
const float ray_tmin [[min_distance]],
|
||||
const float ray_tmax [[max_distance]])
|
||||
{
|
||||
const uint prim = primitive_id + primitive_id_offset;
|
||||
const int type = kernel_data_fetch(objects, object).primitive_type;
|
||||
|
||||
BoundingBoxIntersectionResult result;
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
# ifdef __POINTCLOUD__
|
||||
|
||||
Intersection isect;
|
||||
isect.t = ray_tmax;
|
||||
|
||||
# ifndef __METALRT_MOTION__
|
||||
const float time = 0.0f;
|
||||
# endif
|
||||
|
||||
MetalKernelContext context(launch_params_metal);
|
||||
if (context.point_intersect(
|
||||
nullptr, &isect, ray_origin, ray_direction, ray_tmin, isect.t, object, prim, time, type))
|
||||
{
|
||||
result =
|
||||
metalrt_visibility_test_shadow<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
|
||||
launch_params_metal, payload, object, prim, isect.u);
|
||||
if (result.accept) {
|
||||
result.distance = isect.t;
|
||||
}
|
||||
}
|
||||
|
||||
# endif /* __POINTCLOUD__ */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[intersection(bounding_box,
|
||||
triangle_data,
|
||||
curve_data,
|
||||
METALRT_TAGS METALRT_LIMITS)]] BoundingBoxIntersectionResult
|
||||
__intersection__point_shadow_all(constant KernelParamsMetal &launch_params_metal [[buffer(1)]],
|
||||
ray_data MetalKernelContext::BVHShadowAllPayload &payload
|
||||
[[payload]],
|
||||
const uint object [[instance_id]],
|
||||
const uint primitive_id [[primitive_id]],
|
||||
const uint primitive_id_offset [[user_instance_id]],
|
||||
const float3 ray_origin [[origin]],
|
||||
const float3 ray_direction [[direction]],
|
||||
# if defined(__METALRT_MOTION__)
|
||||
const float time [[time]],
|
||||
# endif
|
||||
const float ray_tmin [[min_distance]],
|
||||
const float ray_tmax [[max_distance]])
|
||||
{
|
||||
const uint prim = primitive_id + primitive_id_offset;
|
||||
const int type = kernel_data_fetch(objects, object).primitive_type;
|
||||
|
||||
BoundingBoxIntersectionResult result;
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
result.distance = ray_tmax;
|
||||
|
||||
# ifdef __POINTCLOUD__
|
||||
|
||||
metalrt_intersection_point_shadow_all(launch_params_metal,
|
||||
payload,
|
||||
object,
|
||||
prim,
|
||||
type,
|
||||
ray_origin,
|
||||
ray_direction,
|
||||
# if defined(__METALRT_MOTION__)
|
||||
time,
|
||||
# else
|
||||
0.0f,
|
||||
# endif
|
||||
ray_tmin,
|
||||
ray_tmax,
|
||||
result);
|
||||
|
||||
# endif /* __POINTCLOUD__ */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __KERNEL_METALRT__ */
|
||||
Reference in New Issue
Block a user