Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
#
# SPDX-License-Identifier: Apache-2.0
set(INC
../../..
)
set(INC_SYS
)
set(SRC_KERNEL_DEVICE_HIPRT
kernel.cpp
)
set(SRC_KERNEL_DEVICE_HIPRT_HEADERS
bvh.h
globals.h
)
set(SRC_KERNEL_DEVICE_HIPRT_SDK_HEADERS
hiprt/hiprt_common.h
hiprt/hiprt_device.h
hiprt/hiprt_types.h
hiprt/hiprt_vec.h
hiprt/hiprt_math.h
)
set(SRC_KERNEL_DEVICE_HIPRT_SDK
hiprt/impl/Aabb.h
hiprt/impl/BvhNode.h
hiprt/impl/Geometry.h
hiprt/impl/hiprt_device_impl.h
hiprt/impl/hiprt_kernels_bitcode.h
hiprt/impl/Instance.h
hiprt/impl/QrDecomposition.h
hiprt/impl/Quaternion.h
hiprt/impl/Scene.h
hiprt/impl/Transform.h
hiprt/impl/Triangle.h
)
set(LIB
)
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIPRT)
set(HIPRT_COMPILER_PARALLEL_JOBS 1 CACHE STRING "Number of parallel compiler instances to use for HIP-RT kernels")
mark_as_advanced(HIPRT_COMPILER_PARALLEL_JOBS)
if(WIN32)
set(hiprt_compile_command ${CMAKE_COMMAND})
set(hiprt_compile_flags
-E env "HIP_PATH=${HIP_ROOT_DIR}"
${HIP_HIPCC_EXECUTABLE})
else()
set(hiprt_compile_command ${HIP_HIPCC_EXECUTABLE})
set(hiprt_compile_flags "")
endif()
if(WITH_NANOVDB)
set(hiprt_compile_flags ${hiprt_compile_flags} -D WITH_NANOVDB)
endif()
if(WITH_CYCLES_DEBUG)
set(hiprt_compile_flags ${hiprt_compile_flags} -D WITH_CYCLES_DEBUG)
endif()
if(WIN32 AND (${HIP_VERSION} STREQUAL "6.1.40252"))
message(WARNING "HIP SDK ${HIP_VERSION} has known rendering artifacts with HIPRT. 5.7 is recommended instead")
endif()
set(hiprt_sources
kernel.cpp
${SRC_KERNEL_DEVICE_HIPRT_HEADERS}
$<TARGET_PROPERTY:cycles_kernel,INTERFACE_SOURCES>
)
set(kernel_sources ${hiprt_sources})
set(hiprt_kernel_src "/kernel.cpp")
set(hiprt_compile_flags
${hiprt_compile_flags}
${HIP_HIPCC_FLAGS}
${CMAKE_CURRENT_SOURCE_DIR}${hiprt_kernel_src}
-D CCL_NAMESPACE_BEGIN=
-D CCL_NAMESPACE_END=
-D HIPCC
-D __KERNEL_HIPRT__
-std=c++17
-mllvm
-amdgpu-early-inline-all=false
-mllvm
-amdgpu-function-calls=true
-parallel-jobs=${HIPRT_COMPILER_PARALLEL_JOBS}
--genco
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../..
-I ${HIPRT_INCLUDE_DIR}
-Wno-parentheses-equality
-Wno-unused-value
-ffast-math
)
set(hiprt_hipfb "")
foreach(arch ${CYCLES_HIP_BINARIES_ARCH})
set(hiprt_file ${CMAKE_CURRENT_BINARY_DIR}/kernel_rt_${arch}.hipfb)
set(hiprt_file_compressed ${hiprt_file}.zst)
set(hiprt_flags
${hiprt_compile_flags}
--offload-arch=${arch}
-o ${hiprt_file})
add_custom_command(
OUTPUT ${hiprt_file}
COMMAND ${hiprt_compile_command} ${hiprt_flags}
DEPENDS ${kernel_sources}
)
add_custom_command(
OUTPUT ${hiprt_file_compressed}
COMMAND "$<TARGET_FILE:zstd_compress>" ${hiprt_file} ${hiprt_file_compressed}
DEPENDS ${hiprt_file}
)
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${hiprt_file_compressed}" ${CYCLES_INSTALL_PATH}/lib)
list(APPEND hiprt_hipfb ${hiprt_file_compressed})
endforeach()
add_custom_target(cycles_kernel_hiprt
ALL
DEPENDS ${hiprt_hipfb}
SOURCES ${SRC_KERNEL_DEVICE_HIPRT} ${SRC_KERNEL_DEVICE_HIPRT_HEADERS}
)
cycles_set_solution_folder(cycles_kernel_hiprt)
source_group("device\\hiprt" FILES ${SRC_KERNEL_DEVICE_HIPRT} ${SRC_KERNEL_DEVICE_HIPRT_HEADERS})
add_dependencies(cycles_kernel cycles_kernel_hip)
endif()
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIPRT}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hiprt)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIPRT_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hiprt)
if(WITH_CYCLES_DEVICE_HIPRT)
delayed_install(${HIPRT_INCLUDE_DIR} "${SRC_KERNEL_DEVICE_HIPRT_SDK_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hiprt/hiprt)
delayed_install(${HIPRT_INCLUDE_DIR} "${SRC_KERNEL_DEVICE_HIPRT_SDK}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hiprt/hiprt/impl)
endif()

View File

@@ -0,0 +1,740 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
#include "kernel/bvh/intersect_filter.h"
CCL_NAMESPACE_BEGIN
struct LocalPayload {
RaySelfPrimitives self;
float ray_time;
int local_object;
uint max_hits;
uint *lcg_state;
LocalIntersection *local_isect;
};
/* --------------------------------------------------------------------
* Utilities.
*/
ccl_device_forceinline void set_hiprt_ray(const ccl_private Ray &ray,
ccl_private hiprtRay &ray_hip)
{
ray_hip.direction = ray.D;
ray_hip.origin = ray.P;
ray_hip.maxT = ray.tmax;
ray_hip.minT = ray.tmin;
}
ccl_device_inline void set_intersect_point(const hiprtHit &hit, ccl_private Intersection *isect)
{
const int object = kernel_data_fetch(user_instance_id, hit.instanceID);
isect->t = hit.t;
isect->u = hit.uv.x;
isect->v = hit.uv.y;
isect->object = object;
isect->type = kernel_data_fetch(objects, object).primitive_type;
if (isect->type & PRIMITIVE_CURVE) {
/* For curves the isect->type is a packed segment information, which is different from the
* primitive type associated with the object. */
/* TODO(sergey): Try to solve this with less fetches.
*
* Ideally avoid having HIP-RT specific custom_prim_info tables, allowing them to be removed
* in order to minimize the memory usage. */
const int2 data_offset = kernel_data_fetch(custom_prim_info_offset, object);
const int2 prim_info = kernel_data_fetch(custom_prim_info, hit.primID + data_offset.x);
isect->prim = prim_info.x + data_offset.y;
isect->type = prim_info.y;
}
else {
const int prim_offset = kernel_data_fetch(object_prim_offset, object);
isect->prim = hit.primID + prim_offset;
}
}
/* --------------------------------------------------------------------
* Custom intersection functions.
*/
ccl_device_inline bool curve_custom_intersect(const hiprtRay &ray,
BVHPayload *payload,
hiprtHit &hit)
{
/* Could also cast shadow payload to get the elements needed to do the intersection no need to
* write a separate function for shadow intersection. */
KernelGlobals kg = nullptr;
const int object_id = kernel_data_fetch(user_instance_id, hit.instanceID);
/* `data_offset.x`: where the data (prim id, type )for the geometry of the current object begins
* the prim_id that is in hiprtHit hit is local to the particular geometry so we add the above
* `ofstream` to map prim id in hiprtHit to the one compatible to what next stage expects
* `data_offset.y`: the offset that has to be added to a local primitive to get the global
* `primitive id = kernel_data_fetch(object_prim_offset, object_id);` */
const int2 data_offset = kernel_data_fetch(custom_prim_info_offset, object_id);
const int prim_offset = data_offset.y;
const int2 prim_info = kernel_data_fetch(custom_prim_info, hit.primID + data_offset.x);
const int curve_index = prim_info.x;
const int key_value = prim_info.y;
#ifdef __SHADOW_LINKING__
if (intersection_skip_shadow_link(kg, payload->ray_self, object_id)) {
return false; /* Ignore hit - continue traversal. */
}
#endif
if (intersection_skip_self_shadow(payload->ray_self, object_id, curve_index + prim_offset)) {
return false;
}
const float ray_time = payload->ray_time;
if ((key_value & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
const int time_offset = kernel_data_fetch(prim_time_offset, object_id);
const float2 prims_time = kernel_data_fetch(prims_time, hit.primID + time_offset);
if (ray_time < prims_time.x || ray_time > prims_time.y) {
return false;
}
}
Intersection isect;
const bool b_hit = curve_intersect(kg,
&isect,
ray.origin,
ray.direction,
ray.minT,
ray.maxT,
object_id,
curve_index + prim_offset,
ray_time,
key_value);
if (b_hit) {
hit.uv.x = isect.u;
hit.uv.y = isect.v;
hit.t = isect.t;
}
return b_hit;
}
ccl_device_inline bool motion_triangle_custom_intersect(const hiprtRay &ray,
BVHPayload *payload,
hiprtHit &hit)
{
KernelGlobals kg = nullptr;
const int object_id = kernel_data_fetch(user_instance_id, hit.instanceID);
const int2 data_offset = kernel_data_fetch(custom_prim_info_offset, object_id);
const int prim_offset = kernel_data_fetch(object_prim_offset, object_id);
const int prim_id_local = kernel_data_fetch(custom_prim_info, hit.primID + data_offset.x).x;
const int prim_id_global = prim_id_local + prim_offset;
if (intersection_skip_self_shadow(payload->ray_self, object_id, prim_id_global)) {
return false;
}
Intersection isect;
const bool b_hit = motion_triangle_intersect(kg,
&isect,
ray.origin,
ray.direction,
ray.minT,
ray.maxT,
payload->ray_time,
payload->ray_visibility,
object_id,
prim_id_global,
hit.instanceID);
if (b_hit) {
hit.uv.x = isect.u;
hit.uv.y = isect.v;
hit.t = isect.t;
}
return b_hit;
}
ccl_device_inline bool motion_triangle_custom_local_intersect(const hiprtRay &ray,
LocalPayload *payload,
hiprtHit &hit)
{
#ifdef __OBJECT_MOTION__
KernelGlobals kg = nullptr;
const int object_id = payload->local_object;
const int prim_offset = kernel_data_fetch(object_prim_offset, object_id);
const int2 data_offset = kernel_data_fetch(custom_prim_info_offset, object_id);
const int prim_id_local = kernel_data_fetch(custom_prim_info, hit.primID + data_offset.x).x;
const int prim_id_global = prim_id_local + prim_offset;
if (intersection_skip_self_local(payload->self, prim_id_global)) {
return false;
}
return motion_triangle_intersect_local(kg,
payload->local_isect,
ray.origin,
ray.direction,
payload->ray_time,
object_id,
prim_id_global,
ray.minT,
ray.maxT,
payload->lcg_state,
payload->max_hits);
#else
return false;
#endif
}
ccl_device_inline bool motion_triangle_custom_volume_intersect(const hiprtRay &ray,
BVHPayload *payload,
hiprtHit &hit)
{
#ifdef __OBJECT_MOTION__
KernelGlobals kg = nullptr;
const int object = kernel_data_fetch(user_instance_id, hit.instanceID);
const int2 data_offset = kernel_data_fetch(custom_prim_info_offset, object);
const int prim_offset = kernel_data_fetch(object_prim_offset, object);
const int prim_id_local = kernel_data_fetch(custom_prim_info, hit.primID + data_offset.x).x;
const int prim = prim_id_local + prim_offset;
if (bvh_volume_anyhit_triangle_filter(
kg, object, prim, payload->ray_self, payload->ray_visibility))
{
return false;
}
Intersection isect;
const bool b_hit = motion_triangle_intersect(kg,
&isect,
ray.origin,
ray.direction,
ray.minT,
ray.maxT,
payload->ray_time,
payload->ray_visibility,
object,
prim,
prim_id_local);
if (b_hit) {
hit.uv.x = isect.u;
hit.uv.y = isect.v;
hit.t = isect.t;
}
return b_hit;
#else
return false;
#endif
}
ccl_device_inline bool point_custom_intersect(const hiprtRay &ray,
BVHPayload *payload,
hiprtHit &hit)
{
#if defined(__POINTCLOUD__)
KernelGlobals kg = nullptr;
const int object_id = kernel_data_fetch(user_instance_id, hit.instanceID);
const int2 data_offset = kernel_data_fetch(custom_prim_info_offset, object_id);
const int prim_offset = kernel_data_fetch(object_prim_offset, object_id);
const int2 prim_info = kernel_data_fetch(custom_prim_info, hit.primID + data_offset.x);
const int prim_id_local = prim_info.x;
const int prim_id_global = prim_id_local + prim_offset;
const int primitive_type = prim_info.y;
# ifdef __SHADOW_LINKING__
if (intersection_skip_shadow_link(kg, payload->ray_self, object_id)) {
return false; /* Ignore hit - continue traversal */
}
# endif
if (intersection_skip_self_shadow(payload->ray_self, object_id, prim_id_global)) {
return false;
}
const float ray_time = payload->ray_time;
if ((primitive_type & PRIMITIVE_MOTION_POINT) && kernel_data.bvh.use_bvh_steps) {
const int time_offset = kernel_data_fetch(prim_time_offset, object_id);
const float2 prims_time = kernel_data_fetch(prims_time, hit.primID + time_offset);
if (ray_time < prims_time.x || ray_time > prims_time.y) {
return false;
}
}
Intersection isect;
const bool b_hit = point_intersect(kg,
&isect,
ray.origin,
ray.direction,
ray.minT,
ray.maxT,
object_id,
prim_id_global,
ray_time,
primitive_type);
if (b_hit) {
hit.uv.x = isect.u;
hit.uv.y = isect.v;
hit.t = isect.t;
}
return b_hit;
#else
return false;
#endif
}
/* --------------------------------------------------------------------
* Intersection filters.
*/
ccl_device_inline bool closest_intersection_filter(const hiprtRay &ray,
BVHPayload *payload,
const hiprtHit &hit)
{
KernelGlobals kg = nullptr;
const int object_id = kernel_data_fetch(user_instance_id, hit.instanceID);
const int prim_offset = kernel_data_fetch(object_prim_offset, object_id);
const int prim = hit.primID + prim_offset;
#ifdef __SHADOW_LINKING__
if (intersection_skip_shadow_link(kg, payload->ray_self, object_id)) {
return true; /* Ignore hit - continue traversal. */
}
#endif
if (intersection_skip_self_shadow(payload->ray_self, object_id, prim)) {
return true; /* Ignore hit - continue traversal. */
}
return false;
}
ccl_device_inline bool shadow_intersection_filter(const hiprtRay &ray,
BVHShadowAllPayload *payload,
const hiprtHit &hit)
{
KernelGlobals kg = nullptr;
Intersection isect;
set_intersect_point(hit, &isect);
return bvh_shadow_all_anyhit_filter<ISECT_TEST_ALL, PRIMITIVE_ALL & ~PRIMITIVE_CURVE>(
kg, payload->state, *payload, payload->ray_self, payload->ray_visibility, isect);
}
ccl_device_inline bool shadow_intersection_filter_curve(const hiprtRay &ray,
BVHShadowAllPayload *payload,
const hiprtHit &hit)
{
KernelGlobals kg = nullptr;
Intersection isect;
set_intersect_point(hit, &isect);
return bvh_shadow_all_anyhit_filter<ISECT_TEST_ALL, PRIMITIVE_CURVE>(
kg, payload->state, *payload, payload->ray_self, payload->ray_visibility, isect);
}
ccl_device_inline bool local_intersection_filter(const hiprtRay &ray,
LocalPayload *payload,
const hiprtHit &hit)
{
#ifdef __BVH_LOCAL__
KernelGlobals kg = nullptr;
const int object_id = payload->local_object;
const uint max_hits = payload->max_hits;
/* Triangle primitive uses hardware intersection, other primitives do custom intersection
* which does reservoir sampling for intersections. For the custom primitives only check
* whether we can stop traversal early on. The rest of the checks here only do for the
* regular triangles. */
const int primitive_type = kernel_data_fetch(objects, object_id).primitive_type;
if (primitive_type != PRIMITIVE_TRIANGLE) {
if (max_hits == 0) {
return false;
}
return true;
}
const int prim_offset = kernel_data_fetch(object_prim_offset, object_id);
const int prim = hit.primID + prim_offset;
# ifndef __RAY_OFFSET__
if (intersection_skip_self_local(payload->self, prim)) {
return true; /* Continue search. */
}
# endif
if (max_hits == 0) {
return false; /* Stop search. */
}
const int hit_index = local_intersect_get_record_index(
payload->local_isect, hit.t, payload->lcg_state, max_hits);
if (hit_index == -1) {
return true; /* Continue search. */
}
Intersection *isect = &payload->local_isect->hits[hit_index];
isect->t = hit.t;
isect->u = hit.uv.x;
isect->v = hit.uv.y;
isect->prim = prim;
isect->object = object_id;
isect->type = primitive_type;
payload->local_isect->Ng[hit_index] = hit.normal;
return true;
#else
return false;
#endif
}
ccl_device_inline bool volume_triangle_intersection_filter(const hiprtRay &ray,
BVHPayload *payload,
const hiprtHit &hit)
{
KernelGlobals kg = nullptr;
const int object = kernel_data_fetch(user_instance_id, hit.instanceID);
const int prim_offset = kernel_data_fetch(object_prim_offset, object);
const int prim = hit.primID + prim_offset;
if (bvh_volume_anyhit_triangle_filter(
kg, object, prim, payload->ray_self, payload->ray_visibility))
{
return true;
}
return false;
}
HIPRT_DEVICE bool intersectFunc(const uint geom_type,
const uint ray_type,
const hiprtFuncTableHeader &tableHeader,
const hiprtRay &ray,
void *payload,
hiprtHit &hit)
{
const uint index = tableHeader.numGeomTypes * ray_type + geom_type;
switch (index) {
case Curve_Intersect_Function:
case Curve_Intersect_Shadow:
return curve_custom_intersect(ray, (BVHPayload *)payload, hit);
case Motion_Triangle_Intersect_Function:
case Motion_Triangle_Intersect_Shadow:
return motion_triangle_custom_intersect(ray, (BVHPayload *)payload, hit);
case Motion_Triangle_Intersect_Local:
return motion_triangle_custom_local_intersect(ray, (LocalPayload *)payload, hit);
case Motion_Triangle_Intersect_Volume:
return motion_triangle_custom_volume_intersect(ray, (BVHPayload *)payload, hit);
case Point_Intersect_Function:
case Point_Intersect_Shadow:
return point_custom_intersect(ray, (BVHPayload *)payload, hit);
default:
break;
}
return false;
}
HIPRT_DEVICE bool filterFunc(const uint geom_type,
const uint ray_type,
const hiprtFuncTableHeader &tableHeader,
const hiprtRay &ray,
void *payload,
const hiprtHit &hit)
{
const uint index = tableHeader.numGeomTypes * ray_type + geom_type;
switch (index) {
case Triangle_Filter_Closest:
return closest_intersection_filter(ray, (BVHPayload *)payload, hit);
case Curve_Filter_Shadow:
return shadow_intersection_filter_curve(ray, (BVHShadowAllPayload *)payload, hit);
case Triangle_Filter_Shadow:
case Motion_Triangle_Filter_Shadow:
case Point_Filter_Shadow:
return shadow_intersection_filter(ray, (BVHShadowAllPayload *)payload, hit);
case Triangle_Filter_Local:
case Motion_Triangle_Filter_Local:
return local_intersection_filter(ray, (LocalPayload *)payload, hit);
case Triangle_Filter_Volume:
return volume_triangle_intersection_filter(ray, (BVHPayload *)payload, hit);
case Motion_Triangle_Filter_Volume:
/* Motion triangle volume filtering is done in the custom intersection function. */
return false;
default:
break;
}
return false;
}
/* --------------------------------------------------------------------
* BVH functions.
*/
ccl_device_intersect bool scene_intersect(KernelGlobals kg,
const ccl_private Ray *ray,
const uint visibility,
ccl_private Intersection *isect)
{
isect->t = ray->tmax;
isect->u = 0.0f;
isect->v = 0.0f;
isect->prim = PRIM_NONE;
isect->object = OBJECT_NONE;
isect->type = PRIMITIVE_NONE;
if (!intersection_ray_valid(ray)) {
isect->t = ray->tmax;
isect->type = PRIMITIVE_NONE;
return false;
}
if (kernel_data.device_bvh == 0) {
return false;
}
hiprtRay ray_hip;
set_hiprt_ray(*ray, ray_hip);
BVHPayload payload;
payload.ray_self = ray->self;
payload.ray_visibility = visibility;
payload.ray_time = ray->time;
Stack stack(kg->global_stack_buffer, kg->shared_stack);
Instance_Stack instance_stack;
hiprtHit hit;
if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE) {
hiprtSceneTraversalAnyHitCustomStack traversal((hiprtScene)kernel_data.device_bvh,
ray_hip,
stack,
instance_stack,
visibility,
hiprtTraversalHintDefault,
&payload,
kernel_params.table_closest_intersect,
0 /* RAY_TYPE */,
ray->time);
hit = traversal.getNextHit();
}
else {
hiprtSceneTraversalClosestCustomStack traversal((hiprtScene)kernel_data.device_bvh,
ray_hip,
stack,
instance_stack,
visibility,
hiprtTraversalHintDefault,
&payload,
kernel_params.table_closest_intersect,
0 /* RAY_TYPE */,
ray->time);
hit = traversal.getNextHit();
}
if (hit.hasHit()) {
set_intersect_point(hit, isect);
return true;
}
return false;
}
ccl_device_intersect bool scene_intersect_shadow(KernelGlobals kg,
const ccl_private Ray *ray,
const uint visibility)
{
Intersection isect;
return scene_intersect(kg, ray, visibility, &isect);
}
#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)
{
if (local_isect != nullptr) {
local_isect->num_hits = 0;
}
if (!intersection_ray_valid(ray)) {
return false;
}
const int primitive_type = kernel_data_fetch(objects, local_object).primitive_type;
if (!(primitive_type & PRIMITIVE_TRIANGLE)) {
/* Local intersection functions are only considering triangle and motion triangle primitives.
* If the local intersection is requested from other primitives (curve or point cloud) perform
* an early return to avoid tree traversal with no primitive intersection. */
return false;
}
float3 P = ray->P;
float3 dir = bvh_clamp_direction(ray->D);
float3 idir = bvh_inverse_direction(dir);
const uint object_flag = kernel_data_fetch(object_flag, local_object);
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
# ifdef __OBJECT_MOTION__
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
# else
bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
# endif
}
hiprtRay ray_hip;
ray_hip.origin = P;
ray_hip.direction = dir;
ray_hip.maxT = ray->tmax;
ray_hip.minT = ray->tmin;
LocalPayload payload = {0};
payload.self = ray->self;
payload.ray_time = ray->time;
payload.local_object = local_object;
payload.max_hits = max_hits;
payload.lcg_state = lcg_state;
payload.local_isect = local_isect;
Stack stack(kg->global_stack_buffer, kg->shared_stack);
Instance_Stack instance_stack;
hiprtGeometry local_geom = (hiprtGeometry)(kernel_data_fetch(blas_ptr, local_object));
hiprtHit hit;
if (primitive_type == PRIMITIVE_MOTION_TRIANGLE) {
/* Motion triangle BVH uses custom primitives which requires custom traversal. */
hiprtGeomCustomTraversalAnyHitCustomStack traversal(local_geom,
ray_hip,
stack,
hiprtTraversalHintDefault,
&payload,
kernel_params.table_local_intersect,
2);
hit = traversal.getNextHit();
}
else {
hiprtGeomTraversalAnyHitCustomStack traversal(local_geom,
ray_hip,
stack,
hiprtTraversalHintDefault,
&payload,
kernel_params.table_local_intersect,
2);
hit = traversal.getNextHit();
}
return hit.hasHit();
}
#endif /*__BVH_LOCAL__ */
#ifdef __TRANSPARENT_SHADOWS__
ccl_device_inline void scene_intersect_shadow_all_hiprt(
KernelGlobals kg,
const ccl_private Ray *ccl_restrict ray,
ccl_private BVHShadowAllPayload &ccl_restrict payload)
{
hiprtRay ray_hip;
set_hiprt_ray(*ray, ray_hip);
Stack stack(kg->global_stack_buffer, kg->shared_stack);
Instance_Stack instance_stack;
hiprtSceneTraversalAnyHitCustomStack traversal((hiprtScene)kernel_data.device_bvh,
ray_hip,
stack,
instance_stack,
payload.ray_visibility,
hiprtTraversalHintDefault,
&payload,
kernel_params.table_shadow_intersect,
1 /* RAY_TYPE */,
ray->time);
const hiprtHit hit = traversal.getNextHit();
(void)hit;
}
#endif /* __TRANSPARENT_SHADOWS__ */
#ifdef __VOLUME__
ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
const ccl_private Ray *ray,
ccl_private Intersection *isect,
const uint visibility)
{
isect->t = ray->tmax;
isect->u = 0.0f;
isect->v = 0.0f;
isect->prim = PRIM_NONE;
isect->object = OBJECT_NONE;
isect->type = PRIMITIVE_NONE;
if (!intersection_ray_valid(ray)) {
return false;
}
hiprtRay ray_hip;
set_hiprt_ray(*ray, ray_hip);
BVHPayload payload;
payload.ray_self = ray->self;
payload.ray_visibility = visibility;
payload.ray_time = ray->time;
Stack stack(kg->global_stack_buffer, kg->shared_stack);
Instance_Stack instance_stack;
hiprtSceneTraversalClosestCustomStack traversal((hiprtScene)kernel_data.device_bvh,
ray_hip,
stack,
instance_stack,
visibility,
hiprtTraversalHintDefault,
&payload,
kernel_params.table_volume_intersect,
3 /* RAY_TYPE */,
ray->time);
const hiprtHit hit = traversal.getNextHit();
if (hit.hasHit()) {
set_intersect_point(hit, isect);
return true;
}
return false;
}
#endif /* __VOLUME__ */
CCL_NAMESPACE_END

View File

@@ -0,0 +1,153 @@
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
/* Constant Globals */
#pragma once
#include "kernel/types.h"
#include "kernel/integrator/state.h"
#include "kernel/util/profiler.h" // IWYU pragma: export
#include "util/color.h" // IWYU pragma: export
#include "util/types_image.h" // IWYU pragma: export
/* The size of global stack available to each thread (memory reserved for each thread in
* global_stack_buffer). */
#define HIPRT_THREAD_STACK_SIZE 64
/* LDS (Local Data Storage) allocation for each thread, the number is obtained empirically. */
#define HIPRT_SHARED_STACK_SIZE 24
/* HIPRT_THREAD_GROUP_SIZE is the number of threads per work group for intersection kernels
* The default number of threads per work-group is 1024, however, since HIP RT intersection kernels
* use local memory, and the local memory size in those kernels scales up with the number of
* threads, the number of threads to is scaled down to 256 to avoid going over maximum local memory
* and to strike a balance between memory access and the number of waves.
*
* Total local stack size would be number of threads * HIPRT_SHARED_STACK_SIZE. */
#define HIPRT_THREAD_GROUP_SIZE 256
CCL_NAMESPACE_BEGIN
struct KernelGlobalsGPU {
hiprtGlobalStackBuffer global_stack_buffer;
hiprtSharedStackBuffer shared_stack;
};
using KernelGlobals = ccl_global KernelGlobalsGPU *ccl_restrict;
/* This macro allocates shared memory and to pass the shared memory down to intersection functions
* KernelGlobals is used. */
#define HIPRT_INIT_KERNEL_GLOBAL() \
ccl_gpu_shared int shared_stack[HIPRT_SHARED_STACK_SIZE * HIPRT_THREAD_GROUP_SIZE]; \
ccl_global KernelGlobalsGPU kg_gpu; \
KernelGlobals kg = &kg_gpu; \
kg->shared_stack.stackData = &shared_stack[0]; \
kg->shared_stack.stackSize = HIPRT_SHARED_STACK_SIZE; \
kg->global_stack_buffer = stack_buffer;
struct KernelParamsHIPRT {
KernelData data;
#define KERNEL_DATA_ARRAY(type, name) const type *name;
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) type *name;
KERNEL_DATA_ARRAY(int, user_instance_id)
KERNEL_DATA_ARRAY(uint64_t, blas_ptr)
KERNEL_DATA_ARRAY(int2, custom_prim_info)
KERNEL_DATA_ARRAY(int2, custom_prim_info_offset)
KERNEL_DATA_ARRAY(float2, prims_time)
KERNEL_DATA_ARRAY(int, prim_time_offset)
#include "kernel/data_arrays.h"
/* Integrator state */
IntegratorStateGPU integrator_state;
hiprtFuncTable table_closest_intersect;
hiprtFuncTable table_shadow_intersect;
hiprtFuncTable table_local_intersect;
hiprtFuncTable table_volume_intersect;
};
/* Intersection_Function_Table_Index defines index values to retrieve custom intersection
* functions from function table. */
enum Intersection_Function_Table_Index {
// Triangles use the intersection function provided by HIP RT and don't need custom intersection
// functions
// Custom intersection functions for closest intersect.
Curve_Intersect_Function = 1, // Custom intersection for curves
Motion_Triangle_Intersect_Function, // Custom intersection for triangles with vertex motion blur
// attributes.
Point_Intersect_Function, // Custom intersection for point cloud.
// Custom intersection functions for shadow rendering are the same as the function for closest
// intersect.
// However, the table indices are different
Triangle_Intersect_Shadow_None,
Curve_Intersect_Shadow,
Motion_Triangle_Intersect_Shadow,
Point_Intersect_Shadow,
// Custom intersection functions for subsurface scattering.
// Only motion triangles have valid custom intersection function
Triangle_Intersect_Local_None,
Curve_Intersect_Local_None,
Motion_Triangle_Intersect_Local,
Point_Intersect_Local_None,
// Custom intersection functions for volume rendering.
// Only motion triangles have valid custom intersection function
Triangle_Intersect_Volume_None,
Curve_Intersect_Volume_None,
Motion_Triangle_Intersect_Volume,
Point_Intersect_Volume_None,
};
// Filter functions, filter hits, i.e. test whether a hit should be accepted or not, and whether
// traversal should stop or continue.
enum Filter_Function_Table_Index {
Triangle_Filter_Closest = 0, // Filter function for triangles for closest intersect, no custom
// intersection function is needed.
Curve_Filter_Opaque_None, // No filter function is needed and everything is handled in the
// intersection function.
Motion_Triangle_Filter_Opaque_None, // No filter function is needed and everything is handled in
// intersection function.
Point_Filter_Opaque_Non, // No filter function is needed.
// Filter function for all primitives for shadow intersection.
// All primitives use the same function but each has a different index in the table.
Triangle_Filter_Shadow,
Curve_Filter_Shadow,
Motion_Triangle_Filter_Shadow,
Point_Filter_Shadow,
// Filter functions for subsurface scattering. Triangles and motion triangles need function
// assignment. They indices for triangles and motion triangles point to the same function. Points
// and curves dont need any function since subsurface scattering is not applied on either.
Triangle_Filter_Local, // Filter functions for triangles
Curve_Filter_Local_None, // Subsurface scattering is not applied on curves, no filter function
// is
// needed.
Motion_Triangle_Filter_Local,
Point_Filter_Local_None,
// Filter functions for volume rendering.
// Volume rendering only applies to triangles and motion triangles.
// Triangles and motion triangles use the same filter functions for volume rendering
Triangle_Filter_Volume,
Curve_Filter_Volume_None,
Motion_Triangle_Filter_Volume,
Point_Filter_Volume_None,
};
#ifdef __KERNEL_GPU__
__constant__ KernelParamsHIPRT kernel_params;
typedef hiprtGlobalStack Stack;
typedef hiprtEmptyInstanceStack Instance_Stack;
#endif
/* Abstraction macros */
#define kernel_data kernel_params.data
#define kernel_data_fetch(name, index) kernel_params.name[(index)]
#define kernel_data_write(name, index, value) kernel_params.name[(index)] = (value)
#define kernel_data_array(name) (kernel_params.name)
#define kernel_integrator_state kernel_params.integrator_state
CCL_NAMESPACE_END

View File

@@ -0,0 +1,140 @@
/* SPDX-FileCopyrightText: 2011-2023 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#ifdef __HIP_DEVICE_COMPILE__
# include "kernel/device/hip/compat.h"
# include "kernel/device/hip/config.h"
# include <hiprt/impl/hiprt_device_impl.h>
# include "kernel/device/hiprt/globals.h"
# include "kernel/device/gpu/image.h"
# include "kernel/tables.h"
# include "kernel/integrator/state.h"
# include "kernel/integrator/state_flow.h"
# include "kernel/integrator/state_util.h"
# include "kernel/integrator/intersect_closest.h"
# include "kernel/integrator/intersect_dedicated_light.h"
# include "kernel/integrator/intersect_mnee.h"
# include "kernel/integrator/intersect_shadow.h"
# include "kernel/integrator/intersect_subsurface.h"
# include "kernel/integrator/intersect_volume_stack.h"
# include "kernel/integrator/shade_surface.h"
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_intersect_closest,
const ccl_global int *path_index_array,
ccl_global float *render_buffer,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_closest(kg, state, render_buffer));
}
}
ccl_gpu_kernel_postfix
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_intersect_shadow,
const ccl_global int *path_index_array,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_shadow(kg, state));
}
}
ccl_gpu_kernel_postfix
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_intersect_subsurface,
const ccl_global int *path_index_array,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_subsurface(kg, state));
}
}
ccl_gpu_kernel_postfix
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_intersect_volume_stack,
const ccl_global int *path_index_array,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_volume_stack(kg, state));
}
}
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_intersect_dedicated_light,
const ccl_global int *path_index_array,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_dedicated_light(kg, state));
}
}
ccl_gpu_kernel_postfix
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_shade_surface_raytrace,
const ccl_global int *path_index_array,
ccl_global float *render_buffer,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_shade_surface_raytrace(kg, state, render_buffer));
}
}
ccl_gpu_kernel_postfix
ccl_gpu_kernel_threads(GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS)
ccl_gpu_kernel_signature(integrator_intersect_mnee,
const ccl_global int *path_index_array,
const int work_size,
ccl_global hiprtGlobalStackBuffer stack_buffer)
{
const int global_index = ccl_gpu_global_id_x();
if (global_index < work_size) {
HIPRT_INIT_KERNEL_GLOBAL()
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
ccl_gpu_kernel_call(integrator_intersect_mnee(kg, state));
}
}
ccl_gpu_kernel_postfix
#endif /* __HIP_DEVICE_COMPILE__ */