Add Chromium-only Blender WebEngine parity work
This commit is contained in:
70
blender-5.2.0/intern/cycles/kernel/device/cpu/CMakeLists.txt
Normal file
70
blender-5.2.0/intern/cycles/kernel/device/cpu/CMakeLists.txt
Normal file
@@ -0,0 +1,70 @@
|
||||
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(INC
|
||||
../../..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_CPU
|
||||
globals.cpp
|
||||
kernel.cpp
|
||||
kernel_avx2.cpp
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_CPU_HEADERS
|
||||
bvh.h
|
||||
compat.h
|
||||
image.h
|
||||
globals.h
|
||||
kernel.h
|
||||
kernel_arch.h
|
||||
kernel_arch_impl.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PUBLIC cycles_util
|
||||
)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CPU module.
|
||||
|
||||
include_directories(${INC})
|
||||
include_directories(SYSTEM ${INC_SYS})
|
||||
|
||||
if(DEFINED CYCLES_KERNEL_FLAGS)
|
||||
set_source_files_properties(kernel.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_KERNEL_FLAGS}")
|
||||
endif()
|
||||
|
||||
if(CXX_HAS_AVX2 AND CXX_HAS_F16C)
|
||||
set_source_files_properties(kernel_avx2.cpp PROPERTIES COMPILE_FLAGS "${CYCLES_AVX2_F16C_FLAGS}")
|
||||
endif()
|
||||
|
||||
# Warnings to avoid using doubles in the kernel.
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
add_check_cxx_compiler_flags(
|
||||
CMAKE_CXX_FLAGS
|
||||
_has_cxxflag_float_conversion "-Werror=float-conversion"
|
||||
_has_cxxflag_double_promotion "-Werror=double-promotion"
|
||||
)
|
||||
unset(_has_cxxflag_float_conversion)
|
||||
unset(_has_cxxflag_double_promotion)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_OSL)
|
||||
list(APPEND LIB
|
||||
PUBLIC cycles_kernel_osl
|
||||
)
|
||||
endif()
|
||||
|
||||
cycles_add_library(cycles_kernel_cpu "${LIB}"
|
||||
${SRC_KERNEL_DEVICE_CPU}
|
||||
${SRC_KERNEL_DEVICE_CPU_HEADERS}
|
||||
)
|
||||
cycles_set_solution_folder(cycles_kernel_cpu)
|
||||
|
||||
source_group("device\\cpu" FILES ${SRC_KERNEL_DEVICE_CPU} ${SRC_KERNEL_DEVICE_CPU_HEADERS})
|
||||
660
blender-5.2.0/intern/cycles/kernel/device/cpu/bvh.h
Normal file
660
blender-5.2.0/intern/cycles/kernel/device/cpu/bvh.h
Normal file
@@ -0,0 +1,660 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* CPU Embree implementation of ray-scene intersection. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <embree4/rtcore_geometry.h>
|
||||
#include <embree4/rtcore_ray.h>
|
||||
#include <embree4/rtcore_scene.h>
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
# include "kernel/device/oneapi/compat.h"
|
||||
# include "kernel/device/oneapi/globals.h"
|
||||
#else
|
||||
# include "kernel/device/cpu/compat.h"
|
||||
# include "kernel/device/cpu/globals.h"
|
||||
#endif
|
||||
|
||||
#include "kernel/bvh/intersect_filter.h"
|
||||
#include "kernel/bvh/types.h"
|
||||
#include "kernel/bvh/util.h"
|
||||
#include "kernel/geom/object.h"
|
||||
#include "kernel/integrator/state.h"
|
||||
#include "kernel/integrator/state_util.h"
|
||||
#include "kernel/sample/lcg.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
using numhit_t = uint16_t;
|
||||
#else
|
||||
using numhit_t = uint32_t;
|
||||
#endif
|
||||
|
||||
/* Before Embree 4.4, the so-called Traversable functionality was exposed through Scene API.
|
||||
* So, in order to simplify code between different versions, we are defining the traversable class
|
||||
* and calls for older Embree versions as well. */
|
||||
#if RTC_VERSION < 40400
|
||||
# define RTCTraversable RTCScene
|
||||
# define rtcGetGeometryUserDataFromTraversable rtcGetGeometryUserDataFromScene
|
||||
# define rtcTraversableIntersect1 rtcIntersect1
|
||||
# define rtcTraversableOccluded1 rtcOccluded1
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
# define CYCLES_EMBREE_USED_FEATURES \
|
||||
(kernel_handler.get_specialization_constant<oneapi_embree_features>())
|
||||
#else
|
||||
# define CYCLES_EMBREE_USED_FEATURES \
|
||||
(RTCFeatureFlags)(RTC_FEATURE_FLAG_TRIANGLE | RTC_FEATURE_FLAG_INSTANCE | \
|
||||
RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS | RTC_FEATURE_FLAG_POINT | \
|
||||
RTC_FEATURE_FLAG_MOTION_BLUR | RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE | \
|
||||
RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE | \
|
||||
RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE)
|
||||
#endif
|
||||
|
||||
#define EMBREE_IS_HAIR(x) (x & 1)
|
||||
|
||||
/* Intersection context. */
|
||||
|
||||
struct CCLFirstHitContext : public RTCRayQueryContext {
|
||||
KernelGlobals kg;
|
||||
/* For avoiding self intersections */
|
||||
const Ray *ray;
|
||||
};
|
||||
|
||||
struct CCLShadowContext : public RTCRayQueryContext {
|
||||
#if defined(__KERNEL_ONEAPI__)
|
||||
ONEAPIKernelContext *oneapi_kernel_context;
|
||||
#else
|
||||
KernelGlobals kg;
|
||||
#endif
|
||||
|
||||
BVHShadowAllPayload *payload;
|
||||
};
|
||||
|
||||
struct CCLLocalContext : public RTCRayQueryContext {
|
||||
KernelGlobals kg;
|
||||
const Ray *ray;
|
||||
numhit_t max_hits;
|
||||
int local_object_id;
|
||||
LocalIntersection *local_isect;
|
||||
uint *lcg_state;
|
||||
bool is_sss;
|
||||
};
|
||||
|
||||
struct CCLVolumeContext : public RTCRayQueryContext {
|
||||
KernelGlobals kg;
|
||||
const Ray *ray;
|
||||
#ifdef __VOLUME_RECORD_ALL__
|
||||
numhit_t max_hits;
|
||||
#endif
|
||||
numhit_t num_hits;
|
||||
Intersection *vol_isect;
|
||||
};
|
||||
|
||||
/* Utilities. */
|
||||
|
||||
ccl_device_inline void kernel_embree_setup_ray(const Ray &ray,
|
||||
RTCRay &rtc_ray,
|
||||
const uint visibility)
|
||||
{
|
||||
rtc_ray.org_x = ray.P.x;
|
||||
rtc_ray.org_y = ray.P.y;
|
||||
rtc_ray.org_z = ray.P.z;
|
||||
rtc_ray.dir_x = ray.D.x;
|
||||
rtc_ray.dir_y = ray.D.y;
|
||||
rtc_ray.dir_z = ray.D.z;
|
||||
rtc_ray.tnear = ray.tmin;
|
||||
rtc_ray.tfar = ray.tmax;
|
||||
rtc_ray.time = ray.time;
|
||||
rtc_ray.mask = visibility;
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray,
|
||||
RTCRayHit &rayhit,
|
||||
const uint visibility)
|
||||
{
|
||||
kernel_embree_setup_ray(ray, rayhit.ray, visibility);
|
||||
rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
}
|
||||
|
||||
ccl_device_inline int kernel_embree_get_hit_object(const RTCHit *hit)
|
||||
{
|
||||
return (hit->instID[0] != RTC_INVALID_GEOMETRY_ID ? hit->instID[0] : hit->geomID) / 2;
|
||||
}
|
||||
|
||||
ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg,
|
||||
const RTCHit *hit,
|
||||
const Ray *ray,
|
||||
const intptr_t prim_offset)
|
||||
{
|
||||
const int object = kernel_embree_get_hit_object(hit);
|
||||
|
||||
int prim;
|
||||
if ((ray->self.object == object) || (ray->self.light_object == object)) {
|
||||
prim = hit->primID + prim_offset;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool is_hair = hit->geomID & 1;
|
||||
if (is_hair) {
|
||||
prim = kernel_data_fetch(curve_segments, prim).prim;
|
||||
}
|
||||
|
||||
return intersection_skip_self_shadow(ray->self, object, prim);
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
|
||||
const RTCRay *ray,
|
||||
const RTCHit *hit,
|
||||
Intersection *isect,
|
||||
const intptr_t prim_offset)
|
||||
{
|
||||
isect->t = ray->tfar;
|
||||
isect->prim = hit->primID + prim_offset;
|
||||
isect->object = kernel_embree_get_hit_object(hit);
|
||||
|
||||
const bool is_hair = hit->geomID & 1;
|
||||
if (is_hair) {
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, isect->prim);
|
||||
isect->type = segment.type;
|
||||
isect->prim = segment.prim;
|
||||
isect->u = hit->u;
|
||||
isect->v = hit->v;
|
||||
}
|
||||
else {
|
||||
isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
|
||||
isect->u = hit->u;
|
||||
isect->v = hit->v;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
|
||||
const RTCRay *ray,
|
||||
const RTCHit *hit,
|
||||
Intersection *isect)
|
||||
{
|
||||
intptr_t prim_offset;
|
||||
if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
|
||||
RTCTraversable inst_scene = (RTCTraversable)rtcGetGeometryUserDataFromTraversable(
|
||||
kernel_data.device_bvh, hit->instID[0]);
|
||||
prim_offset = intptr_t(rtcGetGeometryUserDataFromTraversable(inst_scene, hit->geomID));
|
||||
}
|
||||
else {
|
||||
prim_offset = intptr_t(
|
||||
rtcGetGeometryUserDataFromTraversable(kernel_data.device_bvh, hit->geomID));
|
||||
}
|
||||
kernel_embree_convert_hit(kg, ray, hit, isect, prim_offset);
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_embree_convert_sss_hit(KernelGlobals kg,
|
||||
const RTCRay *ray,
|
||||
const RTCHit *hit,
|
||||
Intersection *isect,
|
||||
const int object,
|
||||
const intptr_t prim_offset)
|
||||
{
|
||||
isect->u = hit->u;
|
||||
isect->v = hit->v;
|
||||
isect->t = ray->tfar;
|
||||
isect->prim = hit->primID + prim_offset;
|
||||
isect->object = object;
|
||||
isect->type = kernel_data_fetch(objects, object).primitive_type;
|
||||
}
|
||||
|
||||
/* Ray filter functions. */
|
||||
|
||||
/* This gets called by Embree at every valid ray/object intersection.
|
||||
* Things like recording subsurface or shadow hits for later evaluation
|
||||
* as well as filtering for volume objects happen here.
|
||||
* Cycles' own BVH does that directly inside the traversal calls. */
|
||||
ccl_device_forceinline void kernel_embree_filter_intersection_func_impl(
|
||||
const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
KernelGlobalsGPU *kg = nullptr;
|
||||
#else
|
||||
const ThreadKernelGlobalsCPU *kg = ctx->kg;
|
||||
#endif
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
if (kernel_embree_is_self_intersection(
|
||||
kg, hit, cray, reinterpret_cast<intptr_t>(args->geometryUserPtr)))
|
||||
{
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __SHADOW_LINKING__
|
||||
if (intersection_skip_shadow_link(kg, cray->self, kernel_embree_get_hit_object(hit))) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This gets called by Embree at every valid ray/object intersection.
|
||||
* Things like recording subsurface or shadow hits for later evaluation
|
||||
* as well as filtering for volume objects happen here.
|
||||
* Cycles' own BVH does that directly inside the traversal calls.
|
||||
*/
|
||||
ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
|
||||
const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
const RTCHit *hit = (RTCHit *)args->hit;
|
||||
|
||||
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
|
||||
BVHShadowAllPayload &payload = *ctx->payload;
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
KernelGlobalsGPU *kg = nullptr;
|
||||
#else
|
||||
const ThreadKernelGlobalsCPU *kg = ctx->kg;
|
||||
#endif
|
||||
|
||||
Intersection isect;
|
||||
kernel_embree_convert_hit(
|
||||
kg, ray, hit, &isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
|
||||
|
||||
if (!bvh_shadow_all_anyhit_filter<ISECT_TEST_ALL & ~ISECT_TEST_VISIBILITY_FLAG>(
|
||||
kg, payload.state, payload, payload.base.ray_self, 0, isect))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*args->valid = 0;
|
||||
}
|
||||
|
||||
ccl_device_forceinline void kernel_embree_filter_occluded_local_func_impl(
|
||||
const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
KernelGlobalsGPU *kg = nullptr;
|
||||
#else
|
||||
const ThreadKernelGlobalsCPU *kg = ctx->kg;
|
||||
#endif
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
/* Check if it's hitting the correct object. */
|
||||
Intersection current_isect;
|
||||
if (ctx->is_sss) {
|
||||
kernel_embree_convert_sss_hit(kg,
|
||||
ray,
|
||||
hit,
|
||||
¤t_isect,
|
||||
ctx->local_object_id,
|
||||
reinterpret_cast<intptr_t>(args->geometryUserPtr));
|
||||
}
|
||||
else {
|
||||
kernel_embree_convert_hit(
|
||||
kg, ray, hit, ¤t_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
|
||||
if (ctx->local_object_id != current_isect.object) {
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (intersection_skip_self_local(cray->self, current_isect.prim)) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* No intersection information requested, just return a hit. */
|
||||
if (ctx->max_hits == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ignore curves. */
|
||||
if (EMBREE_IS_HAIR(hit->geomID)) {
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
LocalIntersection *local_isect = ctx->local_isect;
|
||||
int hit_idx = 0;
|
||||
|
||||
if (ctx->lcg_state) {
|
||||
/* See triangle_intersect_subsurface() for the native equivalent. */
|
||||
for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
|
||||
if (local_isect->hits[i].t == ray->tfar) {
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
local_isect->num_hits++;
|
||||
|
||||
if (local_isect->num_hits <= ctx->max_hits) {
|
||||
hit_idx = local_isect->num_hits - 1;
|
||||
}
|
||||
else {
|
||||
/* reservoir sampling: if we are at the maximum number of
|
||||
* hits, randomly replace element or skip it */
|
||||
hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
|
||||
|
||||
if (hit_idx >= ctx->max_hits) {
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Record closest intersection only. */
|
||||
if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
local_isect->num_hits = 1;
|
||||
}
|
||||
|
||||
/* record intersection */
|
||||
local_isect->hits[hit_idx] = current_isect;
|
||||
local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
}
|
||||
|
||||
ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func_impl(
|
||||
const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
KernelGlobalsGPU *kg = nullptr;
|
||||
#else
|
||||
const ThreadKernelGlobalsCPU *kg = ctx->kg;
|
||||
#endif
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
#ifdef __VOLUME_RECORD_ALL__
|
||||
/* Append the intersection to the end of the array. */
|
||||
if (ctx->num_hits < ctx->max_hits) {
|
||||
#endif
|
||||
Intersection current_isect;
|
||||
kernel_embree_convert_hit(
|
||||
kg, ray, hit, ¤t_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
|
||||
|
||||
if (bvh_volume_anyhit_triangle_filter<false>(
|
||||
kg, current_isect.object, current_isect.prim, cray->self, 0))
|
||||
{
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Intersection *isect = &ctx->vol_isect[ctx->num_hits];
|
||||
++ctx->num_hits;
|
||||
*isect = current_isect;
|
||||
#ifdef __VOLUME_RECORD_ALL__
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
/* Static wrappers so we can call the callbacks from out side the ONEAPIKernelContext class */
|
||||
RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
|
||||
kernel_embree_filter_intersection_func_static(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
|
||||
ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
|
||||
context->kernel_embree_filter_intersection_func_impl(args);
|
||||
}
|
||||
|
||||
RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
|
||||
kernel_embree_filter_occluded_shadow_all_func_static(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
|
||||
ONEAPIKernelContext *context = ctx->oneapi_kernel_context;
|
||||
context->kernel_embree_filter_occluded_shadow_all_func_impl(args);
|
||||
}
|
||||
|
||||
RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
|
||||
kernel_embree_filter_occluded_local_func_static(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
|
||||
ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
|
||||
context->kernel_embree_filter_occluded_local_func_impl(args);
|
||||
}
|
||||
|
||||
RTC_SYCL_INDIRECTLY_CALLABLE static void ccl_always_inline
|
||||
kernel_embree_filter_occluded_volume_all_func_static(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
|
||||
ONEAPIKernelContext *context = static_cast<ONEAPIKernelContext *>(ctx->kg);
|
||||
context->kernel_embree_filter_occluded_volume_all_func_impl(args);
|
||||
}
|
||||
|
||||
# define kernel_embree_filter_intersection_func \
|
||||
ONEAPIKernelContext::kernel_embree_filter_intersection_func_static
|
||||
# define kernel_embree_filter_occluded_shadow_all_func \
|
||||
ONEAPIKernelContext::kernel_embree_filter_occluded_shadow_all_func_static
|
||||
# define kernel_embree_filter_occluded_local_func \
|
||||
ONEAPIKernelContext::kernel_embree_filter_occluded_local_func_static
|
||||
# define kernel_embree_filter_occluded_volume_all_func \
|
||||
ONEAPIKernelContext::kernel_embree_filter_occluded_volume_all_func_static
|
||||
#else
|
||||
# define kernel_embree_filter_intersection_func kernel_embree_filter_intersection_func_impl
|
||||
# define kernel_embree_filter_occluded_shadow_all_func \
|
||||
kernel_embree_filter_occluded_shadow_all_func_impl
|
||||
# define kernel_embree_filter_occluded_local_func kernel_embree_filter_occluded_local_func_impl
|
||||
# define kernel_embree_filter_occluded_volume_all_func \
|
||||
kernel_embree_filter_occluded_volume_all_func_impl
|
||||
#endif
|
||||
|
||||
/* Scene intersection. */
|
||||
|
||||
ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility,
|
||||
ccl_private Intersection *isect)
|
||||
{
|
||||
isect->t = ray->tmax;
|
||||
CCLFirstHitContext ctx;
|
||||
rtcInitRayQueryContext(&ctx);
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(sirgienko): Cycles GPU back-ends passes nullptr to KernelGlobals and
|
||||
* uses global device allocation (CUDA, Optix, HIP) or passes all needed data
|
||||
* as a class context (Metal, oneAPI). So we need to pass this context here
|
||||
* in order to have an access to it later in Embree filter functions on GPU. */
|
||||
ctx.kg = (KernelGlobals)this;
|
||||
#else
|
||||
ctx.kg = kg;
|
||||
#endif
|
||||
|
||||
RTCRayHit ray_hit;
|
||||
ctx.ray = ray;
|
||||
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
|
||||
|
||||
RTCIntersectArguments args;
|
||||
rtcInitIntersectArguments(&args);
|
||||
args.filter = reinterpret_cast<RTCFilterFunctionN>(kernel_embree_filter_intersection_func);
|
||||
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
|
||||
args.context = &ctx;
|
||||
rtcTraversableIntersect1(kernel_data.device_bvh, &ray_hit, &args);
|
||||
if (ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID ||
|
||||
ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __BVH_LOCAL__
|
||||
ccl_device_intersect bool kernel_embree_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)
|
||||
{
|
||||
const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
|
||||
SD_OBJECT_TRANSFORM_APPLIED);
|
||||
CCLLocalContext ctx;
|
||||
rtcInitRayQueryContext(&ctx);
|
||||
# ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(sirgienko): Cycles GPU back-ends passes nullptr to KernelGlobals and
|
||||
* uses global device allocation (CUDA, Optix, HIP) or passes all needed data
|
||||
* as a class context (Metal, oneAPI). So we need to pass this context here
|
||||
* in order to have an access to it later in Embree filter functions on GPU. */
|
||||
ctx.kg = (KernelGlobals)this;
|
||||
# else
|
||||
ctx.kg = kg;
|
||||
# endif
|
||||
ctx.is_sss = has_bvh;
|
||||
ctx.lcg_state = lcg_state;
|
||||
ctx.max_hits = max_hits;
|
||||
ctx.ray = ray;
|
||||
ctx.local_isect = local_isect;
|
||||
if (local_isect) {
|
||||
local_isect->num_hits = 0;
|
||||
}
|
||||
ctx.local_object_id = local_object;
|
||||
RTCRay rtc_ray;
|
||||
kernel_embree_setup_ray(*ray, rtc_ray, PATH_RAY_VISIBILITY_ALL);
|
||||
|
||||
RTCOccludedArguments args;
|
||||
rtcInitOccludedArguments(&args);
|
||||
args.filter = reinterpret_cast<RTCFilterFunctionN>(kernel_embree_filter_occluded_local_func);
|
||||
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
|
||||
args.context = &ctx;
|
||||
|
||||
/* If this object has its own BVH, use it. */
|
||||
if (has_bvh) {
|
||||
float3 P = ray->P;
|
||||
float3 dir = ray->D;
|
||||
float3 idir = ray->D;
|
||||
# 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
|
||||
|
||||
rtc_ray.org_x = P.x;
|
||||
rtc_ray.org_y = P.y;
|
||||
rtc_ray.org_z = P.z;
|
||||
rtc_ray.dir_x = dir.x;
|
||||
rtc_ray.dir_y = dir.y;
|
||||
rtc_ray.dir_z = dir.z;
|
||||
rtc_ray.tnear = ray->tmin;
|
||||
rtc_ray.tfar = ray->tmax;
|
||||
RTCTraversable scene = (RTCTraversable)rtcGetGeometryUserDataFromTraversable(
|
||||
kernel_data.device_bvh, local_object * 2);
|
||||
kernel_assert(scene);
|
||||
if (scene) {
|
||||
rtcTraversableOccluded1(scene, &rtc_ray, &args);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rtcTraversableOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
|
||||
}
|
||||
|
||||
/* rtcOccluded1 sets tfar to -inf if a hit was found. */
|
||||
return (local_isect && local_isect->num_hits > 0) || (rtc_ray.tfar < 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TRANSPARENT_SHADOWS__
|
||||
ccl_device_intersect void kernel_embree_intersect_shadow_all(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
BVHShadowAllPayload &payload)
|
||||
{
|
||||
CCLShadowContext ctx;
|
||||
rtcInitRayQueryContext(&ctx);
|
||||
# if defined(__KERNEL_ONEAPI__)
|
||||
ctx.oneapi_kernel_context = this;
|
||||
# else
|
||||
ctx.kg = kg;
|
||||
# endif
|
||||
ctx.payload = &payload;
|
||||
|
||||
RTCRay rtc_ray;
|
||||
kernel_embree_setup_ray(*ray, rtc_ray, payload.base.ray_visibility);
|
||||
|
||||
RTCOccludedArguments args;
|
||||
rtcInitOccludedArguments(&args);
|
||||
args.filter = reinterpret_cast<RTCFilterFunctionN>(
|
||||
kernel_embree_filter_occluded_shadow_all_func);
|
||||
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
|
||||
args.context = &ctx;
|
||||
|
||||
rtcTraversableOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
# ifdef __VOLUME_RECORD_ALL__
|
||||
const uint max_hits,
|
||||
# endif
|
||||
const uint visibility)
|
||||
{
|
||||
CCLVolumeContext ctx;
|
||||
rtcInitRayQueryContext(&ctx);
|
||||
# ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(sirgienko) Cycles GPU back-ends passes nullptr to KernelGlobals and
|
||||
* uses global device allocation (CUDA, Optix, HIP) or passes all needed data
|
||||
* as a class context (Metal, oneAPI). So we need to pass this context here
|
||||
* in order to have an access to it later in Embree filter functions on GPU. */
|
||||
ctx.kg = (KernelGlobals)this;
|
||||
# else
|
||||
ctx.kg = kg;
|
||||
# endif
|
||||
ctx.vol_isect = isect;
|
||||
# ifdef __VOLUME_RECORD_ALL__
|
||||
ctx.max_hits = numhit_t(max_hits);
|
||||
# endif
|
||||
ctx.num_hits = numhit_t(0);
|
||||
ctx.ray = ray;
|
||||
RTCRay rtc_ray;
|
||||
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
|
||||
RTCOccludedArguments args;
|
||||
rtcInitOccludedArguments(&args);
|
||||
args.filter = reinterpret_cast<RTCFilterFunctionN>(
|
||||
kernel_embree_filter_occluded_volume_all_func);
|
||||
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
|
||||
args.context = &ctx;
|
||||
rtcTraversableOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
|
||||
return ctx.num_hits;
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
22
blender-5.2.0/intern/cycles/kernel/device/cpu/compat.h
Normal file
22
blender-5.2.0/intern/cycles/kernel/device/cpu/compat.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Release kernel has too much false-positive maybe-uninitialized warnings,
|
||||
* which makes it possible to miss actual warnings.
|
||||
*/
|
||||
#if (defined(__GNUC__) && !defined(__clang__)) && defined(NDEBUG)
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
# pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Assertions inside the kernel only work for the CPU device, so we wrap it in
|
||||
* a macro which is empty for other devices */
|
||||
|
||||
#define kernel_assert(cond) assert(cond)
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
43
blender-5.2.0/intern/cycles/kernel/device/cpu/globals.cpp
Normal file
43
blender-5.2.0/intern/cycles/kernel/device/cpu/globals.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
#include "kernel/osl/globals.h"
|
||||
|
||||
#include "util/guiding.h" // IWYU pragma: keep
|
||||
#include "util/profiling.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ThreadKernelGlobalsCPU::ThreadKernelGlobalsCPU(const KernelGlobalsCPU &kernel_globals,
|
||||
OSLGlobals *osl_globals,
|
||||
Profiler &cpu_profiler,
|
||||
const int thread_index)
|
||||
: KernelGlobalsCPU(kernel_globals),
|
||||
#ifdef WITH_OSL
|
||||
osl(osl_globals, thread_index),
|
||||
#endif
|
||||
cpu_profiler_(cpu_profiler)
|
||||
{
|
||||
#ifndef WITH_OSL
|
||||
(void)thread_index;
|
||||
(void)osl_globals;
|
||||
#endif
|
||||
|
||||
#if defined(WITH_PATH_GUIDING)
|
||||
opgl_path_segment_storage = make_unique<openpgl::cpp::PathSegmentStorage>();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ThreadKernelGlobalsCPU::start_profiling()
|
||||
{
|
||||
cpu_profiler_.add_state(&profiler);
|
||||
}
|
||||
|
||||
void ThreadKernelGlobalsCPU::stop_profiling()
|
||||
{
|
||||
cpu_profiler_.remove_state(&profiler);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
113
blender-5.2.0/intern/cycles/kernel/device/cpu/globals.h
Normal file
113
blender-5.2.0/intern/cycles/kernel/device/cpu/globals.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Constant Globals */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/types.h"
|
||||
#include "kernel/util/profiler.h"
|
||||
|
||||
#ifdef __OSL__
|
||||
# include "kernel/osl/globals.h"
|
||||
#endif
|
||||
|
||||
#include "util/guiding.h" // IWYU pragma: keep
|
||||
#include "util/types_image.h" // IWYU pragma: keep
|
||||
#include "util/unique_ptr.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct OSLGlobals;
|
||||
|
||||
/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in
|
||||
* the kernel, to access constant data. These are all stored as flat arrays.
|
||||
* these are really just standard arrays. We can't use actually globals because
|
||||
* multiple renders may be running inside the same process. */
|
||||
|
||||
/* Array for kernel data, with size to be able to assert on invalid data access. */
|
||||
template<typename T> struct kernel_array {
|
||||
const ccl_always_inline T &fetch(const int index) const
|
||||
{
|
||||
kernel_assert(index >= 0 && index < width);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
ccl_always_inline void write(const int index, const T &value) const
|
||||
{
|
||||
data[index] = value;
|
||||
}
|
||||
|
||||
T *data = nullptr;
|
||||
int width = 0;
|
||||
};
|
||||
|
||||
/* Constant globals shared between all threads. */
|
||||
struct KernelGlobalsCPU {
|
||||
#define KERNEL_DATA_ARRAY(type, name) kernel_array<const type> name;
|
||||
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) kernel_array<type> name;
|
||||
#include "kernel/data_arrays.h"
|
||||
|
||||
KernelData data = {};
|
||||
|
||||
KernelImageLoadRequestedCPU image_load_requested_cpu;
|
||||
|
||||
ProfilingState profiler;
|
||||
};
|
||||
|
||||
/* Per-thread global state.
|
||||
*
|
||||
* To avoid pointer indirection, the constant globals are copied to each thread.
|
||||
*
|
||||
* This may not be ideal for cache pressure. Alternative would be to pass an
|
||||
* additional thread index to every function, and potentially to make the shared
|
||||
* part an actual global variable. That would match the GPU more closely, but
|
||||
* also require mutex locks for multiple Cycles instances. */
|
||||
struct ThreadKernelGlobalsCPU : public KernelGlobalsCPU {
|
||||
ThreadKernelGlobalsCPU(const KernelGlobalsCPU &kernel_globals,
|
||||
OSLGlobals *osl_globals_memory,
|
||||
Profiler &cpu_profiler,
|
||||
const int thread_index);
|
||||
|
||||
ThreadKernelGlobalsCPU(ThreadKernelGlobalsCPU &other) = delete;
|
||||
ThreadKernelGlobalsCPU(ThreadKernelGlobalsCPU &&other) noexcept = default;
|
||||
ThreadKernelGlobalsCPU &operator=(const ThreadKernelGlobalsCPU &other) = delete;
|
||||
ThreadKernelGlobalsCPU &operator=(ThreadKernelGlobalsCPU &&other) = delete;
|
||||
|
||||
void start_profiling();
|
||||
void stop_profiling();
|
||||
|
||||
#ifdef __OSL__
|
||||
OSLThreadData osl;
|
||||
#endif
|
||||
|
||||
#if defined(__PATH_GUIDING__)
|
||||
/* Pointers to shared global data structures. */
|
||||
openpgl::cpp::SampleStorage *opgl_sample_data_storage = nullptr;
|
||||
openpgl::cpp::Field *opgl_guiding_field = nullptr;
|
||||
|
||||
/* Local data structures owned by the thread. */
|
||||
unique_ptr<openpgl::cpp::PathSegmentStorage> opgl_path_segment_storage;
|
||||
unique_ptr<openpgl::cpp::SurfaceSamplingDistribution> opgl_surface_sampling_distribution;
|
||||
unique_ptr<openpgl::cpp::VolumeSamplingDistribution> opgl_volume_sampling_distribution;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
Profiler &cpu_profiler_;
|
||||
};
|
||||
|
||||
using KernelGlobals = const ThreadKernelGlobalsCPU *;
|
||||
|
||||
/* Abstraction macros */
|
||||
#define kernel_data_fetch(name, index) (kg->name.fetch(index))
|
||||
#define kernel_data_write(name, index, value) (kg->name.write(index, value))
|
||||
#define kernel_data_array(name) (kg->name.data)
|
||||
#define kernel_data (kg->data)
|
||||
#if defined(WITH_PATH_GUIDING)
|
||||
# define guiding_guiding_field kg->opgl_guiding_field
|
||||
# define guiding_ssd kg->opgl_surface_sampling_distribution
|
||||
# define guiding_vsd kg->opgl_volume_sampling_distribution
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
418
blender-5.2.0/intern/cycles/kernel/device/cpu/image.h
Normal file
418
blender-5.2.0/intern/cycles/kernel/device/cpu/image.h
Normal file
@@ -0,0 +1,418 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/device/cpu/compat.h"
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
#include "kernel/util/image_2d.h"
|
||||
|
||||
#include "util/defines.h"
|
||||
#include "util/half.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Make template functions private so symbols don't conflict between kernels with different
|
||||
* instruction sets. */
|
||||
namespace {
|
||||
|
||||
#define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
|
||||
{ \
|
||||
u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
|
||||
u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
|
||||
u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
|
||||
u[3] = (1.0f / 6.0f) * t * t * t; \
|
||||
} \
|
||||
(void)0
|
||||
|
||||
ccl_device_inline float frac(const float x, int *ix)
|
||||
{
|
||||
int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
|
||||
*ix = i;
|
||||
return x - (float)i;
|
||||
}
|
||||
|
||||
template<typename TexT, typename OutT = float4> struct ImageInterpolator {
|
||||
|
||||
static ccl_always_inline OutT zero()
|
||||
{
|
||||
if constexpr (std::is_same_v<OutT, float4>) {
|
||||
return zero_float4();
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(const float4 r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(const uchar4 r)
|
||||
{
|
||||
const float f = 1.0f / 255.0f;
|
||||
return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float read(const uchar r)
|
||||
{
|
||||
return r * (1.0f / 255.0f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float read(const float r)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(half4 r)
|
||||
{
|
||||
return half4_to_float4_image(r);
|
||||
}
|
||||
|
||||
static ccl_always_inline float read(half r)
|
||||
{
|
||||
return half_to_float_image(r);
|
||||
}
|
||||
|
||||
static ccl_always_inline float read(const uint16_t r)
|
||||
{
|
||||
return r * (1.0f / 65535.0f);
|
||||
}
|
||||
|
||||
static ccl_always_inline float4 read(ushort4 r)
|
||||
{
|
||||
const float f = 1.0f / 65535.0f;
|
||||
return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
|
||||
}
|
||||
|
||||
/* Read 2D Texture Data
|
||||
* Does not check if data request is in bounds. */
|
||||
static ccl_always_inline OutT
|
||||
read(const TexT *data, const int x, int y, const int width, const int /*height*/)
|
||||
{
|
||||
return read(data[y * width + x]);
|
||||
}
|
||||
|
||||
/* Read 2D Texture Data Clip
|
||||
* Returns transparent black if data request is out of bounds. */
|
||||
static ccl_always_inline OutT
|
||||
read_clip(const TexT *data, const int x, int y, const int width, const int height)
|
||||
{
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return zero();
|
||||
}
|
||||
return read(data[y * width + x]);
|
||||
}
|
||||
|
||||
static ccl_always_inline int wrap_periodic(int x, const int width)
|
||||
{
|
||||
x %= width;
|
||||
if (x < 0) {
|
||||
x += width;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static ccl_always_inline int wrap_clamp(const int x, const int width)
|
||||
{
|
||||
return clamp(x, 0, width - 1);
|
||||
}
|
||||
|
||||
static ccl_always_inline int wrap_mirror(const int x, const int width)
|
||||
{
|
||||
const int m = abs(x + (x < 0)) % (2 * width);
|
||||
if (m >= width) {
|
||||
return 2 * width - m - 1;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/* ******** 2D interpolation ******** */
|
||||
|
||||
static ccl_always_inline OutT interp_closest(const KernelImageInfo &info, const float x, float y)
|
||||
{
|
||||
const int width = info.width;
|
||||
const int height = info.height;
|
||||
int ix, iy;
|
||||
frac(x, &ix);
|
||||
frac(y, &iy);
|
||||
switch (info.extension) {
|
||||
case EXTENSION_REPEAT:
|
||||
ix = wrap_periodic(ix, width);
|
||||
iy = wrap_periodic(iy, height);
|
||||
break;
|
||||
case EXTENSION_CLIP:
|
||||
/* No samples are inside the clip region. */
|
||||
if (ix < 0 || ix >= width || iy < 0 || iy >= height) {
|
||||
return zero();
|
||||
}
|
||||
break;
|
||||
case EXTENSION_EXTEND:
|
||||
ix = wrap_clamp(ix, width);
|
||||
iy = wrap_clamp(iy, height);
|
||||
break;
|
||||
case EXTENSION_MIRROR:
|
||||
ix = wrap_mirror(ix, width);
|
||||
iy = wrap_mirror(iy, height);
|
||||
break;
|
||||
default:
|
||||
kernel_assert(0);
|
||||
return zero();
|
||||
}
|
||||
|
||||
const TexT *data = (const TexT *)info.data;
|
||||
return read(data, ix, iy, width, height);
|
||||
}
|
||||
|
||||
static ccl_always_inline OutT interp_linear(const KernelImageInfo &info, const float x, float y)
|
||||
{
|
||||
const int width = info.width;
|
||||
const int height = info.height;
|
||||
|
||||
/* A -0.5 offset is used to center the linear samples around the sample point. */
|
||||
int ix, iy;
|
||||
int nix, niy;
|
||||
const float tx = frac(x - 0.5f, &ix);
|
||||
const float ty = frac(y - 0.5f, &iy);
|
||||
const TexT *data = (const TexT *)info.data;
|
||||
|
||||
switch (info.extension) {
|
||||
case EXTENSION_REPEAT:
|
||||
ix = wrap_periodic(ix, width);
|
||||
nix = wrap_periodic(ix + 1, width);
|
||||
|
||||
iy = wrap_periodic(iy, height);
|
||||
niy = wrap_periodic(iy + 1, height);
|
||||
break;
|
||||
case EXTENSION_CLIP:
|
||||
/* No linear samples are inside the clip region. */
|
||||
if (ix < -1 || ix >= width || iy < -1 || iy >= height) {
|
||||
return zero();
|
||||
}
|
||||
nix = ix + 1;
|
||||
niy = iy + 1;
|
||||
return (1.0f - ty) * (1.0f - tx) * read_clip(data, ix, iy, width, height) +
|
||||
(1.0f - ty) * tx * read_clip(data, nix, iy, width, height) +
|
||||
ty * (1.0f - tx) * read_clip(data, ix, niy, width, height) +
|
||||
ty * tx * read_clip(data, nix, niy, width, height);
|
||||
case EXTENSION_EXTEND:
|
||||
nix = wrap_clamp(ix + 1, width);
|
||||
ix = wrap_clamp(ix, width);
|
||||
niy = wrap_clamp(iy + 1, height);
|
||||
iy = wrap_clamp(iy, height);
|
||||
break;
|
||||
case EXTENSION_MIRROR:
|
||||
nix = wrap_mirror(ix + 1, width);
|
||||
ix = wrap_mirror(ix, width);
|
||||
niy = wrap_mirror(iy + 1, height);
|
||||
iy = wrap_mirror(iy, height);
|
||||
break;
|
||||
default:
|
||||
kernel_assert(0);
|
||||
return zero();
|
||||
}
|
||||
|
||||
return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) +
|
||||
(1.0f - ty) * tx * read(data, nix, iy, width, height) +
|
||||
ty * (1.0f - tx) * read(data, ix, niy, width, height) +
|
||||
ty * tx * read(data, nix, niy, width, height);
|
||||
}
|
||||
|
||||
static ccl_always_inline OutT interp_cubic(const KernelImageInfo &info, const float x, float y)
|
||||
{
|
||||
const int width = info.width;
|
||||
const int height = info.height;
|
||||
|
||||
/* A -0.5 offset is used to center the cubic samples around the sample point. */
|
||||
int ix, iy;
|
||||
const float tx = frac(x - 0.5f, &ix);
|
||||
const float ty = frac(y - 0.5f, &iy);
|
||||
|
||||
int pix, piy;
|
||||
int nix, niy;
|
||||
int nnix, nniy;
|
||||
|
||||
switch (info.extension) {
|
||||
case EXTENSION_REPEAT:
|
||||
ix = wrap_periodic(ix, width);
|
||||
pix = wrap_periodic(ix - 1, width);
|
||||
nix = wrap_periodic(ix + 1, width);
|
||||
nnix = wrap_periodic(ix + 2, width);
|
||||
|
||||
iy = wrap_periodic(iy, height);
|
||||
piy = wrap_periodic(iy - 1, height);
|
||||
niy = wrap_periodic(iy + 1, height);
|
||||
nniy = wrap_periodic(iy + 2, height);
|
||||
break;
|
||||
case EXTENSION_CLIP:
|
||||
/* No cubic samples are inside the clip region. */
|
||||
if (ix < -2 || ix > width || iy < -2 || iy > height) {
|
||||
return zero();
|
||||
}
|
||||
|
||||
pix = ix - 1;
|
||||
nix = ix + 1;
|
||||
nnix = ix + 2;
|
||||
|
||||
piy = iy - 1;
|
||||
niy = iy + 1;
|
||||
nniy = iy + 2;
|
||||
break;
|
||||
case EXTENSION_EXTEND:
|
||||
pix = wrap_clamp(ix - 1, width);
|
||||
nix = wrap_clamp(ix + 1, width);
|
||||
nnix = wrap_clamp(ix + 2, width);
|
||||
ix = wrap_clamp(ix, width);
|
||||
|
||||
piy = wrap_clamp(iy - 1, height);
|
||||
niy = wrap_clamp(iy + 1, height);
|
||||
nniy = wrap_clamp(iy + 2, height);
|
||||
iy = wrap_clamp(iy, height);
|
||||
break;
|
||||
case EXTENSION_MIRROR:
|
||||
pix = wrap_mirror(ix - 1, width);
|
||||
nix = wrap_mirror(ix + 1, width);
|
||||
nnix = wrap_mirror(ix + 2, width);
|
||||
ix = wrap_mirror(ix, width);
|
||||
|
||||
piy = wrap_mirror(iy - 1, height);
|
||||
niy = wrap_mirror(iy + 1, height);
|
||||
nniy = wrap_mirror(iy + 2, height);
|
||||
iy = wrap_mirror(iy, height);
|
||||
break;
|
||||
default:
|
||||
kernel_assert(0);
|
||||
return zero();
|
||||
}
|
||||
|
||||
const TexT *data = (const TexT *)info.data;
|
||||
const int xc[4] = {pix, ix, nix, nnix};
|
||||
const int yc[4] = {piy, iy, niy, nniy};
|
||||
float u[4], v[4];
|
||||
|
||||
/* Some helper macros to keep code size reasonable.
|
||||
* Lets the compiler inline all the matrix multiplications.
|
||||
*/
|
||||
#define DATA(x, y) (read_clip(data, xc[x], yc[y], width, height))
|
||||
#define TERM(col) \
|
||||
(v[col] * \
|
||||
(u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col)))
|
||||
|
||||
SET_CUBIC_SPLINE_WEIGHTS(u, tx);
|
||||
SET_CUBIC_SPLINE_WEIGHTS(v, ty);
|
||||
|
||||
/* Actual interpolation. */
|
||||
return TERM(0) + TERM(1) + TERM(2) + TERM(3);
|
||||
#undef TERM
|
||||
#undef DATA
|
||||
}
|
||||
|
||||
static ccl_always_inline OutT interp(const KernelImageInfo &info, const float x, float y)
|
||||
{
|
||||
switch (info.interpolation) {
|
||||
case INTERPOLATION_CLOSEST:
|
||||
return interp_closest(info, x, y);
|
||||
case INTERPOLATION_LINEAR:
|
||||
return interp_linear(info, x, y);
|
||||
default:
|
||||
return interp_cubic(info, x, y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#undef SET_CUBIC_SPLINE_WEIGHTS
|
||||
|
||||
ccl_device float4 kernel_image_interp(KernelGlobals kg,
|
||||
ShaderData *sd,
|
||||
const int image_texture_id,
|
||||
dual2 uv)
|
||||
{
|
||||
if (image_texture_id == KERNEL_IMAGE_NONE) {
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
const ccl_global KernelImageTexture &tex = kernel_data_fetch(image_textures, image_texture_id);
|
||||
const ccl_global KernelImageInfo *info;
|
||||
|
||||
float2 xy = zero_float2();
|
||||
|
||||
if (tex.tile_descriptor_offset != UINT_MAX) {
|
||||
/* Wrapping. */
|
||||
if (!kernel_image_tile_wrap(ExtensionType(tex.extension), uv.val)) {
|
||||
return zero_float4();
|
||||
}
|
||||
|
||||
/* Tile mapping */
|
||||
const KernelTileDescriptor tile_descriptor = kernel_image_tile_map(
|
||||
kg, sd, tex, image_texture_id, uv, xy);
|
||||
|
||||
if (!kernel_tile_descriptor_loaded(tile_descriptor)) {
|
||||
return (tile_descriptor == KERNEL_TILE_LOAD_FAILED) ? IMAGE_MISSING_RGBA : tex.average_color;
|
||||
}
|
||||
|
||||
info = &kernel_data_fetch(image_info, kernel_tile_descriptor_image_info_id(tile_descriptor));
|
||||
}
|
||||
else {
|
||||
/* Full image sampling. */
|
||||
if (tex.image_info_id == KERNEL_IMAGE_NONE) {
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
|
||||
/* Convert to pixel space. */
|
||||
info = &kernel_data_fetch(image_info, tex.image_info_id);
|
||||
xy = make_float2(uv.val.x * info->width, uv.val.y * info->height);
|
||||
}
|
||||
|
||||
if (UNLIKELY(!info->data)) {
|
||||
return zero_float4();
|
||||
}
|
||||
|
||||
switch (info->data_type) {
|
||||
case IMAGE_DATA_TYPE_HALF: {
|
||||
const float f = ImageInterpolator<half, float>::interp(*info, xy.x, xy.y);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
case IMAGE_DATA_TYPE_BYTE: {
|
||||
const float f = ImageInterpolator<uchar, float>::interp(*info, xy.x, xy.y);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
case IMAGE_DATA_TYPE_USHORT: {
|
||||
const float f = ImageInterpolator<uint16_t, float>::interp(*info, xy.x, xy.y);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
case IMAGE_DATA_TYPE_FLOAT: {
|
||||
const float f = ImageInterpolator<float, float>::interp(*info, xy.x, xy.y);
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
case IMAGE_DATA_TYPE_HALF4:
|
||||
return ImageInterpolator<half4>::interp(*info, xy.x, xy.y);
|
||||
case IMAGE_DATA_TYPE_BYTE4:
|
||||
return ImageInterpolator<uchar4>::interp(*info, xy.x, xy.y);
|
||||
case IMAGE_DATA_TYPE_USHORT4:
|
||||
return ImageInterpolator<ushort4>::interp(*info, xy.x, xy.y);
|
||||
case IMAGE_DATA_TYPE_FLOAT4:
|
||||
return ImageInterpolator<float4>::interp(*info, xy.x, xy.y);
|
||||
default:
|
||||
assert(0);
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_forceinline float4 kernel_image_interp_with_udim(KernelGlobals kg,
|
||||
ShaderData *sd,
|
||||
const int udim_id,
|
||||
dual2 uv)
|
||||
{
|
||||
const int image_texture_id = kernel_image_udim_map(kg, udim_id, uv.val);
|
||||
if (image_texture_id == KERNEL_IMAGE_NONE) {
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
|
||||
return kernel_image_interp(kg, sd, image_texture_id, uv);
|
||||
}
|
||||
|
||||
} /* Namespace. */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
86
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel.cpp
Normal file
86
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* CPU kernel entry points */
|
||||
|
||||
/* On x86-64, our minimum is SSE4.2, so avoid the extra kernel and compile this
|
||||
* one with SSE4.2 intrinsics.
|
||||
*/
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
# define __KERNEL_SSE__
|
||||
# define __KERNEL_SSE2__
|
||||
# define __KERNEL_SSE3__
|
||||
# define __KERNEL_SSSE3__
|
||||
# define __KERNEL_SSE42__
|
||||
#endif
|
||||
|
||||
/* When building kernel for native machine detect kernel features from the flags
|
||||
* set by compiler.
|
||||
*/
|
||||
#ifdef WITH_KERNEL_NATIVE
|
||||
# ifdef __SSE4_2__
|
||||
# ifndef __KERNEL_SSE42__
|
||||
# define __KERNEL_SSE42__
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __AVX__
|
||||
# ifndef __KERNEL_SSE__
|
||||
# define __KERNEL_SSE__
|
||||
# endif
|
||||
# define __KERNEL_AVX__
|
||||
# endif
|
||||
# ifdef __AVX2__
|
||||
# ifndef __KERNEL_SSE__
|
||||
# define __KERNEL_SSE__
|
||||
# endif
|
||||
# define __KERNEL_AVX2__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* quiet unused define warnings */
|
||||
#if defined(__KERNEL_SSE2__)
|
||||
/* do nothing */
|
||||
#endif
|
||||
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
|
||||
#include "kernel/device/cpu/kernel.h"
|
||||
#define KERNEL_ARCH cpu
|
||||
#include "kernel/device/cpu/kernel_arch_impl.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Memory Copy */
|
||||
|
||||
void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, size_t /*unused*/)
|
||||
{
|
||||
if (strcmp(name, "data") == 0) {
|
||||
kg->data = *(KernelData *)host;
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_global_memory_copy(KernelGlobalsCPU *kg,
|
||||
const char *name,
|
||||
void *mem,
|
||||
const size_t size)
|
||||
{
|
||||
if (false) {
|
||||
}
|
||||
|
||||
#define KERNEL_DATA_ARRAY(type, tname) \
|
||||
else if (strcmp(name, #tname) == 0) { \
|
||||
kg->tname.data = (type *)mem; \
|
||||
kg->tname.width = size; \
|
||||
}
|
||||
#include "kernel/data_arrays.h"
|
||||
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
41
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel.h
Normal file
41
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
/* CPU Kernel Interface */
|
||||
|
||||
#include "kernel/types.h"
|
||||
|
||||
#include "util/half.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#define KERNEL_NAME_JOIN(x, y, z) x##_##y##_##z
|
||||
#define KERNEL_NAME_EVAL(arch, name) KERNEL_NAME_JOIN(kernel, arch, name)
|
||||
#define KERNEL_FUNCTION_FULL_NAME(name) KERNEL_NAME_EVAL(KERNEL_ARCH, name)
|
||||
|
||||
struct IntegratorStateCPU;
|
||||
struct KernelGlobalsCPU;
|
||||
struct KernelData;
|
||||
|
||||
KernelGlobalsCPU *kernel_globals_create();
|
||||
void kernel_globals_free(KernelGlobalsCPU *kg);
|
||||
|
||||
void *kernel_osl_memory(const KernelGlobalsCPU *kg);
|
||||
bool kernel_osl_use(const KernelGlobalsCPU *kg);
|
||||
|
||||
void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, const size_t size);
|
||||
void kernel_global_memory_copy(KernelGlobalsCPU *kg,
|
||||
const char *name,
|
||||
void *mem,
|
||||
const size_t size);
|
||||
|
||||
#define KERNEL_ARCH cpu
|
||||
#include "kernel/device/cpu/kernel_arch.h"
|
||||
|
||||
#define KERNEL_ARCH cpu_avx2
|
||||
#include "kernel/device/cpu/kernel_arch.h"
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
148
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel_arch.h
Normal file
148
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel_arch.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Templated common declaration part of all CPU kernels. */
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Integrator.
|
||||
*/
|
||||
|
||||
#define KERNEL_INTEGRATOR_FUNCTION(name) \
|
||||
void KERNEL_FUNCTION_FULL_NAME(integrator_##name)( \
|
||||
const ThreadKernelGlobalsCPU *ccl_restrict kg, IntegratorStateCPU *state)
|
||||
|
||||
#define KERNEL_INTEGRATOR_SHADE_FUNCTION(name) \
|
||||
void KERNEL_FUNCTION_FULL_NAME(integrator_##name)( \
|
||||
const ThreadKernelGlobalsCPU *ccl_restrict kg, \
|
||||
IntegratorStateCPU *state, \
|
||||
ccl_global float *render_buffer)
|
||||
|
||||
#define KERNEL_INTEGRATOR_INIT_FUNCTION(name) \
|
||||
bool KERNEL_FUNCTION_FULL_NAME(integrator_##name)( \
|
||||
const ThreadKernelGlobalsCPU *ccl_restrict kg, \
|
||||
IntegratorStateCPU *state, \
|
||||
KernelWorkTile *tile, \
|
||||
ccl_global float *render_buffer)
|
||||
|
||||
KERNEL_INTEGRATOR_INIT_FUNCTION(init_from_camera);
|
||||
KERNEL_INTEGRATOR_INIT_FUNCTION(init_from_bake);
|
||||
KERNEL_INTEGRATOR_SHADE_FUNCTION(megakernel);
|
||||
|
||||
#undef KERNEL_INTEGRATOR_FUNCTION
|
||||
#undef KERNEL_INTEGRATOR_INIT_FUNCTION
|
||||
#undef KERNEL_INTEGRATOR_SHADE_FUNCTION
|
||||
|
||||
#define KERNEL_FILM_CONVERT_FUNCTION(name) \
|
||||
void KERNEL_FUNCTION_FULL_NAME(film_convert_##name)(const KernelFilmConvert *kfilm_convert, \
|
||||
const float *buffer, \
|
||||
float *pixel, \
|
||||
const int width, \
|
||||
const int buffer_stride, \
|
||||
const int pixel_stride); \
|
||||
void KERNEL_FUNCTION_FULL_NAME(film_convert_half_rgba_##name)( \
|
||||
const KernelFilmConvert *kfilm_convert, \
|
||||
const float *buffer, \
|
||||
half4 *pixel, \
|
||||
const int width, \
|
||||
const int buffer_stride);
|
||||
|
||||
KERNEL_FILM_CONVERT_FUNCTION(depth)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(mist)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(sample_count)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(volume_majorant)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(float)
|
||||
|
||||
KERNEL_FILM_CONVERT_FUNCTION(light_path)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(rgbe)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(float3)
|
||||
|
||||
KERNEL_FILM_CONVERT_FUNCTION(motion)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(cryptomatte)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher_matte_with_shadow)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(combined)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(float4)
|
||||
|
||||
#undef KERNEL_FILM_CONVERT_FUNCTION
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Shader evaluation.
|
||||
*/
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset);
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset);
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_curve_shadow_transparency)(
|
||||
const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset);
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_volume_density)(const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Adaptive sampling.
|
||||
*/
|
||||
|
||||
bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
|
||||
const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int x,
|
||||
const int y,
|
||||
const float threshold,
|
||||
const int reset,
|
||||
const int offset,
|
||||
int stride);
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int y,
|
||||
const int start_x,
|
||||
const int width,
|
||||
const int offset,
|
||||
int stride);
|
||||
void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int x,
|
||||
const int start_y,
|
||||
const int height,
|
||||
const int offset,
|
||||
int stride);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Cryptomatte.
|
||||
*/
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
int pixel_index);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Volume Scattering Probability Guiding.
|
||||
*/
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(volume_guiding_filter_x)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int y,
|
||||
const int center_x,
|
||||
const int min_x,
|
||||
const int max_x,
|
||||
const int offset,
|
||||
int stride);
|
||||
void KERNEL_FUNCTION_FULL_NAME(volume_guiding_filter_y)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int x,
|
||||
const int center_y,
|
||||
const int height,
|
||||
const int offset,
|
||||
int stride);
|
||||
|
||||
#undef KERNEL_ARCH
|
||||
401
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel_arch_impl.h
Normal file
401
blender-5.2.0/intern/cycles/kernel/device/cpu/kernel_arch_impl.h
Normal file
@@ -0,0 +1,401 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Templated common implementation part of all CPU kernels.
|
||||
*
|
||||
* The idea is that particular `.cpp` files sets needed optimization flags and
|
||||
* simply includes this file without worry of copying actual implementation over.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// clang-format off
|
||||
#include "kernel/device/cpu/compat.h"
|
||||
|
||||
#ifndef KERNEL_STUB
|
||||
# include "kernel/globals.h"
|
||||
|
||||
# include "kernel/device/cpu/image.h"
|
||||
|
||||
# include "kernel/integrator/state.h"
|
||||
# include "kernel/integrator/state_flow.h"
|
||||
# include "kernel/integrator/state_util.h"
|
||||
|
||||
# include "kernel/integrator/init_from_camera.h"
|
||||
# include "kernel/integrator/init_from_bake.h"
|
||||
# include "kernel/integrator/megakernel.h"
|
||||
|
||||
# include "kernel/film/adaptive_sampling.h"
|
||||
# include "kernel/film/cryptomatte_passes.h"
|
||||
# include "kernel/film/read.h"
|
||||
# include "kernel/film/volume_guiding_denoise.h"
|
||||
|
||||
# include "kernel/bake/bake.h"
|
||||
|
||||
#else
|
||||
# define STUB_ASSERT(arch, name) \
|
||||
assert(!(#name " kernel stub for architecture " #arch " was called!"))
|
||||
#endif /* KERNEL_STUB */
|
||||
// clang-format on
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Integrator.
|
||||
*/
|
||||
|
||||
#ifdef KERNEL_STUB
|
||||
# define KERNEL_INVOKE(name, ...) (STUB_ASSERT(KERNEL_ARCH, name), 0)
|
||||
#else
|
||||
# define KERNEL_INVOKE(name, ...) integrator_##name(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* TODO: Either use something like get_work_pixel(), or simplify tile which is passed here, so
|
||||
* that it does not contain unused fields. */
|
||||
#define DEFINE_INTEGRATOR_INIT_KERNEL(name) \
|
||||
bool KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const ThreadKernelGlobalsCPU *kg, \
|
||||
IntegratorStateCPU *state, \
|
||||
KernelWorkTile *tile, \
|
||||
ccl_global float *render_buffer) \
|
||||
{ \
|
||||
(void)kg; \
|
||||
(void)state; \
|
||||
(void)tile; \
|
||||
(void)render_buffer; \
|
||||
return KERNEL_INVOKE( \
|
||||
name, kg, state, tile, render_buffer, tile->x, tile->y, tile->start_sample); \
|
||||
}
|
||||
|
||||
#define DEFINE_INTEGRATOR_SHADE_KERNEL(name) \
|
||||
void KERNEL_FUNCTION_FULL_NAME(integrator_##name)(const ThreadKernelGlobalsCPU *kg, \
|
||||
IntegratorStateCPU *state, \
|
||||
ccl_global float *render_buffer) \
|
||||
{ \
|
||||
(void)kg; \
|
||||
(void)state; \
|
||||
(void)render_buffer; \
|
||||
KERNEL_INVOKE(name, kg, state, render_buffer); \
|
||||
}
|
||||
|
||||
DEFINE_INTEGRATOR_INIT_KERNEL(init_from_camera)
|
||||
DEFINE_INTEGRATOR_INIT_KERNEL(init_from_bake)
|
||||
DEFINE_INTEGRATOR_SHADE_KERNEL(megakernel)
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Shader evaluation.
|
||||
*/
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_displace)(const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, shader_eval_displace);
|
||||
(void)kg;
|
||||
(void)input;
|
||||
(void)output;
|
||||
(void)offset;
|
||||
#else
|
||||
uint cache_miss_unused = false;
|
||||
kernel_displace_evaluate(kg, input, output, &cache_miss_unused, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_background)(const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, shader_eval_background);
|
||||
(void)kg;
|
||||
(void)input;
|
||||
(void)output;
|
||||
(void)offset;
|
||||
#else
|
||||
uint cache_miss_unused = false;
|
||||
kernel_background_evaluate(kg, input, output, &cache_miss_unused, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_curve_shadow_transparency)(
|
||||
const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, shader_eval_curve_shadow_transparency);
|
||||
(void)kg;
|
||||
(void)input;
|
||||
(void)output;
|
||||
(void)offset;
|
||||
#else
|
||||
uint cache_miss_unused = false;
|
||||
kernel_curve_shadow_transparency_evaluate(kg, input, output, &cache_miss_unused, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(shader_eval_volume_density)(const ThreadKernelGlobalsCPU *kg,
|
||||
const KernelShaderEvalInput *input,
|
||||
float *output,
|
||||
const int offset)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, shader_eval_volume_density);
|
||||
(void)kg;
|
||||
(void)input;
|
||||
(void)output;
|
||||
(void)offset;
|
||||
#else
|
||||
uint cache_miss_unused = false;
|
||||
kernel_volume_density_evaluate(kg, input, output, &cache_miss_unused, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Adaptive sampling.
|
||||
*/
|
||||
|
||||
bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
|
||||
const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int x,
|
||||
const int y,
|
||||
const float threshold,
|
||||
const int reset,
|
||||
const int offset,
|
||||
const int stride)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, adaptive_sampling_convergence_check);
|
||||
(void)kg;
|
||||
(void)render_buffer;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)threshold;
|
||||
(void)reset;
|
||||
(void)offset;
|
||||
(void)stride;
|
||||
return false;
|
||||
#else
|
||||
return film_adaptive_sampling_convergence_check(
|
||||
kg, render_buffer, x, y, threshold, reset, offset, stride);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_x)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int y,
|
||||
const int start_x,
|
||||
const int width,
|
||||
const int offset,
|
||||
const int stride)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, adaptive_sampling_filter_x);
|
||||
(void)kg;
|
||||
(void)render_buffer;
|
||||
(void)y;
|
||||
(void)start_x;
|
||||
(void)width;
|
||||
(void)offset;
|
||||
(void)stride;
|
||||
#else
|
||||
film_adaptive_sampling_filter_x(kg, render_buffer, y, start_x, width, offset, stride);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_filter_y)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int x,
|
||||
const int start_y,
|
||||
const int height,
|
||||
const int offset,
|
||||
const int stride)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, adaptive_sampling_filter_y);
|
||||
(void)kg;
|
||||
(void)render_buffer;
|
||||
(void)x;
|
||||
(void)start_y;
|
||||
(void)height;
|
||||
(void)offset;
|
||||
(void)stride;
|
||||
#else
|
||||
film_adaptive_sampling_filter_y(kg, render_buffer, x, start_y, height, offset, stride);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Cryptomatte.
|
||||
*/
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(cryptomatte_postprocess)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int pixel_index)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, cryptomatte_postprocess);
|
||||
(void)kg;
|
||||
(void)render_buffer;
|
||||
(void)pixel_index;
|
||||
#else
|
||||
film_cryptomatte_post(kg, render_buffer, pixel_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Volume Scattering Probability Guiding.
|
||||
*/
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(volume_guiding_filter_x)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int y,
|
||||
const int center_x,
|
||||
const int min_x,
|
||||
const int max_x,
|
||||
const int offset,
|
||||
const int stride)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, volume_guiding_filter_x);
|
||||
(void)kg;
|
||||
(void)render_buffer;
|
||||
(void)y;
|
||||
(void)center_x;
|
||||
(void)min_x;
|
||||
(void)max_x;
|
||||
(void)offset;
|
||||
(void)stride;
|
||||
#else
|
||||
volume_guiding_filter_x(kg, render_buffer, y, center_x, min_x, max_x, offset, stride);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KERNEL_FUNCTION_FULL_NAME(volume_guiding_filter_y)(const ThreadKernelGlobalsCPU *kg,
|
||||
ccl_global float *render_buffer,
|
||||
const int x,
|
||||
const int min_y,
|
||||
const int max_y,
|
||||
const int offset,
|
||||
const int stride)
|
||||
{
|
||||
#ifdef KERNEL_STUB
|
||||
STUB_ASSERT(KERNEL_ARCH, volume_guiding_filter_y);
|
||||
(void)kg;
|
||||
(void)render_buffer;
|
||||
(void)x;
|
||||
(void)min_y;
|
||||
(void)max_y;
|
||||
(void)offset;
|
||||
(void)stride;
|
||||
#else
|
||||
volume_guiding_filter_y(kg, render_buffer, x, min_y, max_y, offset, stride);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Film Convert.
|
||||
*/
|
||||
|
||||
#ifdef KERNEL_STUB
|
||||
|
||||
# define KERNEL_FILM_CONVERT_FUNCTION(name, is_float) \
|
||||
void KERNEL_FUNCTION_FULL_NAME(film_convert_##name)(const KernelFilmConvert *kfilm_convert, \
|
||||
const float *buffer, \
|
||||
float *pixel, \
|
||||
const int width, \
|
||||
const int buffer_stride, \
|
||||
const int pixel_stride) \
|
||||
{ \
|
||||
STUB_ASSERT(KERNEL_ARCH, film_convert_##name); \
|
||||
(void)kfilm_convert; \
|
||||
(void)buffer; \
|
||||
(void)pixel; \
|
||||
(void)width; \
|
||||
(void)buffer_stride; \
|
||||
(void)pixel_stride; \
|
||||
} \
|
||||
void KERNEL_FUNCTION_FULL_NAME(film_convert_half_rgba_##name)( \
|
||||
const KernelFilmConvert *kfilm_convert, \
|
||||
const float *buffer, \
|
||||
half4 *pixel, \
|
||||
const int width, \
|
||||
const int buffer_stride) \
|
||||
{ \
|
||||
STUB_ASSERT(KERNEL_ARCH, film_convert_##name); \
|
||||
(void)kfilm_convert; \
|
||||
(void)buffer; \
|
||||
(void)pixel; \
|
||||
(void)width; \
|
||||
(void)buffer_stride; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define KERNEL_FILM_CONVERT_FUNCTION(name, is_float) \
|
||||
void KERNEL_FUNCTION_FULL_NAME(film_convert_##name)(const KernelFilmConvert *kfilm_convert, \
|
||||
const float *buffer, \
|
||||
float *pixel, \
|
||||
const int width, \
|
||||
const int buffer_stride, \
|
||||
const int pixel_stride) \
|
||||
{ \
|
||||
for (int i = 0; i < width; i++, buffer += buffer_stride, pixel += pixel_stride) { \
|
||||
film_get_pass_pixel_##name(kfilm_convert, buffer, pixel); \
|
||||
} \
|
||||
} \
|
||||
void KERNEL_FUNCTION_FULL_NAME(film_convert_half_rgba_##name)( \
|
||||
const KernelFilmConvert *kfilm_convert, \
|
||||
const float *buffer, \
|
||||
half4 *pixel, \
|
||||
const int width, \
|
||||
const int buffer_stride) \
|
||||
{ \
|
||||
for (int i = 0; i < width; i++, buffer += buffer_stride, pixel++) { \
|
||||
float pixel_rgba[4] = {0.0f, 0.0f, 0.0f, 1.0f}; \
|
||||
film_get_pass_pixel_##name(kfilm_convert, buffer, pixel_rgba); \
|
||||
if (is_float) { \
|
||||
pixel_rgba[1] = pixel_rgba[0]; \
|
||||
pixel_rgba[2] = pixel_rgba[0]; \
|
||||
} \
|
||||
film_apply_pass_pixel_overlays_rgba(kfilm_convert, buffer, pixel_rgba); \
|
||||
*pixel = float4_to_half4_display( \
|
||||
make_float4(pixel_rgba[0], pixel_rgba[1], pixel_rgba[2], pixel_rgba[3])); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
KERNEL_FILM_CONVERT_FUNCTION(depth, true)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(mist, true)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(sample_count, true)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(volume_majorant, true)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(float, true)
|
||||
|
||||
KERNEL_FILM_CONVERT_FUNCTION(light_path, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(rgbe, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(float3, false)
|
||||
|
||||
KERNEL_FILM_CONVERT_FUNCTION(motion, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(cryptomatte, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(shadow_catcher_matte_with_shadow, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(combined, false)
|
||||
KERNEL_FILM_CONVERT_FUNCTION(float4, false)
|
||||
|
||||
#undef KERNEL_FILM_CONVERT_FUNCTION
|
||||
|
||||
#undef KERNEL_INVOKE
|
||||
#undef DEFINE_INTEGRATOR_SHADE_KERNEL
|
||||
#undef DEFINE_INTEGRATOR_INIT_KERNEL
|
||||
|
||||
#undef KERNEL_STUB
|
||||
#undef STUB_ASSERT
|
||||
#undef KERNEL_ARCH
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -0,0 +1,29 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Optimized CPU kernel entry points. This file is compiled with AVX2
|
||||
* optimization flags and nearly all functions inlined, while kernel.cpp
|
||||
* is compiled without for other CPU's. */
|
||||
|
||||
#include "util/optimization.h"
|
||||
|
||||
#ifndef WITH_CYCLES_OPTIMIZED_KERNEL_AVX2
|
||||
# define KERNEL_STUB
|
||||
#else
|
||||
/* SSE optimization disabled for now on 32 bit, see bug #36316. */
|
||||
# if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86)))
|
||||
# define __KERNEL_SSE__
|
||||
# define __KERNEL_SSE2__
|
||||
# define __KERNEL_SSE3__
|
||||
# define __KERNEL_SSSE3__
|
||||
# define __KERNEL_SSE42__
|
||||
# define __KERNEL_AVX__
|
||||
# define __KERNEL_AVX2__
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */
|
||||
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
#include "kernel/device/cpu/kernel.h"
|
||||
#define KERNEL_ARCH cpu_avx2
|
||||
#include "kernel/device/cpu/kernel_arch_impl.h"
|
||||
235
blender-5.2.0/intern/cycles/kernel/device/cuda/CMakeLists.txt
Normal file
235
blender-5.2.0/intern/cycles/kernel/device/cuda/CMakeLists.txt
Normal file
@@ -0,0 +1,235 @@
|
||||
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(INC
|
||||
../../..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_CUDA
|
||||
kernel.cu
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_CUDA_HEADERS
|
||||
compat.h
|
||||
config.h
|
||||
globals.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
||||
)
|
||||
|
||||
function(cuda_get_version out_version)
|
||||
execute_process(COMMAND ${CUDA_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT)
|
||||
string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR "${NVCC_OUT}")
|
||||
string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR "${NVCC_OUT}")
|
||||
set(${out_version} "${CUDA_VERSION_MAJOR}${CUDA_VERSION_MINOR}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cuda_add_common_flags cuda_version arch in_flags out_flags)
|
||||
set(flags ${in_flags})
|
||||
|
||||
if(CUDA_HOST_COMPILER)
|
||||
set(flags ${flags} -ccbin="${CUDA_HOST_COMPILER}")
|
||||
endif()
|
||||
|
||||
set(flags ${flags}
|
||||
# Helps with compatibility when using recent clang host compiler.
|
||||
"-std=c++17"
|
||||
--use_fast_math
|
||||
-Wno-deprecated-gpu-targets)
|
||||
|
||||
if(WITH_CYCLES_DEBUG)
|
||||
set(flags ${flags}
|
||||
-D WITH_CYCLES_DEBUG
|
||||
--ptxas-options="-v")
|
||||
endif()
|
||||
|
||||
if(WITH_NANOVDB)
|
||||
set(flags ${flags} -D WITH_NANOVDB)
|
||||
endif()
|
||||
|
||||
if("${cuda_version}" GREATER_EQUAL 123 AND "${arch}" STREQUAL "sm_120")
|
||||
# Enable jump table generation for the SVM switch statement.
|
||||
set(flags ${flags} --jump-table-density 80)
|
||||
endif()
|
||||
|
||||
if(NOT WITH_CYCLES_CUDA_BUILD_SERIAL AND "${cuda_version}" GREATER_EQUAL 129)
|
||||
# Only use split compile with few binaries, to avoid excessive memory usage.
|
||||
# This is mainly helpful for quick local builds for one architecture.
|
||||
list(LENGTH CYCLES_CUDA_BINARIES_ARCH _num_binaries)
|
||||
if(_num_binaries LESS_EQUAL 2)
|
||||
set(flags ${flags} --split-compile=0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${out_flags} ${flags} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
if(WITH_CYCLES_CUDA_BINARIES)
|
||||
# 64 bit only
|
||||
set(CUDA_BITS 64)
|
||||
|
||||
# CUDA version
|
||||
cuda_get_version(CUDA_VERSION)
|
||||
|
||||
# warn for other versions
|
||||
if((CUDA_VERSION STREQUAL "101") OR
|
||||
(CUDA_VERSION STREQUAL "102") OR
|
||||
(CUDA_VERSION_MAJOR STREQUAL "11") OR
|
||||
(CUDA_VERSION_MAJOR STREQUAL "12"))
|
||||
else()
|
||||
message(WARNING
|
||||
"CUDA version ${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR} detected, "
|
||||
"build may succeed but only CUDA 12, 11, 10.2 and 10.1 have been tested")
|
||||
endif()
|
||||
|
||||
# build for each arch
|
||||
set(cuda_sources kernel.cu
|
||||
${SRC_KERNEL_DEVICE_CUDA_HEADERS}
|
||||
$<TARGET_PROPERTY:cycles_kernel,INTERFACE_SOURCES>
|
||||
)
|
||||
set(cuda_cubins "")
|
||||
|
||||
# Modifies in parent scope:
|
||||
# - `cuda_cubins`: appended with compressed `cubin/ptx` output.
|
||||
function(CYCLES_CUDA_KERNEL_ADD arch prev_arch name flags sources experimental)
|
||||
if(${arch} MATCHES "compute_.*")
|
||||
set(format "ptx")
|
||||
else()
|
||||
set(format "cubin")
|
||||
endif()
|
||||
set(cuda_file ${name}_${arch}.${format})
|
||||
set(cuda_file_compressed ${cuda_file}.zst)
|
||||
|
||||
set(kernel_sources ${sources})
|
||||
if(NOT ${prev_arch} STREQUAL "none")
|
||||
if(${prev_arch} MATCHES "compute_.*")
|
||||
set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.ptx)
|
||||
else()
|
||||
set(kernel_sources ${kernel_sources} ${name}_${prev_arch}.cubin)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(cuda_kernel_src "/${name}.cu")
|
||||
|
||||
set(cuda_flags ${flags}
|
||||
-D CCL_NAMESPACE_BEGIN=
|
||||
-D CCL_NAMESPACE_END=
|
||||
-D NVCC
|
||||
-D _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH
|
||||
-m ${CUDA_BITS}
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../..
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file})
|
||||
|
||||
cuda_add_common_flags(${cuda_version} ${arch} "${cuda_flags}" cuda_flags)
|
||||
|
||||
set(_cuda_nvcc_args
|
||||
-arch=${arch}
|
||||
${CUDA_NVCC_FLAGS}
|
||||
--${format}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}${cuda_kernel_src}
|
||||
${cuda_flags}
|
||||
)
|
||||
|
||||
if(WITH_COMPILER_CCACHE AND CCACHE_PROGRAM)
|
||||
add_custom_command(
|
||||
OUTPUT ${cuda_file}
|
||||
COMMAND ${CCACHE_PROGRAM} ${cuda_nvcc_executable} ${_cuda_nvcc_args}
|
||||
DEPENDS ${kernel_sources})
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT ${cuda_file}
|
||||
COMMAND ${cuda_nvcc_executable} ${_cuda_nvcc_args}
|
||||
DEPENDS ${kernel_sources})
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${cuda_file_compressed}
|
||||
COMMAND "$<TARGET_FILE:zstd_compress>" ${cuda_file} ${cuda_file_compressed}
|
||||
DEPENDS ${cuda_file})
|
||||
|
||||
unset(_cuda_nvcc_args)
|
||||
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cuda_file_compressed}" ${CYCLES_INSTALL_PATH}/lib)
|
||||
list(APPEND cuda_cubins ${cuda_file_compressed})
|
||||
set(cuda_cubins "${cuda_cubins}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
set(prev_arch "none")
|
||||
foreach(arch ${CYCLES_CUDA_BINARIES_ARCH})
|
||||
if(${arch} MATCHES ".*_3.")
|
||||
message(STATUS "CUDA binaries for ${arch} are no longer supported, skipped.")
|
||||
elseif(${arch} MATCHES "compute_7." AND DEFINED CUDA11_NVCC_EXECUTABLE)
|
||||
# Use CUDA 11 if available for the default PTX kernel. This allows us to
|
||||
# keep the driver requirements for user machines low.
|
||||
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
|
||||
set(cuda_version 110)
|
||||
elseif((${arch} MATCHES ".*_5." OR ${arch} MATCHES ".*_6." OR ${arch} MATCHES ".*_70") AND "${CUDA_VERSION}" GREATER_EQUAL 130)
|
||||
# Support for Maxwell, Pascal and Volta was dropped in CUDA 13
|
||||
if(DEFINED CUDA11_NVCC_EXECUTABLE)
|
||||
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
|
||||
set(cuda_version 110)
|
||||
else()
|
||||
message(STATUS "CUDA binaries for ${arch} are no longer supported with CUDA 13.0+, skipped.")
|
||||
endif()
|
||||
elseif(${arch} MATCHES ".*_7." AND "${CUDA_VERSION}" LESS 100)
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 10.0+, skipped.")
|
||||
elseif(${arch} MATCHES ".*_8.")
|
||||
if("${CUDA_VERSION}" GREATER_EQUAL 111) # Support for sm_86 was introduced in CUDA 11
|
||||
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
|
||||
set(cuda_version ${CUDA_VERSION})
|
||||
elseif(DEFINED CUDA11_NVCC_EXECUTABLE)
|
||||
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA11_TOOLKIT_ROOT_DIR})
|
||||
set(cuda_version 110)
|
||||
else()
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 11.1+, skipped.")
|
||||
endif()
|
||||
elseif(${arch} MATCHES ".*_10." OR ${arch} MATCHES ".*_120")
|
||||
if("${CUDA_VERSION}" GREATER_EQUAL 128) # Support for sm_100, sm_101, sm_120 was introduced in CUDA 12.8
|
||||
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
|
||||
set(cuda_version ${CUDA_VERSION})
|
||||
else()
|
||||
message(STATUS "CUDA binaries for ${arch} require CUDA 12.8+, skipped.")
|
||||
endif()
|
||||
else()
|
||||
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
|
||||
set(cuda_toolkit_root_dir ${CUDA_TOOLKIT_ROOT_DIR})
|
||||
set(cuda_version ${CUDA_VERSION})
|
||||
endif()
|
||||
if(DEFINED cuda_nvcc_executable AND DEFINED cuda_toolkit_root_dir)
|
||||
# Compile regular kernel
|
||||
cycles_cuda_kernel_add(${arch} ${prev_arch} kernel "" "${cuda_sources}" FALSE)
|
||||
|
||||
if(WITH_CYCLES_CUDA_BUILD_SERIAL)
|
||||
set(prev_arch ${arch})
|
||||
endif()
|
||||
|
||||
unset(cuda_nvcc_executable)
|
||||
unset(cuda_toolkit_root_dir)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_custom_target(cycles_kernel_cuda
|
||||
ALL
|
||||
DEPENDS ${cuda_cubins}
|
||||
SOURCES ${SRC_KERNEL_DEVICE_CUDA} ${SRC_KERNEL_DEVICE_CUDA_HEADERS}
|
||||
)
|
||||
cycles_set_solution_folder(cycles_kernel_cuda)
|
||||
|
||||
source_group("device\\cuda" FILES ${SRC_KERNEL_DEVICE_CUDA} ${SRC_KERNEL_DEVICE_CUDA_HEADERS})
|
||||
|
||||
add_dependencies(cycles_kernel cycles_kernel_cuda)
|
||||
endif()
|
||||
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_CUDA}" ${CYCLES_INSTALL_PATH}/source/kernel/device/cuda)
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_CUDA_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/cuda)
|
||||
119
blender-5.2.0/intern/cycles/kernel/device/cuda/compat.h
Normal file
119
blender-5.2.0/intern/cycles/kernel/device/cuda/compat.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_CUDA__
|
||||
#define CCL_NAMESPACE_BEGIN
|
||||
#define CCL_NAMESPACE_END
|
||||
|
||||
#ifndef ATTR_FALLTHROUGH
|
||||
# define ATTR_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
/* Manual definitions so we can compile without CUDA toolkit. */
|
||||
|
||||
#ifdef __CUDACC_RTC__
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef CYCLES_CUBIN_CC
|
||||
# define FLT_MIN 1.175494350822287507969e-38f
|
||||
# define FLT_MAX 340282346638528859811704183484516925440.0f
|
||||
# define FLT_EPSILON 1.192092896e-07F
|
||||
#endif
|
||||
|
||||
/* Qualifiers */
|
||||
|
||||
#define ccl_device __device__ __inline__
|
||||
#define ccl_device_extern extern "C" __device__
|
||||
#define ccl_device_inline __device__ __inline__
|
||||
#define ccl_device_forceinline __device__ __forceinline__
|
||||
#define ccl_device_noinline __device__ __noinline__
|
||||
#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
|
||||
#define ccl_inline_constant __constant__
|
||||
#define ccl_device_constant __constant__ __device__
|
||||
#define ccl_static_constexpr static constexpr
|
||||
#define ccl_constant const
|
||||
#define ccl_gpu_shared __shared__
|
||||
#define ccl_private
|
||||
#define ccl_ray_data ccl_private
|
||||
#define ccl_may_alias
|
||||
#define ccl_restrict __restrict__
|
||||
#define ccl_align(n) __align__(n)
|
||||
#define ccl_optional_struct_init
|
||||
#define ccl_attr_maybe_unused [[maybe_unused]]
|
||||
|
||||
/* No assert supported for CUDA */
|
||||
|
||||
#define kernel_assert(cond)
|
||||
|
||||
/* GPU thread, block, grid size and index */
|
||||
|
||||
#define ccl_gpu_thread_idx_x (threadIdx.x)
|
||||
#define ccl_gpu_block_dim_x (blockDim.x)
|
||||
#define ccl_gpu_block_idx_x (blockIdx.x)
|
||||
#define ccl_gpu_grid_dim_x (gridDim.x)
|
||||
#define ccl_gpu_warp_size (warpSize)
|
||||
#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
|
||||
|
||||
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
|
||||
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
|
||||
|
||||
/* GPU warp synchronization. */
|
||||
|
||||
#define ccl_gpu_syncthreads() __syncthreads()
|
||||
#define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate)
|
||||
|
||||
/* GPU texture objects */
|
||||
|
||||
typedef unsigned long long CUtexObject;
|
||||
typedef CUtexObject ccl_gpu_image_object_2D;
|
||||
|
||||
template<typename T>
|
||||
ccl_device_forceinline T ccl_gpu_image_object_read_2D(const ccl_gpu_image_object_2D texobj,
|
||||
const float x,
|
||||
const float y)
|
||||
{
|
||||
return tex2D<T>(texobj, x, y);
|
||||
}
|
||||
|
||||
/* Use fast math functions */
|
||||
|
||||
#define cosf(x) __cosf(((float)(x)))
|
||||
#define sinf(x) __sinf(((float)(x)))
|
||||
#define powf(x, y) __powf(((float)(x)), ((float)(y)))
|
||||
#define tanf(x) __tanf(((float)(x)))
|
||||
#define logf(x) __logf(((float)(x)))
|
||||
#define expf(x) __expf(((float)(x)))
|
||||
|
||||
/* Half */
|
||||
|
||||
typedef unsigned short half;
|
||||
|
||||
ccl_device_forceinline half __float2half(const float f)
|
||||
{
|
||||
half val;
|
||||
asm("{ cvt.rn.f16.f32 %0, %1;}\n" : "=h"(val) : "f"(f));
|
||||
return val;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float __half2float(const half h)
|
||||
{
|
||||
float val;
|
||||
asm("{ cvt.f32.f16 %0, %1;}\n" : "=f"(val) : "h"(h));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Types */
|
||||
|
||||
#include "util/half.h"
|
||||
#include "util/types.h"
|
||||
88
blender-5.2.0/intern/cycles/kernel/device/cuda/config.h
Normal file
88
blender-5.2.0/intern/cycles/kernel/device/cuda/config.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Device data taken from CUDA occupancy calculator.
|
||||
*
|
||||
* Terminology
|
||||
* - CUDA GPUs have multiple streaming multiprocessors
|
||||
* - Each multiprocessor executes multiple thread blocks
|
||||
* - Each thread block contains a number of threads, also known as the block size
|
||||
* - Multiprocessors have a fixed number of registers, and the amount of registers
|
||||
* used by each threads limits the number of threads per block.
|
||||
*/
|
||||
|
||||
/* 5.x, 6.x */
|
||||
#if __CUDA_ARCH__ <= 699
|
||||
# define GPU_MULTIPRESSOR_MAX_REGISTERS 65536
|
||||
# define GPU_MULTIPROCESSOR_MAX_BLOCKS 32
|
||||
# define GPU_BLOCK_MAX_THREADS 1024
|
||||
# define GPU_THREAD_MAX_REGISTERS 255
|
||||
|
||||
/* tunable parameters */
|
||||
# define GPU_KERNEL_BLOCK_NUM_THREADS 256
|
||||
/* CUDA 9.0 seems to cause slowdowns on high-end Pascal cards unless we increase the number of
|
||||
* registers */
|
||||
# if __CUDACC_VER_MAJOR__ >= 9 && __CUDA_ARCH__ >= 600
|
||||
# define GPU_KERNEL_MAX_REGISTERS 64
|
||||
# else
|
||||
# define GPU_KERNEL_MAX_REGISTERS 48
|
||||
# endif
|
||||
|
||||
/* 7.x, 8.x, 12.x */
|
||||
#elif __CUDA_ARCH__ <= 1299
|
||||
# define GPU_MULTIPRESSOR_MAX_REGISTERS 65536
|
||||
# define GPU_MULTIPROCESSOR_MAX_BLOCKS 32
|
||||
# define GPU_BLOCK_MAX_THREADS 1024
|
||||
# define GPU_THREAD_MAX_REGISTERS 255
|
||||
|
||||
/* tunable parameters */
|
||||
# define GPU_KERNEL_BLOCK_NUM_THREADS 384
|
||||
# define GPU_KERNEL_MAX_REGISTERS 168
|
||||
|
||||
/* unknown architecture */
|
||||
#else
|
||||
# error "Unknown or unsupported CUDA architecture, can't determine launch bounds"
|
||||
#endif
|
||||
|
||||
/* Compute number of threads per block and minimum blocks per multiprocessor
|
||||
* given the maximum number of registers per thread. */
|
||||
#define ccl_gpu_kernel(block_num_threads, thread_num_registers) \
|
||||
extern "C" __global__ void __launch_bounds__(block_num_threads, \
|
||||
GPU_MULTIPRESSOR_MAX_REGISTERS / \
|
||||
(block_num_threads * thread_num_registers))
|
||||
|
||||
#define ccl_gpu_kernel_threads(block_num_threads) \
|
||||
extern "C" __global__ void __launch_bounds__(block_num_threads)
|
||||
|
||||
#define ccl_gpu_kernel_signature(name, ...) kernel_gpu_##name(__VA_ARGS__)
|
||||
#define ccl_gpu_kernel_postfix
|
||||
|
||||
#define ccl_gpu_kernel_call(x) x
|
||||
#define ccl_gpu_kernel_within_bounds(i, n) ((i) < (n))
|
||||
|
||||
/* 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 { \
|
||||
__VA_ARGS__; \
|
||||
__device__ int operator()(const int state) \
|
||||
{ \
|
||||
return (func); \
|
||||
} \
|
||||
} ccl_gpu_kernel_lambda_pass
|
||||
|
||||
/* sanity checks */
|
||||
|
||||
#if GPU_KERNEL_BLOCK_NUM_THREADS > GPU_BLOCK_MAX_THREADS
|
||||
# error "Maximum number of threads per block exceeded"
|
||||
#endif
|
||||
|
||||
#if GPU_MULTIPRESSOR_MAX_REGISTERS / (GPU_KERNEL_BLOCK_NUM_THREADS * GPU_KERNEL_MAX_REGISTERS) > \
|
||||
GPU_MULTIPROCESSOR_MAX_BLOCKS
|
||||
# error "Maximum number of blocks per multiprocessor exceeded"
|
||||
#endif
|
||||
|
||||
#if GPU_KERNEL_MAX_REGISTERS > GPU_THREAD_MAX_REGISTERS
|
||||
# error "Maximum number of registers per thread exceeded"
|
||||
#endif
|
||||
48
blender-5.2.0/intern/cycles/kernel/device/cuda/globals.h
Normal file
48
blender-5.2.0/intern/cycles/kernel/device/cuda/globals.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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"
|
||||
|
||||
#include "util/color.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Not actually used, just a nullptr pointer that gets passed everywhere, which we
|
||||
* hope gets optimized out by the compiler. */
|
||||
struct KernelGlobalsGPU {
|
||||
int unused[1];
|
||||
};
|
||||
using KernelGlobals = const ccl_global KernelGlobalsGPU *ccl_restrict;
|
||||
|
||||
struct KernelParamsCUDA {
|
||||
/* Global scene data and textures */
|
||||
KernelData data;
|
||||
#define KERNEL_DATA_ARRAY(type, name) const type *name;
|
||||
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) type *name;
|
||||
#include "kernel/data_arrays.h"
|
||||
|
||||
/* Integrator state */
|
||||
IntegratorStateGPU integrator_state;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL_GPU__
|
||||
__constant__ KernelParamsCUDA kernel_params;
|
||||
#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
|
||||
16
blender-5.2.0/intern/cycles/kernel/device/cuda/kernel.cu
Normal file
16
blender-5.2.0/intern/cycles/kernel/device/cuda/kernel.cu
Normal file
@@ -0,0 +1,16 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* CUDA kernel entry points */
|
||||
|
||||
#ifdef __CUDA_ARCH__
|
||||
|
||||
# include "kernel/device/cuda/compat.h"
|
||||
# include "kernel/device/cuda/config.h"
|
||||
# include "kernel/device/cuda/globals.h"
|
||||
|
||||
# include "kernel/device/gpu/image.h"
|
||||
# include "kernel/device/gpu/kernel.h"
|
||||
|
||||
#endif
|
||||
18
blender-5.2.0/intern/cycles/kernel/device/gpu/block_sizes.h
Normal file
18
blender-5.2.0/intern/cycles/kernel/device/gpu/block_sizes.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/* SPDX-FileCopyrightText: 2017-2025 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __HIP__
|
||||
# define GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE 1024
|
||||
# define GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE 1024
|
||||
# define GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE 1024
|
||||
#else
|
||||
# define GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE 512
|
||||
# define GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE 512
|
||||
# define GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE 512
|
||||
#endif
|
||||
|
||||
#define GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY (~0)
|
||||
#define GPU_PARALLEL_SORT_BLOCK_SIZE 1024
|
||||
173
blender-5.2.0/intern/cycles/kernel/device/gpu/image.h
Normal file
173
blender-5.2.0/intern/cycles/kernel/device/gpu/image.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/* SPDX-FileCopyrightText: 2017-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/globals.h"
|
||||
#include "kernel/util/image_2d.h"
|
||||
#include "util/defines.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_inline float frac(const float x, ccl_private int *ix)
|
||||
{
|
||||
int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
|
||||
*ix = i;
|
||||
return x - (float)i;
|
||||
}
|
||||
|
||||
/* w0, w1, w2, and w3 are the four cubic B-spline basis functions. */
|
||||
ccl_device float cubic_w0(const float a)
|
||||
{
|
||||
return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f);
|
||||
}
|
||||
ccl_device float cubic_w1(const float a)
|
||||
{
|
||||
return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f);
|
||||
}
|
||||
ccl_device float cubic_w2(const float a)
|
||||
{
|
||||
return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f);
|
||||
}
|
||||
ccl_device float cubic_w3(const float a)
|
||||
{
|
||||
return (1.0f / 6.0f) * (a * a * a);
|
||||
}
|
||||
|
||||
/* g0 and g1 are the two amplitude functions. */
|
||||
ccl_device float cubic_g0(const float a)
|
||||
{
|
||||
return cubic_w0(a) + cubic_w1(a);
|
||||
}
|
||||
ccl_device float cubic_g1(const float a)
|
||||
{
|
||||
return cubic_w2(a) + cubic_w3(a);
|
||||
}
|
||||
|
||||
/* h0 and h1 are the two offset functions */
|
||||
ccl_device float cubic_h0(const float a)
|
||||
{
|
||||
return (cubic_w1(a) / cubic_g0(a)) - 1.0f;
|
||||
}
|
||||
ccl_device float cubic_h1(const float a)
|
||||
{
|
||||
return (cubic_w3(a) / cubic_g1(a)) + 1.0f;
|
||||
}
|
||||
|
||||
/* Fast bicubic texture lookup using 4 bilinear lookups, adapted from CUDA samples. */
|
||||
template<typename T>
|
||||
ccl_device_noinline T kernel_image_interp_bicubic(const ccl_global KernelImageInfo &info,
|
||||
const float2 uv)
|
||||
{
|
||||
ccl_gpu_image_object_2D tex = (ccl_gpu_image_object_2D)info.data;
|
||||
|
||||
const float x = (uv.x * (float)info.width) - 0.5f;
|
||||
const float y = (uv.y * (float)info.height) - 0.5f;
|
||||
|
||||
const float px = floorf(x);
|
||||
const float py = floorf(y);
|
||||
const float fx = x - px;
|
||||
const float fy = y - py;
|
||||
|
||||
const float g0x = cubic_g0(fx);
|
||||
const float g1x = cubic_g1(fx);
|
||||
/* Note +0.5 offset to compensate for CUDA linear filtering convention. */
|
||||
const float x0 = (px + cubic_h0(fx) + 0.5f) * info.inv_width;
|
||||
const float x1 = (px + cubic_h1(fx) + 0.5f) * info.inv_width;
|
||||
const float y0 = (py + cubic_h0(fy) + 0.5f) * info.inv_height;
|
||||
const float y1 = (py + cubic_h1(fy) + 0.5f) * info.inv_height;
|
||||
|
||||
return cubic_g0(fy) * (g0x * ccl_gpu_image_object_read_2D<T>(tex, x0, y0) +
|
||||
g1x * ccl_gpu_image_object_read_2D<T>(tex, x1, y0)) +
|
||||
cubic_g1(fy) * (g0x * ccl_gpu_image_object_read_2D<T>(tex, x0, y1) +
|
||||
g1x * ccl_gpu_image_object_read_2D<T>(tex, x1, y1));
|
||||
}
|
||||
|
||||
ccl_device float4 kernel_image_interp(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const int image_texture_id,
|
||||
dual2 uv)
|
||||
{
|
||||
if (image_texture_id == KERNEL_IMAGE_NONE) {
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
const ccl_global KernelImageTexture &tex = kernel_data_fetch(image_textures, image_texture_id);
|
||||
const ccl_global KernelImageInfo *info;
|
||||
|
||||
float2 sample_uv;
|
||||
|
||||
if (tex.tile_descriptor_offset != KERNEL_TILE_LOAD_NONE) {
|
||||
/* Wrapping. */
|
||||
if (!kernel_image_tile_wrap(ExtensionType(tex.extension), uv.val)) {
|
||||
return zero_float4();
|
||||
}
|
||||
|
||||
/* Tile mapping */
|
||||
float2 xy = zero_float2();
|
||||
const KernelTileDescriptor tile_descriptor = kernel_image_tile_map(
|
||||
kg, sd, tex, image_texture_id, uv, xy);
|
||||
|
||||
if (!kernel_tile_descriptor_loaded(tile_descriptor)) {
|
||||
return (tile_descriptor == KERNEL_TILE_LOAD_FAILED) ? IMAGE_MISSING_RGBA : tex.average_color;
|
||||
}
|
||||
|
||||
info = &kernel_data_fetch(image_info, kernel_tile_descriptor_image_info_id(tile_descriptor));
|
||||
|
||||
/* Convert to normalized space again. */
|
||||
sample_uv = make_float2(xy.x * info->inv_width, xy.y * info->inv_height);
|
||||
}
|
||||
else {
|
||||
/* Full image sampling. */
|
||||
if (tex.image_info_id == KERNEL_IMAGE_NONE) {
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
|
||||
info = &kernel_data_fetch(image_info, tex.image_info_id);
|
||||
sample_uv = uv.val;
|
||||
}
|
||||
|
||||
/* float4, byte4, ushort4 and half4 */
|
||||
const int texture_type = info->data_type;
|
||||
if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 ||
|
||||
texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4)
|
||||
{
|
||||
if (info->interpolation == INTERPOLATION_CUBIC || info->interpolation == INTERPOLATION_SMART) {
|
||||
return kernel_image_interp_bicubic<float4>(*info, sample_uv);
|
||||
}
|
||||
else {
|
||||
ccl_gpu_image_object_2D tex = (ccl_gpu_image_object_2D)info->data;
|
||||
return ccl_gpu_image_object_read_2D<float4>(tex, sample_uv.x, sample_uv.y);
|
||||
}
|
||||
}
|
||||
/* float, byte and half */
|
||||
else {
|
||||
float f;
|
||||
|
||||
if (info->interpolation == INTERPOLATION_CUBIC || info->interpolation == INTERPOLATION_SMART) {
|
||||
f = kernel_image_interp_bicubic<float>(*info, sample_uv);
|
||||
}
|
||||
else {
|
||||
ccl_gpu_image_object_2D tex = (ccl_gpu_image_object_2D)info->data;
|
||||
f = ccl_gpu_image_object_read_2D<float>(tex, sample_uv.x, sample_uv.y);
|
||||
}
|
||||
|
||||
return make_float4(f, f, f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_forceinline float4 kernel_image_interp_with_udim(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const int udim_id,
|
||||
dual2 uv)
|
||||
{
|
||||
const int image_texture_id = kernel_image_udim_map(kg, udim_id, uv.val);
|
||||
if (image_texture_id == KERNEL_IMAGE_NONE) {
|
||||
return IMAGE_MISSING_RGBA;
|
||||
}
|
||||
|
||||
return kernel_image_interp(kg, sd, image_texture_id, uv);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
1366
blender-5.2.0/intern/cycles/kernel/device/gpu/kernel.h
Normal file
1366
blender-5.2.0/intern/cycles/kernel/device/gpu/kernel.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,180 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Given an array of states, build an array of indices for which the states
|
||||
* are active.
|
||||
*
|
||||
* Shared memory requirement is `sizeof(int) * (number_of_warps + 1)`. */
|
||||
|
||||
#include "kernel/device/gpu/block_sizes.h"
|
||||
#include "util/atomic.h"
|
||||
|
||||
/* TODO: abstract more device differences, define `ccl_gpu_local_syncthreads`,
|
||||
* `ccl_gpu_thread_warp`, `ccl_gpu_warp_index`, `ccl_gpu_num_warps` for all devices
|
||||
* and keep device specific code in `compat.h`. */
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
|
||||
template<typename IsActiveOp>
|
||||
void gpu_parallel_active_index_array_impl(const uint num_states,
|
||||
ccl_global int *ccl_restrict indices,
|
||||
ccl_global int *ccl_restrict num_indices,
|
||||
IsActiveOp is_active_op)
|
||||
{
|
||||
const sycl::nd_item<1> &item_id = sycl::ext::oneapi::this_work_item::get_nd_item<1>();
|
||||
const uint blocksize = item_id.get_local_range(0);
|
||||
|
||||
sycl::multi_ptr<int[GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE + 1],
|
||||
sycl::access::address_space::local_space>
|
||||
ptr = sycl::ext::oneapi::group_local_memory<
|
||||
int[GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE + 1]>(item_id.get_group());
|
||||
int *warp_offset = *ptr;
|
||||
|
||||
/* NOTE(@nsirgien): Here we calculate the same value as below but
|
||||
* faster for DPC++ : seems CUDA converting "%", "/", "*" based calculations below into
|
||||
* something faster already but DPC++ doesn't, so it's better to use
|
||||
* direct request of needed parameters - switching from this computation to computation below
|
||||
* will cause 2.5x performance slowdown. */
|
||||
const uint thread_index = item_id.get_local_id(0);
|
||||
const uint thread_warp = item_id.get_sub_group().get_local_id();
|
||||
|
||||
const uint warp_index = item_id.get_sub_group().get_group_id();
|
||||
const uint num_warps = item_id.get_sub_group().get_group_range()[0];
|
||||
|
||||
const uint state_index = item_id.get_global_id(0);
|
||||
|
||||
/* Test if state corresponding to this thread is active. */
|
||||
const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0;
|
||||
#else /* !__KERNEL__ONEAPI__ */
|
||||
# ifndef __KERNEL_METAL__
|
||||
template<typename IsActiveOp>
|
||||
__device__
|
||||
# endif
|
||||
void
|
||||
gpu_parallel_active_index_array_impl(const uint num_states,
|
||||
ccl_global int *indices,
|
||||
ccl_global int *num_indices,
|
||||
# ifdef __KERNEL_METAL__
|
||||
const uint is_active,
|
||||
const uint blocksize,
|
||||
const int thread_index,
|
||||
const uint state_index,
|
||||
const int ccl_gpu_warp_size,
|
||||
const int thread_warp,
|
||||
const int warp_index,
|
||||
const int num_warps,
|
||||
threadgroup int *warp_offset)
|
||||
{
|
||||
# else
|
||||
IsActiveOp is_active_op)
|
||||
{
|
||||
extern ccl_gpu_shared int warp_offset[];
|
||||
|
||||
# ifndef __KERNEL_METAL__
|
||||
const uint blocksize = ccl_gpu_block_dim_x;
|
||||
# endif
|
||||
|
||||
const uint thread_index = ccl_gpu_thread_idx_x;
|
||||
const uint thread_warp = thread_index % ccl_gpu_warp_size;
|
||||
|
||||
const uint warp_index = thread_index / ccl_gpu_warp_size;
|
||||
const uint num_warps = blocksize / ccl_gpu_warp_size;
|
||||
|
||||
const uint state_index = ccl_gpu_block_idx_x * blocksize + thread_index;
|
||||
|
||||
/* Test if state corresponding to this thread is active. */
|
||||
const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0;
|
||||
# endif
|
||||
#endif /* !__KERNEL_ONEAPI__ */
|
||||
/* For each thread within a warp compute how many other active states precede it. */
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
const uint thread_offset = sycl::exclusive_scan_over_group(
|
||||
item_id.get_sub_group(), is_active, std::plus<>());
|
||||
#else
|
||||
const uint thread_offset = popcount(ccl_gpu_ballot(is_active) &
|
||||
ccl_gpu_thread_mask(thread_warp));
|
||||
#endif
|
||||
|
||||
/* Last thread in warp stores number of active states for each warp. */
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
if (thread_warp == item_id.get_sub_group().get_local_range()[0] - 1) {
|
||||
#else
|
||||
if (thread_warp == ccl_gpu_warp_size - 1) {
|
||||
#endif
|
||||
warp_offset[warp_index] = thread_offset + is_active;
|
||||
}
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(@nsirgien): For us here only local memory writing (warp_offset) is important,
|
||||
* so faster local barriers can be used. */
|
||||
ccl_gpu_local_syncthreads();
|
||||
#else
|
||||
ccl_gpu_syncthreads();
|
||||
#endif
|
||||
|
||||
/* Last thread in block converts per-warp sizes to offsets, increments global size of
|
||||
* index array and gets offset to write to. */
|
||||
if (thread_index == blocksize - 1) {
|
||||
/* TODO: parallelize this. */
|
||||
int offset = 0;
|
||||
for (int i = 0; i < num_warps; i++) {
|
||||
int num_active = warp_offset[i];
|
||||
warp_offset[i] = offset;
|
||||
offset += num_active;
|
||||
}
|
||||
|
||||
const uint block_num_active = warp_offset[warp_index] + thread_offset + is_active;
|
||||
warp_offset[num_warps] = atomic_fetch_and_add_uint32(num_indices, block_num_active);
|
||||
}
|
||||
|
||||
#ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(@nsirgien): For us here only important local memory writing (warp_offset),
|
||||
* so faster local barriers can be used. */
|
||||
ccl_gpu_local_syncthreads();
|
||||
#else
|
||||
ccl_gpu_syncthreads();
|
||||
#endif
|
||||
|
||||
/* Write to index array. */
|
||||
if (is_active) {
|
||||
const uint block_offset = warp_offset[num_warps];
|
||||
indices[block_offset + warp_offset[warp_index] + thread_offset] = state_index;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __KERNEL_METAL__
|
||||
|
||||
# define gpu_parallel_active_index_array(num_states, indices, num_indices, is_active_op) \
|
||||
const uint is_active = (ccl_gpu_global_id_x() < num_states) ? \
|
||||
is_active_op(ccl_gpu_global_id_x()) : \
|
||||
0; \
|
||||
gpu_parallel_active_index_array_impl(num_states, \
|
||||
indices, \
|
||||
num_indices, \
|
||||
is_active, \
|
||||
metal_local_size, \
|
||||
metal_local_id, \
|
||||
metal_global_id, \
|
||||
simdgroup_size, \
|
||||
simd_lane_index, \
|
||||
simd_group_index, \
|
||||
num_simd_groups, \
|
||||
(threadgroup int *)threadgroup_array)
|
||||
#elif defined(__KERNEL_ONEAPI__)
|
||||
|
||||
# define gpu_parallel_active_index_array(num_states, indices, num_indices, is_active_op) \
|
||||
gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op)
|
||||
|
||||
#else
|
||||
|
||||
# define gpu_parallel_active_index_array(num_states, indices, num_indices, is_active_op) \
|
||||
gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op)
|
||||
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Parallel prefix sum.
|
||||
*
|
||||
* TODO: actually make this work in parallel.
|
||||
*
|
||||
* This is used for an array the size of the number of shaders in the scene
|
||||
* which is not usually huge, so might not be a significant bottleneck. */
|
||||
|
||||
#include "util/atomic.h"
|
||||
|
||||
__device__ void gpu_parallel_prefix_sum(const int global_id,
|
||||
ccl_global int *counter,
|
||||
ccl_global int *prefix_sum,
|
||||
const int num_values)
|
||||
{
|
||||
if (global_id != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < num_values; i++) {
|
||||
const int new_offset = offset + counter[i];
|
||||
prefix_sum[i] = offset;
|
||||
counter[i] = 0;
|
||||
offset = new_offset;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -0,0 +1,165 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Given an array of states, build an array of indices for which the states
|
||||
* are active and sorted by a given key. The prefix sum of the number of active
|
||||
* states per key must have already been computed.
|
||||
*
|
||||
* TODO: there may be ways to optimize this to avoid this many atomic ops? */
|
||||
|
||||
#include "kernel/device/gpu/block_sizes.h"
|
||||
#include "util/atomic.h"
|
||||
|
||||
#if defined(__KERNEL_LOCAL_ATOMIC_SORT__)
|
||||
|
||||
ccl_device_inline void gpu_parallel_sort_bucket_pass(const uint num_states,
|
||||
const uint partition_size,
|
||||
const uint max_shaders,
|
||||
const uint queued_kernel,
|
||||
ccl_global ushort *d_queued_kernel,
|
||||
ccl_global uint *d_shader_sort_key,
|
||||
ccl_global int *partition_key_offsets,
|
||||
ccl_gpu_shared int *buckets,
|
||||
const ushort local_id,
|
||||
const ushort local_size,
|
||||
const uint grid_id)
|
||||
{
|
||||
/* Zero the bucket sizes. */
|
||||
for (uint i = local_id; i < max_shaders; i += local_size) {
|
||||
atomic_store_local(&buckets[i], 0);
|
||||
}
|
||||
|
||||
# ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(@nsirgien): For us here only local memory writing (buckets) is important,
|
||||
* so faster local barriers can be used. */
|
||||
ccl_gpu_local_syncthreads();
|
||||
# else
|
||||
ccl_gpu_syncthreads();
|
||||
# endif
|
||||
|
||||
/* Determine bucket sizes within the partitions. */
|
||||
|
||||
const uint partition_start = partition_size * uint(grid_id);
|
||||
const uint partition_end = min(num_states, partition_start + partition_size);
|
||||
|
||||
for (int state_index = partition_start + uint(local_id); state_index < partition_end;
|
||||
state_index += uint(local_size))
|
||||
{
|
||||
ushort kernel_index = d_queued_kernel[state_index];
|
||||
if (kernel_index == queued_kernel) {
|
||||
uint key = d_shader_sort_key[state_index] % max_shaders;
|
||||
atomic_fetch_and_add_uint32_shared(&buckets[key], 1);
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(@nsirgien): For us here only local memory writing (buckets) is important,
|
||||
* so faster local barriers can be used. */
|
||||
ccl_gpu_local_syncthreads();
|
||||
# else
|
||||
ccl_gpu_syncthreads();
|
||||
# endif
|
||||
|
||||
/* Calculate the partition's local offsets from the prefix sum of bucket sizes. */
|
||||
|
||||
if (local_id == 0) {
|
||||
int offset = 0;
|
||||
for (int i = 0; i < max_shaders; i++) {
|
||||
partition_key_offsets[i + uint(grid_id) * (max_shaders + 1)] = offset;
|
||||
offset = offset + atomic_load_local(&buckets[i]);
|
||||
}
|
||||
|
||||
/* Store the number of active states in this partition. */
|
||||
partition_key_offsets[max_shaders + uint(grid_id) * (max_shaders + 1)] = offset;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline void gpu_parallel_sort_write_pass(const uint num_states,
|
||||
const uint partition_size,
|
||||
const uint max_shaders,
|
||||
const uint queued_kernel,
|
||||
const int num_states_limit,
|
||||
ccl_global int *indices,
|
||||
ccl_global ushort *d_queued_kernel,
|
||||
ccl_global uint *d_shader_sort_key,
|
||||
ccl_global int *partition_key_offsets,
|
||||
ccl_gpu_shared int *local_offset,
|
||||
const ushort local_id,
|
||||
const ushort local_size,
|
||||
const uint grid_id)
|
||||
{
|
||||
/* Calculate each partition's global offset from the prefix sum of the active state counts per
|
||||
* partition. */
|
||||
|
||||
int partition_offset = 0;
|
||||
for (uint i = 0; i < grid_id; i++) {
|
||||
partition_offset += partition_key_offsets[max_shaders + i * (max_shaders + 1)];
|
||||
}
|
||||
|
||||
ccl_global int *key_offsets = partition_key_offsets + grid_id * (max_shaders + 1);
|
||||
for (uint i = local_id; i < max_shaders; i += local_size) {
|
||||
atomic_store_local(&local_offset[i], key_offsets[i] + partition_offset);
|
||||
}
|
||||
|
||||
# ifdef __KERNEL_ONEAPI__
|
||||
/* NOTE(@nsirgien): For us here only local memory writing (local_offset) is important,
|
||||
* so faster local barriers can be used. */
|
||||
ccl_gpu_local_syncthreads();
|
||||
# else
|
||||
ccl_gpu_syncthreads();
|
||||
# endif
|
||||
|
||||
/* Write the sorted active indices. */
|
||||
|
||||
const uint partition_start = partition_size * uint(grid_id);
|
||||
const uint partition_end = min(num_states, partition_start + partition_size);
|
||||
|
||||
for (int state_index = partition_start + uint(local_id); state_index < partition_end;
|
||||
state_index += uint(local_size))
|
||||
{
|
||||
ushort kernel_index = d_queued_kernel[state_index];
|
||||
if (kernel_index == queued_kernel) {
|
||||
uint key = d_shader_sort_key[state_index] % max_shaders;
|
||||
int index = atomic_fetch_and_add_uint32_shared(&local_offset[key], 1);
|
||||
if (index < num_states_limit) {
|
||||
indices[index] = state_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __KERNEL_LOCAL_ATOMIC_SORT__ */
|
||||
|
||||
template<typename GetKeyOp>
|
||||
__device__ void gpu_parallel_sorted_index_array(const uint state_index,
|
||||
const uint num_states,
|
||||
const int num_states_limit,
|
||||
ccl_global int *indices,
|
||||
ccl_global int *num_indices,
|
||||
ccl_global int *key_counter,
|
||||
ccl_global int *key_prefix_sum,
|
||||
GetKeyOp get_key_op)
|
||||
{
|
||||
const int key = (state_index < num_states) ? get_key_op(state_index) :
|
||||
GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY;
|
||||
|
||||
if (key != GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY) {
|
||||
const uint index = atomic_fetch_and_add_uint32(&key_prefix_sum[key], 1);
|
||||
if (index < num_states_limit) {
|
||||
/* Assign state index. */
|
||||
indices[index] = state_index;
|
||||
}
|
||||
else {
|
||||
/* Can't process this state now, increase the counter again so that
|
||||
* it will be handled in another iteration. */
|
||||
atomic_fetch_and_add_uint32(&key_counter[key], 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/*
|
||||
* Utility functions for work stealing
|
||||
*/
|
||||
|
||||
/* Map global work index to tile, pixel X/Y and sample. */
|
||||
ccl_device_inline void get_work_pixel(const ccl_global KernelWorkTile *tile,
|
||||
const uint global_work_index,
|
||||
ccl_private uint *x,
|
||||
ccl_private uint *y,
|
||||
ccl_private uint *sample)
|
||||
{
|
||||
uint sample_offset, pixel_offset;
|
||||
|
||||
if (kernel_data.integrator.scrambling_distance < 0.9f) {
|
||||
/* Keep threads for the same sample together. */
|
||||
const uint tile_pixels = tile->w * tile->h;
|
||||
sample_offset = global_work_index / tile_pixels;
|
||||
pixel_offset = global_work_index - sample_offset * tile_pixels;
|
||||
}
|
||||
else {
|
||||
/* Keeping threads for the same pixel together.
|
||||
* Appears to improve performance by a few % on CUDA and OptiX. */
|
||||
sample_offset = global_work_index % tile->num_samples;
|
||||
pixel_offset = global_work_index / tile->num_samples;
|
||||
}
|
||||
|
||||
const uint y_offset = pixel_offset / tile->w;
|
||||
const uint x_offset = pixel_offset - y_offset * tile->w;
|
||||
|
||||
*x = tile->x + x_offset;
|
||||
*y = tile->y + y_offset;
|
||||
*sample = tile->start_sample + sample_offset;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
126
blender-5.2.0/intern/cycles/kernel/device/hip/CMakeLists.txt
Normal file
126
blender-5.2.0/intern/cycles/kernel/device/hip/CMakeLists.txt
Normal file
@@ -0,0 +1,126 @@
|
||||
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(INC
|
||||
../../..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_HIP
|
||||
kernel.cpp
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_HIP_HEADERS
|
||||
compat.h
|
||||
config.h
|
||||
globals.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
|
||||
# build for each arch
|
||||
set(hip_sources
|
||||
kernel.cpp
|
||||
${SRC_KERNEL_DEVICE_HIP_HEADERS}
|
||||
$<TARGET_PROPERTY:cycles_kernel,INTERFACE_SOURCES>
|
||||
)
|
||||
set(hip_fatbins "")
|
||||
|
||||
# Modifies in parent scope:
|
||||
# - `hip_fatbins`: appended with compressed `fatbin` output.
|
||||
function(CYCLES_HIP_KERNEL_ADD arch name flags sources experimental)
|
||||
set(format "fatbin")
|
||||
set(hip_file ${name}_${arch}.${format})
|
||||
set(hip_file_compressed ${hip_file}.zst)
|
||||
set(kernel_sources ${sources})
|
||||
|
||||
set(hip_kernel_src "/${name}.cpp")
|
||||
|
||||
if(WIN32)
|
||||
set(hip_command ${CMAKE_COMMAND})
|
||||
set(hip_flags
|
||||
-E env "HIP_PATH=${HIP_ROOT_DIR}"
|
||||
${HIP_HIPCC_EXECUTABLE})
|
||||
else()
|
||||
set(hip_command ${HIP_HIPCC_EXECUTABLE})
|
||||
set(hip_flags "")
|
||||
endif()
|
||||
|
||||
# There's a few bugs in the HIP compiler causing some scenes to fail to render,
|
||||
# or render improperly with specific combinations of device and/or compiler.
|
||||
# - Vega (gfx90x) fails to render some scenes
|
||||
# - Other GPUs (E.g. RDNA3) render volumes improperly with HIP 6.1.40252
|
||||
# A workaround is to set -O1 opt level during kernel compilation for these
|
||||
# configurations.
|
||||
if(WIN32 AND ((${arch} MATCHES "gfx90[a-z0-9]+") OR (${HIP_VERSION} STREQUAL "6.1.40252")))
|
||||
set(hip_opt_flags "-O1")
|
||||
else()
|
||||
set(hip_opt_flags "")
|
||||
endif()
|
||||
|
||||
set(hip_flags
|
||||
${hip_flags}
|
||||
--offload-arch=${arch}
|
||||
${HIP_HIPCC_FLAGS}
|
||||
--genco
|
||||
${CMAKE_CURRENT_SOURCE_DIR}${hip_kernel_src}
|
||||
${flags}
|
||||
-D CCL_NAMESPACE_BEGIN=
|
||||
-D CCL_NAMESPACE_END=
|
||||
-D HIPCC
|
||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../..
|
||||
-Wno-parentheses-equality
|
||||
-Wno-unused-value
|
||||
-ffast-math
|
||||
-std=c++17
|
||||
${hip_opt_flags}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/${hip_file})
|
||||
|
||||
if(WITH_NANOVDB)
|
||||
set(hip_flags ${hip_flags}
|
||||
-D WITH_NANOVDB)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_DEBUG)
|
||||
set(hip_flags ${hip_flags} -D WITH_CYCLES_DEBUG)
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${hip_file}
|
||||
COMMAND ${hip_command} ${hip_flags}
|
||||
DEPENDS ${kernel_sources})
|
||||
add_custom_command(
|
||||
OUTPUT ${hip_file_compressed}
|
||||
COMMAND "$<TARGET_FILE:zstd_compress>" ${hip_file} ${hip_file_compressed}
|
||||
DEPENDS ${hip_file})
|
||||
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${hip_file_compressed}" ${CYCLES_INSTALL_PATH}/lib)
|
||||
list(APPEND hip_fatbins ${hip_file_compressed})
|
||||
set(hip_fatbins "${hip_fatbins}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
foreach(arch ${CYCLES_HIP_BINARIES_ARCH})
|
||||
# Compile regular kernel
|
||||
cycles_hip_kernel_add(${arch} kernel "" "${hip_sources}" FALSE)
|
||||
endforeach()
|
||||
|
||||
add_custom_target(cycles_kernel_hip
|
||||
ALL
|
||||
DEPENDS ${hip_fatbins}
|
||||
SOURCES ${SRC_KERNEL_DEVICE_HIP} ${SRC_KERNEL_DEVICE_HIP_HEADERS}
|
||||
)
|
||||
cycles_set_solution_folder(cycles_kernel_hip)
|
||||
|
||||
source_group("device\\hip" FILES ${SRC_KERNEL_DEVICE_HIP} ${SRC_KERNEL_DEVICE_HIP_HEADERS})
|
||||
|
||||
add_dependencies(cycles_kernel cycles_kernel_hip)
|
||||
endif()
|
||||
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIP}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip)
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIP_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip)
|
||||
103
blender-5.2.0/intern/cycles/kernel/device/hip/compat.h
Normal file
103
blender-5.2.0/intern/cycles/kernel/device/hip/compat.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_HIP__
|
||||
#define CCL_NAMESPACE_BEGIN
|
||||
#define CCL_NAMESPACE_END
|
||||
|
||||
#ifndef ATTR_FALLTHROUGH
|
||||
# define ATTR_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#ifdef __HIPCC_RTC__
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef CYCLES_HIPBIN_CC
|
||||
# define FLT_MIN 1.175494350822287507969e-38f
|
||||
# define FLT_MAX 340282346638528859811704183484516925440.0f
|
||||
# define FLT_EPSILON 1.192092896e-07F
|
||||
#endif
|
||||
|
||||
/* Qualifiers */
|
||||
|
||||
#define ccl_device __device__ __inline__
|
||||
#define ccl_device_extern extern "C" __device__
|
||||
#define ccl_device_inline __device__ __inline__
|
||||
#define ccl_device_forceinline __device__ __forceinline__
|
||||
#define ccl_device_noinline __device__ __noinline__
|
||||
#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
|
||||
#define ccl_inline_constant __constant__
|
||||
#define ccl_device_constant __constant__ __device__
|
||||
#define ccl_static_constexpr static constexpr
|
||||
#define ccl_constant const
|
||||
#define ccl_gpu_shared __shared__
|
||||
#define ccl_private
|
||||
#define ccl_ray_data ccl_private
|
||||
#define ccl_may_alias
|
||||
#define ccl_restrict __restrict__
|
||||
#define ccl_align(n) __align__(n)
|
||||
#define ccl_optional_struct_init
|
||||
#define ccl_attr_maybe_unused [[maybe_unused]]
|
||||
|
||||
#define kernel_assert(cond)
|
||||
|
||||
/* Types */
|
||||
#ifdef __HIP__
|
||||
# include "hip/hip_fp16.h"
|
||||
# include "hip/hip_runtime.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#define ccl_gpu_thread_idx_x (threadIdx.x)
|
||||
#define ccl_gpu_block_dim_x (blockDim.x)
|
||||
#define ccl_gpu_block_idx_x (blockIdx.x)
|
||||
#define ccl_gpu_grid_dim_x (gridDim.x)
|
||||
#define ccl_gpu_warp_size (warpSize)
|
||||
#define ccl_gpu_thread_mask(thread_warp) uint64_t((1ull << thread_warp) - 1)
|
||||
|
||||
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
|
||||
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
|
||||
|
||||
/* GPU warp synchronization */
|
||||
|
||||
#define ccl_gpu_syncthreads() __syncthreads()
|
||||
#define ccl_gpu_ballot(predicate) __ballot(predicate)
|
||||
|
||||
/* GPU texture objects */
|
||||
typedef hipTextureObject_t ccl_gpu_image_object_2D;
|
||||
|
||||
template<typename T>
|
||||
ccl_device_forceinline T ccl_gpu_image_object_read_2D(const ccl_gpu_image_object_2D texobj,
|
||||
const float x,
|
||||
const float y)
|
||||
{
|
||||
return tex2D<T>(texobj, x, y);
|
||||
}
|
||||
|
||||
/* Use fast math functions */
|
||||
|
||||
#define cosf(x) __cosf(((float)(x)))
|
||||
#define sinf(x) __sinf(((float)(x)))
|
||||
#define powf(x, y) __powf(((float)(x)), ((float)(y)))
|
||||
#define tanf(x) __tanf(((float)(x)))
|
||||
#define logf(x) __logf(((float)(x)))
|
||||
#define expf(x) __expf(((float)(x)))
|
||||
|
||||
/* Types */
|
||||
|
||||
#include "util/half.h"
|
||||
#include "util/types.h"
|
||||
68
blender-5.2.0/intern/cycles/kernel/device/hip/config.h
Normal file
68
blender-5.2.0/intern/cycles/kernel/device/hip/config.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Device data taken from HIP occupancy calculator.
|
||||
*
|
||||
* Terminology
|
||||
* - HIP GPUs have multiple streaming multiprocessors
|
||||
* - Each multiprocessor executes multiple thread blocks
|
||||
* - Each thread block contains a number of threads, also known as the block size
|
||||
* - Multiprocessors have a fixed number of registers, and the amount of registers
|
||||
* used by each threads limits the number of threads per block.
|
||||
*/
|
||||
|
||||
/* Launch Bound Definitions */
|
||||
#define GPU_MULTIPRESSOR_MAX_REGISTERS 65536
|
||||
#define GPU_MULTIPROCESSOR_MAX_BLOCKS 64
|
||||
#define GPU_BLOCK_MAX_THREADS 1024
|
||||
#define GPU_THREAD_MAX_REGISTERS 255
|
||||
|
||||
#define GPU_KERNEL_BLOCK_NUM_THREADS 1024
|
||||
#define GPU_KERNEL_MAX_REGISTERS 64
|
||||
|
||||
/* For performance tuning of HIPRT kernels we might have to change the number
|
||||
* that's why we don't use GPU_KERNEL_BLOCK_NUM_THREADS. */
|
||||
#define GPU_HIPRT_KERNEL_BLOCK_NUM_THREADS 1024
|
||||
|
||||
/* Compute number of threads per block and minimum blocks per multiprocessor
|
||||
* given the maximum number of registers per thread. */
|
||||
#define ccl_gpu_kernel(block_num_threads, thread_num_registers) \
|
||||
extern "C" __global__ void __launch_bounds__(block_num_threads, \
|
||||
GPU_MULTIPRESSOR_MAX_REGISTERS / \
|
||||
(block_num_threads * thread_num_registers))
|
||||
|
||||
#define ccl_gpu_kernel_threads(block_num_threads) \
|
||||
extern "C" __global__ void __launch_bounds__(block_num_threads)
|
||||
|
||||
#define ccl_gpu_kernel_signature(name, ...) kernel_gpu_##name(__VA_ARGS__)
|
||||
#define ccl_gpu_kernel_postfix
|
||||
|
||||
#define ccl_gpu_kernel_call(x) x
|
||||
#define ccl_gpu_kernel_within_bounds(i, n) ((i) < (n))
|
||||
|
||||
/* 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 { \
|
||||
__VA_ARGS__; \
|
||||
__device__ int operator()(const int state) \
|
||||
{ \
|
||||
return (func); \
|
||||
} \
|
||||
} ccl_gpu_kernel_lambda_pass
|
||||
|
||||
/* sanity checks */
|
||||
|
||||
#if GPU_KERNEL_BLOCK_NUM_THREADS > GPU_BLOCK_MAX_THREADS
|
||||
# error "Maximum number of threads per block exceeded"
|
||||
#endif
|
||||
|
||||
#if GPU_MULTIPRESSOR_MAX_REGISTERS / (GPU_KERNEL_BLOCK_NUM_THREADS * GPU_KERNEL_MAX_REGISTERS) > \
|
||||
GPU_MULTIPROCESSOR_MAX_BLOCKS
|
||||
# error "Maximum number of blocks per multiprocessor exceeded"
|
||||
#endif
|
||||
|
||||
#if GPU_KERNEL_MAX_REGISTERS > GPU_THREAD_MAX_REGISTERS
|
||||
# error "Maximum number of registers per thread exceeded"
|
||||
#endif
|
||||
48
blender-5.2.0/intern/cycles/kernel/device/hip/globals.h
Normal file
48
blender-5.2.0/intern/cycles/kernel/device/hip/globals.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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"
|
||||
|
||||
#include "util/color.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Not actually used, just a nullptr pointer that gets passed everywhere, which we
|
||||
* hope gets optimized out by the compiler. */
|
||||
struct KernelGlobalsGPU {
|
||||
int unused[1];
|
||||
};
|
||||
using KernelGlobals = const ccl_global KernelGlobalsGPU *ccl_restrict;
|
||||
|
||||
struct KernelParamsHIP {
|
||||
/* Global scene data and textures */
|
||||
KernelData data;
|
||||
#define KERNEL_DATA_ARRAY(type, name) const type *name;
|
||||
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) type *name;
|
||||
#include "kernel/data_arrays.h"
|
||||
|
||||
/* Integrator state */
|
||||
IntegratorStateGPU integrator_state;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL_GPU__
|
||||
__constant__ KernelParamsHIP kernel_params;
|
||||
#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
|
||||
16
blender-5.2.0/intern/cycles/kernel/device/hip/kernel.cpp
Normal file
16
blender-5.2.0/intern/cycles/kernel/device/hip/kernel.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* HIP kernel entry points */
|
||||
|
||||
#ifdef __HIP_DEVICE_COMPILE__
|
||||
|
||||
# include "kernel/device/hip/compat.h"
|
||||
# include "kernel/device/hip/config.h"
|
||||
# include "kernel/device/hip/globals.h"
|
||||
|
||||
# include "kernel/device/gpu/image.h"
|
||||
# include "kernel/device/gpu/kernel.h"
|
||||
|
||||
#endif
|
||||
144
blender-5.2.0/intern/cycles/kernel/device/hiprt/CMakeLists.txt
Normal file
144
blender-5.2.0/intern/cycles/kernel/device/hiprt/CMakeLists.txt
Normal 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()
|
||||
740
blender-5.2.0/intern/cycles/kernel/device/hiprt/bvh.h
Normal file
740
blender-5.2.0/intern/cycles/kernel/device/hiprt/bvh.h
Normal 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
|
||||
153
blender-5.2.0/intern/cycles/kernel/device/hiprt/globals.h
Normal file
153
blender-5.2.0/intern/cycles/kernel/device/hiprt/globals.h
Normal 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
|
||||
140
blender-5.2.0/intern/cycles/kernel/device/hiprt/kernel.cpp
Normal file
140
blender-5.2.0/intern/cycles/kernel/device/hiprt/kernel.cpp
Normal 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__ */
|
||||
@@ -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__ */
|
||||
296
blender-5.2.0/intern/cycles/kernel/device/oneapi/CMakeLists.txt
Normal file
296
blender-5.2.0/intern/cycles/kernel/device/oneapi/CMakeLists.txt
Normal file
@@ -0,0 +1,296 @@
|
||||
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(INC
|
||||
../../..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_ONEAPI
|
||||
kernel.cpp
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_ONEAPI_HEADERS
|
||||
compat.h
|
||||
context_begin.h
|
||||
context_end.h
|
||||
context_intersect_begin.h
|
||||
context_intersect_end.h
|
||||
globals.h
|
||||
kernel.h
|
||||
kernel_templates.h
|
||||
../cpu/bvh.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_DEVICE_ONEAPI)
|
||||
if(WITH_CYCLES_ONEAPI_BINARIES)
|
||||
set(cycles_kernel_oneapi_lib_suffix "_aot")
|
||||
else()
|
||||
set(cycles_kernel_oneapi_lib_suffix "_jit")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.dll)
|
||||
set(cycles_kernel_oneapi_linker_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.lib)
|
||||
else()
|
||||
set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so)
|
||||
endif()
|
||||
|
||||
set(cycles_oneapi_kernel_sources
|
||||
${SRC_KERNEL_DEVICE_ONEAPI}
|
||||
${SRC_KERNEL_DEVICE_ONEAPI_HEADERS}
|
||||
$<TARGET_PROPERTY:cycles_kernel,INTERFACE_SOURCES>
|
||||
)
|
||||
|
||||
set(SYCL_OFFLINE_COMPILER_PARALLEL_JOBS 1 CACHE STRING "Number of parallel compiler instances to use for device binaries compilation (expect ~8GB peak memory usage per instance).")
|
||||
mark_as_advanced(SYCL_OFFLINE_COMPILER_PARALLEL_JOBS)
|
||||
|
||||
if(WITH_CYCLES_ONEAPI_BINARIES)
|
||||
message(STATUS "${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS} instance(s) of oneAPI offline compiler will be used.")
|
||||
endif()
|
||||
set(sycl_compiler_flags
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${SRC_KERNEL_DEVICE_ONEAPI}
|
||||
-fsycl
|
||||
-fsycl-unnamed-lambda
|
||||
-fdelayed-template-parsing
|
||||
-fsycl-device-code-split=per_kernel
|
||||
-fsycl-max-parallel-link-jobs=${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS}
|
||||
--offload-compress
|
||||
--offload-compression-level=19
|
||||
-shared
|
||||
-DWITH_ONEAPI
|
||||
-O2
|
||||
-ffast-math
|
||||
-D__KERNEL_LOCAL_ATOMIC_SORT__
|
||||
-o"${cycles_kernel_oneapi_lib}"
|
||||
-I"${CMAKE_CURRENT_SOURCE_DIR}/../../.."
|
||||
)
|
||||
# SYCL_CPP_FLAGS is a variable that the user can set to pass extra compiler options.
|
||||
if(DEFINED SYCL_CPP_FLAGS)
|
||||
list(APPEND sycl_compiler_flags ${SYCL_CPP_FLAGS})
|
||||
endif()
|
||||
|
||||
# Set defaults for spir64 and spir64_gen options
|
||||
if(NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64)
|
||||
set(CYCLES_ONEAPI_SYCL_OPTIONS_spir64 "-options '-cl-fast-relaxed-math -ze-intel-enable-auto-large-GRF-mode -ze-opt-regular-grf-kernel integrator_intersect -ze-opt-large-grf-kernel shade_surface -ze-opt-no-local-to-generic'")
|
||||
endif()
|
||||
if(NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen)
|
||||
set(CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "${CYCLES_ONEAPI_SYCL_OPTIONS_spir64}" CACHE STRING "Extra build options for spir64_gen target")
|
||||
mark_as_advanced(CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen)
|
||||
endif()
|
||||
# Enable `zebin`, a graphics binary format with improved compatibility.
|
||||
string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "--format zebin ")
|
||||
|
||||
# Host execution won't use GPU binaries, no need to compile them.
|
||||
if(WITH_CYCLES_ONEAPI_BINARIES)
|
||||
# Add the list of Intel devices to build binaries for.
|
||||
foreach(device ${CYCLES_ONEAPI_INTEL_BINARIES_ARCH})
|
||||
# Run `ocloc` ids to test if the device is supported.
|
||||
execute_process(
|
||||
COMMAND ${OCLOC_ENV_COMMAND} ${OCLOC_BINARY_FULL_FILEPATH} ids ${device}
|
||||
RESULT_VARIABLE oclocids_ret
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(NOT oclocids_ret EQUAL 0)
|
||||
list(REMOVE_ITEM CYCLES_ONEAPI_INTEL_BINARIES_ARCH ${device})
|
||||
message(STATUS
|
||||
"Cycles oneAPI: "
|
||||
"binaries for ${device} not supported by Intel Graphics Compiler/ocloc, skipped."
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
list(JOIN CYCLES_ONEAPI_INTEL_BINARIES_ARCH "," gen_devices_string)
|
||||
if("${gen_devices_string}" STREQUAL "")
|
||||
# Don't compile spir64_gen if no device is targeted
|
||||
message(STATUS "Cycles oneAPI: skipping spir64_gen compilation as no devices are targeted.")
|
||||
list(REMOVE_ITEM CYCLES_ONEAPI_SYCL_TARGETS spir64_gen)
|
||||
else()
|
||||
string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "-device ${gen_devices_string} ")
|
||||
endif()
|
||||
else()
|
||||
list(REMOVE_ITEM CYCLES_ONEAPI_SYCL_TARGETS spir64_gen)
|
||||
endif()
|
||||
|
||||
# Iterate over all targets and their options.
|
||||
list(JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string)
|
||||
list(APPEND sycl_compiler_flags -fsycl-targets=${targets_string})
|
||||
foreach(target ${CYCLES_ONEAPI_SYCL_TARGETS})
|
||||
if(DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_${target})
|
||||
list(APPEND sycl_compiler_flags
|
||||
"-Xsycl-target-backend=${target} \"${CYCLES_ONEAPI_SYCL_OPTIONS_${target}}\""
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(WITH_NANOVDB)
|
||||
list(APPEND sycl_compiler_flags
|
||||
-DWITH_NANOVDB)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_EMBREE AND EMBREE_SYCL_SUPPORT)
|
||||
list(APPEND sycl_compiler_flags
|
||||
-DWITH_EMBREE
|
||||
-DWITH_EMBREE_GPU
|
||||
-DEMBREE_MAJOR_VERSION=${EMBREE_MAJOR_VERSION}
|
||||
-I"${EMBREE_INCLUDE_DIRS}")
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND sycl_compiler_flags
|
||||
-ladvapi32.lib
|
||||
)
|
||||
endif()
|
||||
|
||||
set(next_library_mode "")
|
||||
foreach(library ${EMBREE_LIBRARIES})
|
||||
string(TOLOWER "${library}" library_lower)
|
||||
if(("${library_lower}" STREQUAL "optimized") OR
|
||||
("${library_lower}" STREQUAL "debug"))
|
||||
set(next_library_mode "${library_lower}")
|
||||
else()
|
||||
if(next_library_mode STREQUAL "")
|
||||
list(APPEND EMBREE_TBB_LIBRARIES_optimized ${library})
|
||||
list(APPEND EMBREE_TBB_LIBRARIES_debug ${library})
|
||||
else()
|
||||
list(APPEND EMBREE_TBB_LIBRARIES_${next_library_mode} ${library})
|
||||
endif()
|
||||
set(next_library_mode "")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(library ${TBB_LIBRARIES})
|
||||
string(TOLOWER "${library}" library_lower)
|
||||
if(("${library_lower}" STREQUAL "optimized") OR
|
||||
("${library_lower}" STREQUAL "debug"))
|
||||
set(next_library_mode "${library_lower}")
|
||||
else()
|
||||
if(next_library_mode STREQUAL "")
|
||||
list(APPEND EMBREE_TBB_LIBRARIES_optimized ${library})
|
||||
list(APPEND EMBREE_TBB_LIBRARIES_debug ${library})
|
||||
else()
|
||||
list(APPEND EMBREE_TBB_LIBRARIES_${next_library_mode} ${library})
|
||||
endif()
|
||||
set(next_library_mode "")
|
||||
endif()
|
||||
endforeach()
|
||||
list(APPEND sycl_compiler_flags
|
||||
"$<$<CONFIG:Release>:${EMBREE_TBB_LIBRARIES_optimized}>"
|
||||
"$<$<CONFIG:RelWithDebInfo>:${EMBREE_TBB_LIBRARIES_optimized}>"
|
||||
"$<$<CONFIG:MinSizeRel>:${EMBREE_TBB_LIBRARIES_optimized}>"
|
||||
"$<$<CONFIG:Debug>:${EMBREE_TBB_LIBRARIES_debug}>"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_DEBUG)
|
||||
list(APPEND sycl_compiler_flags -DWITH_CYCLES_DEBUG)
|
||||
endif()
|
||||
|
||||
get_filename_component(sycl_compiler_root ${SYCL_COMPILER} DIRECTORY)
|
||||
|
||||
if(WIN32) # Add Windows specific compiler flags.
|
||||
list(APPEND sycl_compiler_flags
|
||||
-fms-extensions
|
||||
-fms-compatibility
|
||||
-D_WINDLL
|
||||
-D_MBCS
|
||||
-DWIN32
|
||||
-D_WINDOWS
|
||||
-D_CRT_NONSTDC_NO_DEPRECATE
|
||||
-D_CRT_SECURE_NO_DEPRECATE
|
||||
-DONEAPI_EXPORT
|
||||
)
|
||||
else() # Add Linux specific compiler flags.
|
||||
list(APPEND sycl_compiler_flags -fPIC)
|
||||
list(APPEND sycl_compiler_flags -fvisibility=hidden)
|
||||
|
||||
# Add $ORIGIN to `cycles_kernel_oneapi.so` RPATH so `libsycl.so` and
|
||||
# `libpi_level_zero.so` can be placed next to it and get found.
|
||||
list(APPEND sycl_compiler_flags -Wl,-rpath,'$$ORIGIN')
|
||||
endif()
|
||||
|
||||
# Create CONFIG specific compiler flags.
|
||||
set(sycl_compiler_flags_Release ${sycl_compiler_flags})
|
||||
set(sycl_compiler_flags_Debug ${sycl_compiler_flags})
|
||||
set(sycl_compiler_flags_RelWithDebInfo ${sycl_compiler_flags})
|
||||
|
||||
list(APPEND sycl_compiler_flags_Release
|
||||
-DNDEBUG
|
||||
)
|
||||
list(APPEND sycl_compiler_flags_RelWithDebInfo
|
||||
-DNDEBUG
|
||||
-g
|
||||
)
|
||||
list(APPEND sycl_compiler_flags_Debug
|
||||
-g
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND sycl_compiler_flags_Debug
|
||||
-D_DEBUG
|
||||
-nostdlib
|
||||
-Xclang --dependent-lib=msvcrtd
|
||||
)
|
||||
|
||||
list(APPEND sycl_compiler_flags
|
||||
-L"${sycl_compiler_root}/../lib" # To find sycl.lib
|
||||
-L"${sycl_compiler_root}/../compiler/lib/intel64_win" # To find libircmt.lib (when using `icpx`)
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${cycles_kernel_oneapi_lib} ${cycles_kernel_oneapi_linker_lib}
|
||||
COMMAND ${CMAKE_COMMAND} -E env
|
||||
"PATH=${OCLOC_INSTALL_DIR}\;${sycl_compiler_root}"
|
||||
${SYCL_COMPILER}
|
||||
"$<$<CONFIG:Release>:${sycl_compiler_flags_Release}>"
|
||||
"$<$<CONFIG:RelWithDebInfo>:${sycl_compiler_flags_RelWithDebInfo}>"
|
||||
"$<$<CONFIG:Debug>:${sycl_compiler_flags_Debug}>"
|
||||
"$<$<CONFIG:MinSizeRel>:${sycl_compiler_flags_Release}>"
|
||||
COMMAND_EXPAND_LISTS
|
||||
DEPENDS ${cycles_oneapi_kernel_sources} ${SYCL_COMPILER})
|
||||
else()
|
||||
# The following join/replace operations are to prevent cmake from
|
||||
# escaping space chars with backslashes in add_custom_command.
|
||||
list(JOIN sycl_compiler_flags_Release " " sycl_compiler_flags_Release_str)
|
||||
string(REPLACE " " ";" sycl_compiler_flags_Release_str ${sycl_compiler_flags_Release_str})
|
||||
list(JOIN sycl_compiler_flags_RelWithDebInfo " " sycl_compiler_flags_RelWithDebInfo_str)
|
||||
string(REPLACE " " ";" sycl_compiler_flags_RelWithDebInfo_str ${sycl_compiler_flags_RelWithDebInfo_str})
|
||||
list(JOIN sycl_compiler_flags_Debug " " sycl_compiler_flags_Debug_str)
|
||||
string(REPLACE " " ";" sycl_compiler_flags_Debug_str ${sycl_compiler_flags_Debug_str})
|
||||
add_custom_command(
|
||||
OUTPUT ${cycles_kernel_oneapi_lib}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env
|
||||
"LD_LIBRARY_PATH=${sycl_compiler_root}/../lib:${OCLOC_LD_LIBRARY_PATH}"
|
||||
# `$ENV{PATH}` is for compiler to find `ld`.
|
||||
"PATH=${OCLOC_INSTALL_DIR}/bin:${sycl_compiler_root}:$ENV{PATH}"
|
||||
${SYCL_COMPILER}
|
||||
"$<$<CONFIG:Release>:${sycl_compiler_flags_Release_str}>"
|
||||
"$<$<CONFIG:RelWithDebInfo>:${sycl_compiler_flags_RelWithDebInfo_str}>"
|
||||
"$<$<CONFIG:Debug>:${sycl_compiler_flags_Debug_str}>"
|
||||
"$<$<CONFIG:MinSizeRel>:${sycl_compiler_flags_Release_str}>"
|
||||
COMMAND_EXPAND_LISTS
|
||||
DEPENDS ${cycles_oneapi_kernel_sources} ${SYCL_COMPILER})
|
||||
endif()
|
||||
|
||||
# install dynamic libraries required at runtime
|
||||
delayed_install("" "${cycles_kernel_oneapi_lib}" ${cycles_kernel_runtime_lib_target_path})
|
||||
|
||||
add_custom_target(cycles_kernel_oneapi
|
||||
ALL
|
||||
DEPENDS ${cycles_kernel_oneapi_lib}
|
||||
SOURCES ${SRC_KERNEL_DEVICE_ONEAPI} ${SRC_KERNEL_DEVICE_ONEAPI_HEADERS}
|
||||
)
|
||||
cycles_set_solution_folder(cycles_kernel_oneapi)
|
||||
|
||||
source_group("device\\oneapi" FILES ${SRC_KERNEL_DEVICE_ONEAPI} ${SRC_KERNEL_DEVICE_ONEAPI_HEADERS})
|
||||
|
||||
add_dependencies(cycles_kernel cycles_kernel_oneapi)
|
||||
endif()
|
||||
270
blender-5.2.0/intern/cycles/kernel/device/oneapi/compat.h
Normal file
270
blender-5.2.0/intern/cycles/kernel/device/oneapi/compat.h
Normal file
@@ -0,0 +1,270 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_ONEAPI__
|
||||
#define __KERNEL_64_BIT__
|
||||
|
||||
#ifdef WITH_EMBREE_GPU
|
||||
# define __KERNEL_GPU_RAYTRACING__
|
||||
#endif
|
||||
|
||||
#define CCL_NAMESPACE_BEGIN
|
||||
#define CCL_NAMESPACE_END
|
||||
|
||||
#include <cstdint>
|
||||
#include <math.h>
|
||||
|
||||
#ifndef __NODES_MAX_GROUP__
|
||||
# define __NODES_MAX_GROUP__ NODE_GROUP_LEVEL_MAX
|
||||
#endif
|
||||
#ifndef __NODES_FEATURES__
|
||||
# define __NODES_FEATURES__ NODE_FEATURE_ALL
|
||||
#endif
|
||||
|
||||
/* This one does not have an abstraction.
|
||||
* It's used by other devices directly.
|
||||
*/
|
||||
|
||||
#define __device__
|
||||
|
||||
/* Qualifier wrappers for different names on different devices */
|
||||
|
||||
#define ccl_device inline
|
||||
#define ccl_device_extern extern "C"
|
||||
#define ccl_global
|
||||
#define ccl_always_inline __attribute__((always_inline))
|
||||
#define ccl_device_inline __attribute__((always_inline))
|
||||
#define ccl_noinline __attribute__((noinline))
|
||||
#define ccl_inline_constant const constexpr
|
||||
#define ccl_device_constant static constexpr
|
||||
#define ccl_static_constexpr static constexpr
|
||||
#define ccl_device_forceinline __attribute__((always_inline))
|
||||
#define ccl_device_noinline __attribute__((noinline))
|
||||
#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_restrict __restrict__
|
||||
#define ccl_optional_struct_init
|
||||
#define ccl_private
|
||||
#define ccl_ray_data ccl_private
|
||||
#define ccl_gpu_shared
|
||||
#define ATTR_FALLTHROUGH __attribute__((fallthrough))
|
||||
#define ccl_constant const
|
||||
#define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))
|
||||
#define ccl_align(n) __attribute__((aligned(n)))
|
||||
#define kernel_assert(cond)
|
||||
#define ccl_may_alias
|
||||
#define ccl_attr_maybe_unused [[maybe_unused]]
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* kernel.h adapters */
|
||||
#define ccl_gpu_kernel(block_num_threads, thread_num_registers)
|
||||
#define ccl_gpu_kernel_threads(block_num_threads)
|
||||
|
||||
# define __ccl_gpu_kernel_signature(name, ...) \
|
||||
void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
|
||||
size_t kernel_global_size, \
|
||||
size_t kernel_local_size, \
|
||||
sycl::handler &cgh, \
|
||||
__VA_ARGS__) { \
|
||||
(void)(kg); \
|
||||
cgh.parallel_for( \
|
||||
sycl::nd_range<1>(kernel_global_size, kernel_local_size), \
|
||||
[=](sycl::nd_item<1> item) {
|
||||
|
||||
# define ccl_gpu_kernel_signature __ccl_gpu_kernel_signature
|
||||
|
||||
# define ccl_gpu_kernel_postfix \
|
||||
}); \
|
||||
}
|
||||
|
||||
#define ccl_gpu_kernel_call(x) ((ONEAPIKernelContext*)kg)->x
|
||||
#define ccl_gpu_kernel_within_bounds(i, n) ((i) < (n))
|
||||
|
||||
#define ccl_gpu_kernel_lambda(func, ...) \
|
||||
struct KernelLambda \
|
||||
{ \
|
||||
KernelLambda(const ONEAPIKernelContext *_kg) : kg(_kg) {} \
|
||||
ccl_private const ONEAPIKernelContext *kg; \
|
||||
__VA_ARGS__; \
|
||||
int operator()(const int state) const { return (func); } \
|
||||
} ccl_gpu_kernel_lambda_pass((ONEAPIKernelContext *)kg)
|
||||
|
||||
/* GPU thread, block, grid size and index */
|
||||
|
||||
# define ccl_gpu_thread_idx_x (sycl::ext::oneapi::this_work_item::get_nd_item<1>().get_local_id(0))
|
||||
# define ccl_gpu_block_dim_x (sycl::ext::oneapi::this_work_item::get_nd_item<1>().get_local_range(0))
|
||||
# define ccl_gpu_block_idx_x (sycl::ext::oneapi::this_work_item::get_nd_item<1>().get_group(0))
|
||||
# define ccl_gpu_grid_dim_x (sycl::ext::oneapi::this_work_item::get_nd_item<1>().get_group_range(0))
|
||||
# define ccl_gpu_warp_size (sycl::ext::oneapi::this_work_item::get_sub_group().get_local_range()[0])
|
||||
# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
|
||||
|
||||
# define ccl_gpu_global_id_x() (sycl::ext::oneapi::this_work_item::get_nd_item<1>().get_global_id(0))
|
||||
# define ccl_gpu_global_size_x() (sycl::ext::oneapi::this_work_item::get_nd_item<1>().get_global_range(0))
|
||||
|
||||
/* GPU warp synchronization */
|
||||
# define ccl_gpu_syncthreads() sycl::ext::oneapi::this_work_item::get_nd_item<1>().barrier()
|
||||
# define ccl_gpu_local_syncthreads() sycl::ext::oneapi::this_work_item::get_nd_item<1>().barrier(sycl::access::fence_space::local_space)
|
||||
|
||||
/* A ballot in SYCL is only available as an Intel extension and its DPC++ v6.3 implementation
|
||||
* does not support devices with sub-group sizes above 64. Summing values (of any type) within
|
||||
* sub-groups can be achieved with the SYCL core feature inclusive_scan_over_group, which has
|
||||
* better support on non-Intel devices. */
|
||||
# define ccl_gpu_ballot(predicate) 0; static_assert(false, "Use sycl::inclusive_scan_over_group on oneAPI device instead of ccl_gpu_ballot")
|
||||
|
||||
/* Debug defines */
|
||||
#if defined(__SYCL_DEVICE_ONLY__)
|
||||
# define CCL_ONEAPI_CONSTANT __attribute__((opencl_constant))
|
||||
#else
|
||||
# define CCL_ONEAPI_CONSTANT
|
||||
#endif
|
||||
|
||||
#define sycl_printf(format, ...) { \
|
||||
static const CCL_ONEAPI_CONSTANT char fmt[] = format; \
|
||||
sycl::ext::oneapi::experimental::printf(fmt, __VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
#define sycl_printf_(format) { \
|
||||
static const CCL_ONEAPI_CONSTANT char fmt[] = format; \
|
||||
sycl::ext::oneapi::experimental::printf(fmt); \
|
||||
}
|
||||
|
||||
/* GPU texture objects */
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/* Types */
|
||||
|
||||
/* It's not possible to use sycl types like sycl::float3, sycl::int3, etc
|
||||
* because these types have different interfaces from blender version. */
|
||||
|
||||
using uchar = unsigned char;
|
||||
using sycl::half;
|
||||
|
||||
/* math functions */
|
||||
ccl_device_forceinline float __uint_as_float(unsigned int x)
|
||||
{
|
||||
return sycl::bit_cast<float>(x);
|
||||
}
|
||||
ccl_device_forceinline unsigned int __float_as_uint(const float x)
|
||||
{
|
||||
return sycl::bit_cast<unsigned int>(x);
|
||||
}
|
||||
ccl_device_forceinline float __int_as_float(const int x)
|
||||
{
|
||||
return sycl::bit_cast<float>(x);
|
||||
}
|
||||
ccl_device_forceinline int __float_as_int(const float x)
|
||||
{
|
||||
return sycl::bit_cast<int>(x);
|
||||
}
|
||||
|
||||
#define fabsf(x) sycl::fabs((x))
|
||||
#define copysignf(x, y) sycl::copysign((x), (y))
|
||||
#define asinf(x) sycl::asin((x))
|
||||
#define acosf(x) sycl::acos((x))
|
||||
#define atanf(x) sycl::atan((x))
|
||||
#define floorf(x) sycl::floor((x))
|
||||
#define ceilf(x) sycl::ceil((x))
|
||||
#define roundf(x) sycl::round((x))
|
||||
#define sinhf(x) sycl::sinh((x))
|
||||
#define coshf(x) sycl::cosh((x))
|
||||
#define tanhf(x) sycl::tanh((x))
|
||||
#define hypotf(x, y) sycl::hypot((x), (y))
|
||||
#define atan2f(x, y) sycl::atan2((x), (y))
|
||||
#define fmaxf(x, y) sycl::fmax((x), (y))
|
||||
#define fminf(x, y) sycl::fmin((x), (y))
|
||||
#define fmodf(x, y) sycl::fmod((x), (y))
|
||||
#define lgammaf(x) sycl::lgamma((x))
|
||||
#define ldexpf(x, y) sycl::ldexp((x), (y))
|
||||
|
||||
#define cosf(x) sycl::native::cos(((float)(x)))
|
||||
#define sinf(x) sycl::native::sin(((float)(x)))
|
||||
#define powf(x, y) sycl::native::powr(((float)(x)), ((float)(y)))
|
||||
#define tanf(x) sycl::native::tan(((float)(x)))
|
||||
#define logf(x) sycl::native::log(((float)(x)))
|
||||
#define expf(x) sycl::native::exp(((float)(x)))
|
||||
#define sqrtf(x) sycl::native::sqrt(((float)(x)))
|
||||
|
||||
#define __forceinline __attribute__((always_inline))
|
||||
|
||||
/* Types */
|
||||
#include "util/half.h"
|
||||
#include "util/types.h"
|
||||
|
||||
static_assert(
|
||||
sizeof(sycl::ext::oneapi::experimental::sampled_image_handle::raw_image_handle_type) ==
|
||||
sizeof(uint64_t));
|
||||
typedef uint64_t ccl_gpu_image_object_2D;
|
||||
typedef uint64_t ccl_gpu_image_object_3D;
|
||||
|
||||
template<typename T>
|
||||
ccl_device_forceinline T ccl_gpu_image_object_read_2D(const ccl_gpu_image_object_2D texobj,
|
||||
const float x,
|
||||
const float y)
|
||||
{
|
||||
/* Generic implementation not possible due to limitation with SYCL bindless sampled images
|
||||
* not being able to read in a format, which is different from the supported data type of
|
||||
* the texture.
|
||||
* But looks it looks like this is not a problem at the moment. */
|
||||
static_assert(false);
|
||||
return T();
|
||||
}
|
||||
|
||||
template<>
|
||||
ccl_device_forceinline float ccl_gpu_image_object_read_2D<float>(
|
||||
const ccl_gpu_image_object_2D texobj, const float x, const float y)
|
||||
{
|
||||
sycl::ext::oneapi::experimental::sampled_image_handle image(
|
||||
(sycl::ext::oneapi::experimental::sampled_image_handle::raw_image_handle_type)texobj);
|
||||
return sycl::ext::oneapi::experimental::sample_image<float>(image, sycl::float2{x, y});
|
||||
}
|
||||
|
||||
template<>
|
||||
ccl_device_forceinline float4 ccl_gpu_image_object_read_2D<float4>(
|
||||
const ccl_gpu_image_object_2D texobj, const float x, const float y)
|
||||
{
|
||||
sycl::ext::oneapi::experimental::sampled_image_handle image(
|
||||
(sycl::ext::oneapi::experimental::sampled_image_handle::raw_image_handle_type)texobj);
|
||||
return sycl::ext::oneapi::experimental::sample_image<float4, sycl::vec<float, 4>>(
|
||||
image, sycl::float2{x, y});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ccl_device_forceinline T ccl_gpu_image_object_read_3D(const ccl_gpu_image_object_3D texobj,
|
||||
const float x,
|
||||
const float y,
|
||||
const float z)
|
||||
{
|
||||
/* A generic implementation is not possible due to limitations with SYCL bindless sampled images
|
||||
* not being able to read in a format that is different from the supported data type of
|
||||
* the texture.
|
||||
* However, it looks like this is not a problem at the moment, but I am leaving a static
|
||||
* assert in order to easily detect if it becomes a problem in the future. */
|
||||
static_assert(false);
|
||||
return T();
|
||||
}
|
||||
|
||||
template<>
|
||||
ccl_device_forceinline float ccl_gpu_image_object_read_3D<float>(
|
||||
const ccl_gpu_image_object_3D texobj, const float x, const float y, const float z)
|
||||
{
|
||||
sycl::ext::oneapi::experimental::sampled_image_handle image(
|
||||
(sycl::ext::oneapi::experimental::sampled_image_handle::raw_image_handle_type)texobj);
|
||||
return sycl::ext::oneapi::experimental::sample_image<float>(image, sycl::float3{x, y, z});
|
||||
}
|
||||
|
||||
template<>
|
||||
ccl_device_forceinline float4 ccl_gpu_image_object_read_3D<float4>(
|
||||
const ccl_gpu_image_object_3D texobj, const float x, const float y, const float z)
|
||||
{
|
||||
sycl::ext::oneapi::experimental::sampled_image_handle image(
|
||||
(sycl::ext::oneapi::experimental::sampled_image_handle::raw_image_handle_type)texobj);
|
||||
return sycl::ext::oneapi::experimental::sample_image<float4, sycl::vec<float, 4>>(
|
||||
image, sycl::float3{x, y, z});
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "kernel/util/nanovdb.h"
|
||||
|
||||
/* clang-format off */
|
||||
struct ONEAPIKernelContext : public KernelGlobalsGPU {
|
||||
public:
|
||||
# include "kernel/device/gpu/image.h"
|
||||
/* clang-format on */
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
}
|
||||
; /* end of ONEAPIKernelContext class definition */
|
||||
|
||||
#undef kernel_integrator_state
|
||||
#define kernel_integrator_state (*(kg->integrator_state))
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#if defined(WITH_EMBREE_GPU)
|
||||
# undef ccl_gpu_kernel_signature
|
||||
# define ccl_gpu_kernel_signature(name, ...) \
|
||||
void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
|
||||
size_t kernel_global_size, \
|
||||
size_t kernel_local_size, \
|
||||
sycl::handler &cgh, \
|
||||
__VA_ARGS__) \
|
||||
{ \
|
||||
(void)(kg); \
|
||||
cgh.parallel_for( \
|
||||
sycl::nd_range<1>(kernel_global_size, kernel_local_size), \
|
||||
[=](sycl::nd_item<1> item, sycl::kernel_handler oneapi_kernel_handler) { \
|
||||
((ONEAPIKernelContext*)kg)->kernel_handler = oneapi_kernel_handler;
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#if defined(WITH_EMBREE_GPU)
|
||||
# undef ccl_gpu_kernel_signature
|
||||
# define ccl_gpu_kernel_signature __ccl_gpu_kernel_signature
|
||||
#endif
|
||||
47
blender-5.2.0/intern/cycles/kernel/device/oneapi/globals.h
Normal file
47
blender-5.2.0/intern/cycles/kernel/device/oneapi/globals.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Constant Globals */
|
||||
|
||||
#pragma once
|
||||
|
||||
#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
|
||||
|
||||
/* NOTE(@nsirgien): With SYCL we can't declare __constant__ global variable, which will be
|
||||
* accessible from device code, like it has been done for Cycles CUDA backend. So, the backend will
|
||||
* allocate this "constant" memory regions and store pointers to them in oneAPI context class */
|
||||
|
||||
struct IntegratorStateGPU;
|
||||
struct IntegratorQueueCounter;
|
||||
|
||||
struct KernelGlobalsGPU {
|
||||
|
||||
#define KERNEL_DATA_ARRAY(type, name) const type *__##name = nullptr;
|
||||
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) type *__##name = nullptr;
|
||||
#include "kernel/data_arrays.h"
|
||||
IntegratorStateGPU *integrator_state;
|
||||
const KernelData *__data;
|
||||
sycl::kernel_handler kernel_handler;
|
||||
};
|
||||
|
||||
using KernelGlobals = ccl_global KernelGlobalsGPU *ccl_restrict;
|
||||
|
||||
#define kernel_data (*(__data))
|
||||
#define kernel_integrator_state (*(integrator_state))
|
||||
|
||||
/* data lookup defines */
|
||||
|
||||
#define kernel_data_fetch(name, index) __##name[(index)]
|
||||
#define kernel_data_write(name, index, value) __##name[(index)] = (value)
|
||||
#define kernel_data_array(name) __##name
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
758
blender-5.2.0/intern/cycles/kernel/device/oneapi/kernel.cpp
Normal file
758
blender-5.2.0/intern/cycles/kernel/device/oneapi/kernel.cpp
Normal file
@@ -0,0 +1,758 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_ONEAPI
|
||||
|
||||
# include "kernel.h"
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
# include <set>
|
||||
|
||||
/* <algorithm> is needed until included upstream in sycl/detail/property_list_base.hpp */
|
||||
# include <algorithm>
|
||||
# include <sycl/sycl.hpp>
|
||||
|
||||
# include "kernel/device/oneapi/compat.h"
|
||||
# include "kernel/device/oneapi/globals.h"
|
||||
# include "kernel/device/oneapi/kernel_templates.h"
|
||||
|
||||
# include "kernel/device/gpu/kernel.h"
|
||||
|
||||
# include "device/kernel.cpp"
|
||||
|
||||
static OneAPIErrorCallback s_error_cb = nullptr;
|
||||
static void *s_error_user_ptr = nullptr;
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
static RTCFeatureFlags oneapi_embree_features_from_kernel_features(const uint kernel_features)
|
||||
{
|
||||
unsigned int feature_flags = RTC_FEATURE_FLAG_TRIANGLE | RTC_FEATURE_FLAG_INSTANCE |
|
||||
RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS;
|
||||
|
||||
if (kernel_features & KERNEL_FEATURE_HAIR_THICK) {
|
||||
feature_flags |= RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE |
|
||||
RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE;
|
||||
}
|
||||
if (kernel_features & KERNEL_FEATURE_HAIR) {
|
||||
feature_flags |= RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE;
|
||||
}
|
||||
if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
|
||||
feature_flags |= RTC_FEATURE_FLAG_POINT;
|
||||
}
|
||||
if (kernel_features & KERNEL_FEATURE_OBJECT_MOTION) {
|
||||
feature_flags |= RTC_FEATURE_FLAG_MOTION_BLUR;
|
||||
}
|
||||
|
||||
return (RTCFeatureFlags)feature_flags;
|
||||
}
|
||||
# endif
|
||||
|
||||
void oneapi_set_error_cb(OneAPIErrorCallback cb, void *user_ptr)
|
||||
{
|
||||
s_error_cb = cb;
|
||||
s_error_user_ptr = user_ptr;
|
||||
}
|
||||
|
||||
size_t oneapi_suggested_gpu_kernel_size(const DeviceKernel kernel)
|
||||
{
|
||||
/* This defines are available only to the device code, so making this function
|
||||
* seems to be the most reasonable way to provide access to them for the host code. */
|
||||
switch (kernel) {
|
||||
case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
|
||||
return GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE;
|
||||
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES:
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES:
|
||||
return GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE;
|
||||
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORT_BUCKET_PASS:
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORT_WRITE_PASS:
|
||||
return GPU_PARALLEL_SORT_BLOCK_SIZE;
|
||||
|
||||
case DEVICE_KERNEL_PREFIX_SUM:
|
||||
return GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE;
|
||||
|
||||
default:
|
||||
return (size_t)0;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE(@nsirgien): Execution of this simple kernel will check basic functionality like
|
||||
* memory allocations, memory transfers and execution of kernel with USM memory. */
|
||||
bool oneapi_run_test_kernel(SyclQueue *queue_)
|
||||
{
|
||||
assert(queue_);
|
||||
sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
|
||||
const size_t N = 8;
|
||||
const size_t memory_byte_size = sizeof(int) * N;
|
||||
|
||||
bool is_computation_correct = true;
|
||||
try {
|
||||
int *A_host = (int *)sycl::aligned_alloc_host(16, memory_byte_size, *queue);
|
||||
|
||||
for (size_t i = (size_t)0; i < N; i++) {
|
||||
A_host[i] = rand() % 32;
|
||||
}
|
||||
|
||||
int *A_device = (int *)sycl::malloc_device(memory_byte_size, *queue);
|
||||
int *B_device = (int *)sycl::malloc_device(memory_byte_size, *queue);
|
||||
|
||||
queue->memcpy(A_device, A_host, memory_byte_size);
|
||||
queue->wait_and_throw();
|
||||
|
||||
queue->submit([&](sycl::handler &cgh) {
|
||||
cgh.parallel_for(N, [=](sycl::id<1> idx) { B_device[idx] = A_device[idx] + idx.get(0); });
|
||||
});
|
||||
queue->wait_and_throw();
|
||||
|
||||
int *B_host = (int *)sycl::aligned_alloc_host(16, memory_byte_size, *queue);
|
||||
|
||||
queue->memcpy(B_host, B_device, memory_byte_size);
|
||||
queue->wait_and_throw();
|
||||
|
||||
for (size_t i = (size_t)0; i < N; i++) {
|
||||
const int expected_result = i + A_host[i];
|
||||
if (B_host[i] != expected_result) {
|
||||
is_computation_correct = false;
|
||||
if (s_error_cb) {
|
||||
s_error_cb(("Incorrect result in test kernel execution - expected " +
|
||||
std::to_string(expected_result) + ", got " + std::to_string(B_host[i]))
|
||||
.c_str(),
|
||||
s_error_user_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sycl::free(A_host, *queue);
|
||||
sycl::free(B_host, *queue);
|
||||
sycl::free(A_device, *queue);
|
||||
sycl::free(B_device, *queue);
|
||||
queue->wait_and_throw();
|
||||
}
|
||||
catch (const sycl::exception &e) {
|
||||
if (s_error_cb) {
|
||||
s_error_cb(e.what(), s_error_user_ptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_computation_correct;
|
||||
}
|
||||
|
||||
bool oneapi_zero_memory_on_device(SyclQueue *queue_, void *device_pointer, const size_t num_bytes)
|
||||
{
|
||||
assert(queue_);
|
||||
sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
|
||||
try {
|
||||
queue->memset(device_pointer, 0, num_bytes);
|
||||
queue->wait_and_throw();
|
||||
return true;
|
||||
}
|
||||
catch (const sycl::exception &e) {
|
||||
if (s_error_cb) {
|
||||
s_error_cb(e.what(), s_error_user_ptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool oneapi_kernel_is_required_for_features(const std::string &kernel_name,
|
||||
const uint kernel_features)
|
||||
{
|
||||
/* Skip all non-Cycles kernels */
|
||||
if (kernel_name.find("oneapi_kernel_") == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) == 0 &&
|
||||
kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE)) !=
|
||||
std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((kernel_features & KERNEL_FEATURE_MNEE) == 0 &&
|
||||
kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_MNEE)) !=
|
||||
std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((kernel_features & KERNEL_FEATURE_VOLUME) == 0 &&
|
||||
kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK)) !=
|
||||
std::string::npos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((kernel_features & (KERNEL_FEATURE_PATH_TRACING | KERNEL_FEATURE_BAKING)) == 0) &&
|
||||
((kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST)) !=
|
||||
std::string::npos) ||
|
||||
(kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW)) !=
|
||||
std::string::npos) ||
|
||||
(kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE)) !=
|
||||
std::string::npos) ||
|
||||
(kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_MNEE)) !=
|
||||
std::string::npos) ||
|
||||
(kernel_name.find(device_kernel_as_string(
|
||||
DEVICE_KERNEL_INTEGRATOR_INTERSECT_DEDICATED_LIGHT)) != std::string::npos)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool oneapi_kernel_is_compatible_with_hardware_raytracing(const std::string &kernel_name)
|
||||
{
|
||||
/* MNEE and Ray-trace kernels work correctly with Hardware Ray-tracing starting with Embree 4.1.
|
||||
*/
|
||||
# if defined(RTC_VERSION) && RTC_VERSION < 40100
|
||||
return (kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_INTERSECT_MNEE)) ==
|
||||
std::string::npos) &&
|
||||
(kernel_name.find(device_kernel_as_string(
|
||||
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE)) == std::string::npos);
|
||||
# else
|
||||
return true;
|
||||
# endif
|
||||
}
|
||||
|
||||
bool oneapi_kernel_has_intersections(const std::string &kernel_name)
|
||||
{
|
||||
for (int i = 0; i < (int)DEVICE_KERNEL_NUM; i++) {
|
||||
DeviceKernel kernel = (DeviceKernel)i;
|
||||
if (device_kernel_has_intersection(kernel)) {
|
||||
if (kernel_name.find(device_kernel_as_string(kernel)) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool oneapi_load_kernels(SyclQueue *queue_,
|
||||
const uint kernel_features,
|
||||
bool use_hardware_raytracing)
|
||||
{
|
||||
assert(queue_);
|
||||
sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
/* For best performance, we always JIT compile the kernels that are using Embree. */
|
||||
if (use_hardware_raytracing) {
|
||||
try {
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> all_kernels_bundle =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(),
|
||||
{queue->get_device()});
|
||||
|
||||
for (const sycl::kernel_id &kernel_id : all_kernels_bundle.get_kernel_ids()) {
|
||||
const std::string &kernel_name = kernel_id.get_name();
|
||||
|
||||
if (!oneapi_kernel_is_required_for_features(kernel_name, kernel_features) ||
|
||||
!(oneapi_kernel_has_intersections(kernel_name) &&
|
||||
oneapi_kernel_is_compatible_with_hardware_raytracing(kernel_name)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(
|
||||
queue->get_context(), {queue->get_device()}, {kernel_id});
|
||||
|
||||
const RTCFeatureFlags embree_features = oneapi_embree_features_from_kernel_features(
|
||||
kernel_features);
|
||||
one_kernel_bundle_input
|
||||
.set_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>(
|
||||
embree_features);
|
||||
sycl::build(one_kernel_bundle_input);
|
||||
}
|
||||
}
|
||||
catch (const sycl::exception &e) {
|
||||
if (s_error_cb) {
|
||||
s_error_cb(e.what(), s_error_user_ptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
try {
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> all_kernels_bundle =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(),
|
||||
{queue->get_device()});
|
||||
|
||||
for (const sycl::kernel_id &kernel_id : all_kernels_bundle.get_kernel_ids()) {
|
||||
const std::string &kernel_name = kernel_id.get_name();
|
||||
|
||||
/* In case HWRT is on, compilation of kernels using Embree is already handled in previous
|
||||
* block. */
|
||||
if (!oneapi_kernel_is_required_for_features(kernel_name, kernel_features) ||
|
||||
(use_hardware_raytracing && oneapi_kernel_has_intersections(kernel_name) &&
|
||||
oneapi_kernel_is_compatible_with_hardware_raytracing(kernel_name)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
if (oneapi_kernel_has_intersections(kernel_name)) {
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(
|
||||
queue->get_context(), {queue->get_device()}, {kernel_id});
|
||||
one_kernel_bundle_input
|
||||
.set_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>(
|
||||
RTC_FEATURE_FLAG_NONE);
|
||||
sycl::build(one_kernel_bundle_input);
|
||||
continue;
|
||||
}
|
||||
# endif
|
||||
/* This call will ensure that AoT or cached JIT binaries are available
|
||||
* for execution. It will trigger compilation if it is not already the case. */
|
||||
(void)sycl::get_kernel_bundle<sycl::bundle_state::executable>(
|
||||
queue->get_context(), {queue->get_device()}, {kernel_id});
|
||||
}
|
||||
}
|
||||
catch (const sycl::exception &e) {
|
||||
if (s_error_cb) {
|
||||
s_error_cb(e.what(), s_error_user_ptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool oneapi_enqueue_kernel(KernelContext *kernel_context,
|
||||
const int kernel,
|
||||
const size_t global_size,
|
||||
const size_t local_size,
|
||||
const uint kernel_features,
|
||||
bool use_hardware_raytracing,
|
||||
void **args)
|
||||
{
|
||||
bool success = true;
|
||||
::DeviceKernel device_kernel = (::DeviceKernel)kernel;
|
||||
KernelGlobalsGPU *kg = (KernelGlobalsGPU *)kernel_context->kernel_globals;
|
||||
sycl::queue *queue = reinterpret_cast<sycl::queue *>(kernel_context->queue);
|
||||
assert(queue);
|
||||
if (!queue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Let the compiler throw an error if there are any kernels missing in this implementation. */
|
||||
# if defined(_WIN32)
|
||||
# pragma warning(error : 4062)
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic error "-Wswitch"
|
||||
# endif
|
||||
|
||||
int max_shaders = 0;
|
||||
|
||||
if (device_kernel == DEVICE_KERNEL_INTEGRATOR_SORT_BUCKET_PASS ||
|
||||
device_kernel == DEVICE_KERNEL_INTEGRATOR_SORT_WRITE_PASS)
|
||||
{
|
||||
max_shaders = (kernel_context->scene_max_shaders);
|
||||
}
|
||||
|
||||
try {
|
||||
queue->submit([&](sycl::handler &cgh) {
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
/* Spec says it has no effect if the called kernel doesn't support the below specialization
|
||||
* constant but it can still trigger a recompilation, so we set it only if needed. */
|
||||
if (device_kernel_has_intersection(device_kernel)) {
|
||||
const RTCFeatureFlags embree_features = use_hardware_raytracing ?
|
||||
oneapi_embree_features_from_kernel_features(
|
||||
kernel_features) :
|
||||
RTC_FEATURE_FLAG_NONE;
|
||||
cgh.set_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>(
|
||||
embree_features);
|
||||
}
|
||||
# else
|
||||
(void)kernel_features;
|
||||
# endif
|
||||
switch (device_kernel) {
|
||||
case DEVICE_KERNEL_INTEGRATOR_RESET: {
|
||||
oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_reset);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_init_from_camera);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_init_from_bake);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_intersect_closest);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_intersect_shadow);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_intersect_subsurface);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_intersect_volume_stack);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_DEDICATED_LIGHT: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_intersect_dedicated_light);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_MNEE: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_intersect_mnee);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_background);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT_NEE: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_light_nee);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT_FORWARD: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_shade_light_forward);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_shadow);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_surface);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_shade_surface_raytrace);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_volume);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME_RAY_MARCHING: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_shade_volume_ray_marching);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_shade_dedicated_light);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_queued_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_queued_shadow_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_active_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_terminated_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_terminated_shadow_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_sorted_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORT_BUCKET_PASS: {
|
||||
sycl::local_accessor<int> local_mem(max_shaders, cgh);
|
||||
oneapi_kernel_integrator_sort_bucket_pass(kg,
|
||||
global_size,
|
||||
local_size,
|
||||
cgh,
|
||||
*(int *)(args[0]),
|
||||
*(int *)(args[1]),
|
||||
*(int *)(args[2]),
|
||||
*(int **)(args[3]),
|
||||
*(int *)(args[4]),
|
||||
local_mem);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SORT_WRITE_PASS: {
|
||||
sycl::local_accessor<int> local_mem(max_shaders, cgh);
|
||||
oneapi_kernel_integrator_sort_write_pass(kg,
|
||||
global_size,
|
||||
local_size,
|
||||
cgh,
|
||||
*(int *)(args[0]),
|
||||
*(int *)(args[1]),
|
||||
*(int *)(args[2]),
|
||||
*(int **)(args[3]),
|
||||
*(int *)(args[4]),
|
||||
local_mem);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_compact_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_compact_shadow_paths_array);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_adaptive_sampling_convergence_check);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_adaptive_sampling_filter_x);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_adaptive_sampling_filter_y);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_SHADER_EVAL_DISPLACE: {
|
||||
oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_shader_eval_displace);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_SHADER_EVAL_BACKGROUND: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_shader_eval_background);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_shader_eval_curve_shadow_transparency);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_SHADER_EVAL_VOLUME_DENSITY: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_shader_eval_volume_density);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_PREFIX_SUM: {
|
||||
oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_prefix_sum);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_VOLUME_GUIDING_FILTER_X: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_volume_guiding_filter_x);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_VOLUME_GUIDING_FILTER_Y: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_volume_guiding_filter_y);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
# define DEVICE_KERNEL_FILM_CONVERT_PARTIAL(VARIANT, variant) \
|
||||
case DEVICE_KERNEL_FILM_CONVERT_##VARIANT: { \
|
||||
oneapi_call(kg, cgh, \
|
||||
global_size, \
|
||||
local_size, \
|
||||
args, \
|
||||
oneapi_kernel_film_convert_##variant); \
|
||||
break; \
|
||||
}
|
||||
|
||||
# define DEVICE_KERNEL_FILM_CONVERT(variant, VARIANT) \
|
||||
DEVICE_KERNEL_FILM_CONVERT_PARTIAL(VARIANT, variant) \
|
||||
DEVICE_KERNEL_FILM_CONVERT_PARTIAL(VARIANT##_HALF_RGBA, variant##_half_rgba)
|
||||
|
||||
DEVICE_KERNEL_FILM_CONVERT(depth, DEPTH);
|
||||
DEVICE_KERNEL_FILM_CONVERT(mist, MIST);
|
||||
DEVICE_KERNEL_FILM_CONVERT(volume_majorant, VOLUME_MAJORANT);
|
||||
DEVICE_KERNEL_FILM_CONVERT(sample_count, SAMPLE_COUNT);
|
||||
DEVICE_KERNEL_FILM_CONVERT(float, FLOAT);
|
||||
DEVICE_KERNEL_FILM_CONVERT(light_path, LIGHT_PATH);
|
||||
DEVICE_KERNEL_FILM_CONVERT(rgbe, RGBE);
|
||||
DEVICE_KERNEL_FILM_CONVERT(float3, FLOAT3);
|
||||
DEVICE_KERNEL_FILM_CONVERT(motion, MOTION);
|
||||
DEVICE_KERNEL_FILM_CONVERT(cryptomatte, CRYPTOMATTE);
|
||||
DEVICE_KERNEL_FILM_CONVERT(shadow_catcher, SHADOW_CATCHER);
|
||||
DEVICE_KERNEL_FILM_CONVERT(shadow_catcher_matte_with_shadow,
|
||||
SHADOW_CATCHER_MATTE_WITH_SHADOW);
|
||||
DEVICE_KERNEL_FILM_CONVERT(combined, COMBINED);
|
||||
DEVICE_KERNEL_FILM_CONVERT(float4, FLOAT4);
|
||||
|
||||
# undef DEVICE_KERNEL_FILM_CONVERT
|
||||
# undef DEVICE_KERNEL_FILM_CONVERT_PARTIAL
|
||||
/* clang-format on */
|
||||
|
||||
case DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_filter_guiding_preprocess);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_filter_guiding_set_fake_albedo);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_FILTER_COLOR_PREPROCESS: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_filter_color_preprocess);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_filter_color_postprocess);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_FILTER_COLOR_FLIP_Y: {
|
||||
oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_filter_color_flip_y);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_cryptomatte_postprocess);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES: {
|
||||
oneapi_call(
|
||||
kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_compact_states);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_compact_shadow_states);
|
||||
break;
|
||||
}
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS: {
|
||||
oneapi_call(kg,
|
||||
cgh,
|
||||
global_size,
|
||||
local_size,
|
||||
args,
|
||||
oneapi_kernel_integrator_shadow_catcher_count_possible_splits);
|
||||
break;
|
||||
}
|
||||
/* Unsupported kernels */
|
||||
case DEVICE_KERNEL_NUM:
|
||||
case DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL:
|
||||
case DEVICE_KERNEL_INTEGRATOR_SHADOW_PATH_MNEE_PENDING:
|
||||
kernel_assert(0);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (const sycl::exception &e) {
|
||||
if (s_error_cb) {
|
||||
s_error_cb(e.what(), s_error_user_ptr);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(_WIN32)
|
||||
# pragma warning(default : 4062)
|
||||
# elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
return success;
|
||||
}
|
||||
|
||||
#endif /* WITH_ONEAPI */
|
||||
67
blender-5.2.0/intern/cycles/kernel/device/oneapi/kernel.h
Normal file
67
blender-5.2.0/intern/cycles/kernel/device/oneapi/kernel.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef WITH_ONEAPI
|
||||
|
||||
# include <stddef.h>
|
||||
|
||||
/* NOTE(@nsirgien): Should match underlying type in the declaration inside "kernel/types.h"
|
||||
* TODO: use kernel/types.h directly. */
|
||||
enum DeviceKernel : int;
|
||||
|
||||
# ifndef CYCLES_KERNEL_ONEAPI_EXPORT
|
||||
# ifdef _WIN32
|
||||
# if defined(ONEAPI_EXPORT)
|
||||
# define CYCLES_KERNEL_ONEAPI_EXPORT extern __declspec(dllexport)
|
||||
# else
|
||||
# define CYCLES_KERNEL_ONEAPI_EXPORT extern __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# define CYCLES_KERNEL_ONEAPI_EXPORT extern __attribute__((visibility("default")))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
class SyclQueue;
|
||||
class SyclDevice;
|
||||
|
||||
typedef void (*OneAPIErrorCallback)(const char *error, void *user_ptr);
|
||||
|
||||
struct KernelContext {
|
||||
/* Queue, associated with selected device */
|
||||
SyclQueue *queue = nullptr;
|
||||
/* Pointer to USM device memory with all global/constant allocation on this device */
|
||||
void *kernel_globals = nullptr;
|
||||
/* We needs this additional data for some kernels. */
|
||||
int scene_max_shaders = 0;
|
||||
};
|
||||
|
||||
/* Use extern C linking so that the symbols can be easily load from the dynamic library at runtime.
|
||||
*/
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_run_test_kernel(SyclQueue *queue_);
|
||||
CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_zero_memory_on_device(SyclQueue *queue_,
|
||||
void *device_pointer,
|
||||
size_t num_bytes);
|
||||
CYCLES_KERNEL_ONEAPI_EXPORT void oneapi_set_error_cb(OneAPIErrorCallback cb, void *user_ptr);
|
||||
CYCLES_KERNEL_ONEAPI_EXPORT size_t oneapi_suggested_gpu_kernel_size(const DeviceKernel kernel);
|
||||
CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_enqueue_kernel(KernelContext *context,
|
||||
const int kernel,
|
||||
const size_t global_size,
|
||||
const size_t local_size,
|
||||
const unsigned int kernel_features,
|
||||
bool use_hardware_raytracing,
|
||||
void **args);
|
||||
CYCLES_KERNEL_ONEAPI_EXPORT bool oneapi_load_kernels(SyclQueue *queue,
|
||||
const unsigned int kernel_features,
|
||||
bool use_hardware_raytracing);
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif /* WITH_ONEAPI */
|
||||
@@ -0,0 +1,124 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
/* Some macro magic to generate templates for kernel arguments.
|
||||
* The resulting oneapi_call() template allows to call a SYCL/C++ kernel
|
||||
* with typed arguments by only giving it a void `**args` as given by Cycles.
|
||||
* The template will automatically cast from void* to the expected type. */
|
||||
|
||||
/* When expanded by the preprocessor, the generated templates will look like this example: */
|
||||
#if 0
|
||||
template<typename T0, typename T1, typename T2>
|
||||
void oneapi_call(
|
||||
KernelGlobalsGPU *kg,
|
||||
sycl::handler &cgh,
|
||||
const size_t global_size,
|
||||
const size_t local_size,
|
||||
void **args,
|
||||
void (*func)(const KernelGlobalsGPU *, size_t, size_t, sycl::handler &, T0, T1, T2))
|
||||
{
|
||||
func(kg, global_size, local_size, cgh, *(T0 *)(args[0]), *(T1 *)(args[1]), *(T2 *)(args[2]));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* clang-format off */
|
||||
#define ONEAPI_TYP(x) typename T##x
|
||||
#define ONEAPI_CAST(x) *(T##x *)(args[x])
|
||||
#define ONEAPI_T(x) T##x
|
||||
|
||||
#define ONEAPI_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, N, ...) N
|
||||
#define ONEAPI_0(_call, ...)
|
||||
#define ONEAPI_1(_call, x) _call(x)
|
||||
#define ONEAPI_2(_call, x, ...) _call(x), ONEAPI_1(_call, __VA_ARGS__)
|
||||
#define ONEAPI_3(_call, x, ...) _call(x), ONEAPI_2(_call, __VA_ARGS__)
|
||||
#define ONEAPI_4(_call, x, ...) _call(x), ONEAPI_3(_call, __VA_ARGS__)
|
||||
#define ONEAPI_5(_call, x, ...) _call(x), ONEAPI_4(_call, __VA_ARGS__)
|
||||
#define ONEAPI_6(_call, x, ...) _call(x), ONEAPI_5(_call, __VA_ARGS__)
|
||||
#define ONEAPI_7(_call, x, ...) _call(x), ONEAPI_6(_call, __VA_ARGS__)
|
||||
#define ONEAPI_8(_call, x, ...) _call(x), ONEAPI_7(_call, __VA_ARGS__)
|
||||
#define ONEAPI_9(_call, x, ...) _call(x), ONEAPI_8(_call, __VA_ARGS__)
|
||||
#define ONEAPI_10(_call, x, ...) _call(x), ONEAPI_9(_call, __VA_ARGS__)
|
||||
#define ONEAPI_11(_call, x, ...) _call(x), ONEAPI_10(_call, __VA_ARGS__)
|
||||
#define ONEAPI_12(_call, x, ...) _call(x), ONEAPI_11(_call, __VA_ARGS__)
|
||||
#define ONEAPI_13(_call, x, ...) _call(x), ONEAPI_12(_call, __VA_ARGS__)
|
||||
#define ONEAPI_14(_call, x, ...) _call(x), ONEAPI_13(_call, __VA_ARGS__)
|
||||
#define ONEAPI_15(_call, x, ...) _call(x), ONEAPI_14(_call, __VA_ARGS__)
|
||||
#define ONEAPI_16(_call, x, ...) _call(x), ONEAPI_15(_call, __VA_ARGS__)
|
||||
#define ONEAPI_17(_call, x, ...) _call(x), ONEAPI_16(_call, __VA_ARGS__)
|
||||
#define ONEAPI_18(_call, x, ...) _call(x), ONEAPI_17(_call, __VA_ARGS__)
|
||||
#define ONEAPI_19(_call, x, ...) _call(x), ONEAPI_18(_call, __VA_ARGS__)
|
||||
#define ONEAPI_20(_call, x, ...) _call(x), ONEAPI_19(_call, __VA_ARGS__)
|
||||
#define ONEAPI_21(_call, x, ...) _call(x), ONEAPI_20(_call, __VA_ARGS__)
|
||||
|
||||
#define ONEAPI_CALL_FOR(x, ...) \
|
||||
ONEAPI_GET_NTH_ARG("ignored", \
|
||||
##__VA_ARGS__, \
|
||||
ONEAPI_21, \
|
||||
ONEAPI_20, \
|
||||
ONEAPI_19, \
|
||||
ONEAPI_18, \
|
||||
ONEAPI_17, \
|
||||
ONEAPI_16, \
|
||||
ONEAPI_15, \
|
||||
ONEAPI_14, \
|
||||
ONEAPI_13, \
|
||||
ONEAPI_12, \
|
||||
ONEAPI_11, \
|
||||
ONEAPI_10, \
|
||||
ONEAPI_9, \
|
||||
ONEAPI_8, \
|
||||
ONEAPI_7, \
|
||||
ONEAPI_6, \
|
||||
ONEAPI_5, \
|
||||
ONEAPI_4, \
|
||||
ONEAPI_3, \
|
||||
ONEAPI_2, \
|
||||
ONEAPI_1, \
|
||||
ONEAPI_0) \
|
||||
(x, ##__VA_ARGS__)
|
||||
|
||||
/* This template automatically casts entries in the void **args array to the types requested by the kernel func.
|
||||
* Since kernel parameters are passed as void ** to the device, this is the closest that we have to type safety. */
|
||||
#define oneapi_template(...) \
|
||||
template<ONEAPI_CALL_FOR(ONEAPI_TYP, __VA_ARGS__)> \
|
||||
void oneapi_call( \
|
||||
KernelGlobalsGPU *kg, \
|
||||
sycl::handler &cgh, \
|
||||
size_t global_size, \
|
||||
size_t local_size, \
|
||||
void **args, \
|
||||
void (*func)(KernelGlobalsGPU*, size_t, size_t, sycl::handler &, ONEAPI_CALL_FOR(ONEAPI_T, __VA_ARGS__))) \
|
||||
{ \
|
||||
func(kg, \
|
||||
global_size, \
|
||||
local_size, \
|
||||
cgh, \
|
||||
ONEAPI_CALL_FOR(ONEAPI_CAST, __VA_ARGS__)); \
|
||||
}
|
||||
|
||||
oneapi_template(0)
|
||||
oneapi_template(0, 1)
|
||||
oneapi_template(0, 1, 2)
|
||||
oneapi_template(0, 1, 2, 3)
|
||||
oneapi_template(0, 1, 2, 3, 4)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
|
||||
oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
|
||||
|
||||
/* clang-format on */
|
||||
160
blender-5.2.0/intern/cycles/kernel/device/optix/CMakeLists.txt
Normal file
160
blender-5.2.0/intern/cycles/kernel/device/optix/CMakeLists.txt
Normal file
@@ -0,0 +1,160 @@
|
||||
# SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(INC
|
||||
../../..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC_KERNEL_DEVICE_OPTIX
|
||||
kernel.cu
|
||||
kernel_mnee.cu
|
||||
kernel_shader_raytrace.cu
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_OSL)
|
||||
math(EXPR OSL_LIBRARY_VERSION_CODE "${OSL_VERSION_MAJOR} * 10000 + ${OSL_VERSION_MINOR} * 100 + ${OSL_VERSION_PATCH}")
|
||||
|
||||
set(SRC_KERNEL_DEVICE_OPTIX
|
||||
${SRC_KERNEL_DEVICE_OPTIX}
|
||||
../../osl/services_optix.cu
|
||||
kernel_osl.cu
|
||||
kernel_osl_camera.cu
|
||||
kernel_osl_mnee.cu
|
||||
kernel_osl_shader_raytrace.cu
|
||||
kernel_osl_volume.cu
|
||||
)
|
||||
endif()
|
||||
|
||||
set(SRC_KERNEL_DEVICE_OPTIX_HEADERS
|
||||
bvh.h
|
||||
compat.h
|
||||
globals.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_CUDA_BINARIES AND WITH_CYCLES_DEVICE_OPTIX)
|
||||
# CUDA version
|
||||
cuda_get_version(CUDA_VERSION)
|
||||
|
||||
# Modifies in parent scope:
|
||||
# - `optix_ptx`: appended with compressed ptx output.
|
||||
function(cycles_optix_kernel_add name input flags)
|
||||
set(output "${CMAKE_CURRENT_BINARY_DIR}/${name}.ptx")
|
||||
set(output_compressed "${output}.zst")
|
||||
|
||||
set(cuda_flags ${flags}
|
||||
-I "${OPTIX_INCLUDE_DIR}"
|
||||
-I "${CMAKE_CURRENT_SOURCE_DIR}/../../.."
|
||||
-o ${output})
|
||||
|
||||
if(WITH_CYCLES_OSL)
|
||||
set(cuda_flags ${cuda_flags}
|
||||
-D OSL_LIBRARY_VERSION_CODE=${OSL_LIBRARY_VERSION_CODE})
|
||||
endif()
|
||||
|
||||
set(arch compute_50)
|
||||
set(cuda_nvcc_executable ${CUDA_NVCC_EXECUTABLE})
|
||||
set(cuda_version ${CUDA_VERSION})
|
||||
if("${CUDA_VERSION}" GREATER_EQUAL 130) # Support for Maxwell, Pascal and Volta was dropped in CUDA 13
|
||||
if(DEFINED CUDA11_NVCC_EXECUTABLE)
|
||||
# Use CUDA 11 for the OptiX PTX kernel, to retain support for older architectures.
|
||||
set(cuda_nvcc_executable ${CUDA11_NVCC_EXECUTABLE})
|
||||
set(cuda_version 110)
|
||||
else()
|
||||
set(arch compute_75)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cuda_add_common_flags(${cuda_version} ${arch} "${cuda_flags}" cuda_flags)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${output}
|
||||
DEPENDS
|
||||
${input}
|
||||
${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
|
||||
$<TARGET_PROPERTY:cycles_kernel,INTERFACE_SOURCES>
|
||||
COMMAND
|
||||
${cuda_nvcc_executable}
|
||||
--ptx
|
||||
-arch=${arch}
|
||||
${cuda_flags}
|
||||
${input}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
unset(cuda_nvcc_executable)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_compressed}
|
||||
COMMAND "$<TARGET_FILE:zstd_compress>" ${output} ${output_compressed}
|
||||
DEPENDS ${output})
|
||||
|
||||
list(APPEND optix_ptx ${output_compressed})
|
||||
set(optix_ptx "${optix_ptx}" PARENT_SCOPE)
|
||||
|
||||
delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${output_compressed}" ${CYCLES_INSTALL_PATH}/lib)
|
||||
endfunction()
|
||||
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix
|
||||
"kernel.cu"
|
||||
"")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_mnee
|
||||
"kernel_mnee.cu"
|
||||
"")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_shader_raytrace
|
||||
"kernel_shader_raytrace.cu"
|
||||
"--keep-device-functions")
|
||||
if(WITH_CYCLES_OSL)
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_osl
|
||||
"kernel_osl.cu"
|
||||
"--relocatable-device-code=true")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_osl_shader_raytrace
|
||||
"kernel_osl_shader_raytrace.cu"
|
||||
"--relocatable-device-code=true")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_osl_mnee
|
||||
"kernel_osl_mnee.cu"
|
||||
"--relocatable-device-code=true")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_osl_volume
|
||||
"kernel_osl_volume.cu"
|
||||
"--relocatable-device-code=true")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_osl_camera
|
||||
"kernel_osl_camera.cu"
|
||||
"--relocatable-device-code=true")
|
||||
cycles_optix_kernel_add(
|
||||
kernel_optix_osl_services
|
||||
"../../osl/services_optix.cu"
|
||||
"--relocatable-device-code=true")
|
||||
endif()
|
||||
|
||||
add_custom_target(cycles_kernel_optix
|
||||
ALL
|
||||
DEPENDS ${optix_ptx}
|
||||
SOURCES ${SRC_KERNEL_DEVICE_OPTIX} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
|
||||
)
|
||||
cycles_set_solution_folder(cycles_kernel_optix)
|
||||
|
||||
source_group("device\\optix" FILES ${SRC_KERNEL_DEVICE_OPTIX} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS})
|
||||
|
||||
add_dependencies(cycles_kernel cycles_kernel_optix)
|
||||
endif()
|
||||
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_OPTIX}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix)
|
||||
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_OPTIX_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix)
|
||||
644
blender-5.2.0/intern/cycles/kernel/device/optix/bvh.h
Normal file
644
blender-5.2.0/intern/cycles/kernel/device/optix/bvh.h
Normal file
@@ -0,0 +1,644 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* OptiX implementation of ray-scene intersection.
|
||||
*
|
||||
* Note on the payload registers.
|
||||
* Intersection and filtering functions might be sharing the same registers, even if it is not
|
||||
* very obvious from the trace/traverse call. The registers that have special meaning and are to
|
||||
* be kept "locked" to their meaning:
|
||||
* uint p4 = visibility;
|
||||
* uint p6 = pointer_pack_to_uint_0(ray);
|
||||
* uint p7 = pointer_pack_to_uint_1(ray); */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kernel/bvh/types.h"
|
||||
#include "kernel/bvh/util.h"
|
||||
|
||||
#define OPTIX_DEFINE_ABI_VERSION_ONLY
|
||||
#include <optix_function_table.h>
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Utilities. */
|
||||
|
||||
template<typename T> ccl_device_forceinline T *get_payload_ptr_0()
|
||||
{
|
||||
return pointer_unpack_from_uint<T>(optixGetPayload_0(), optixGetPayload_1());
|
||||
}
|
||||
template<typename T> ccl_device_forceinline T *get_payload_ptr_2()
|
||||
{
|
||||
return pointer_unpack_from_uint<T>(optixGetPayload_2(), optixGetPayload_3());
|
||||
}
|
||||
|
||||
template<typename T> ccl_device_forceinline T *get_payload_ptr_6()
|
||||
{
|
||||
return (T *)(((uint64_t)optixGetPayload_7() << 32) | optixGetPayload_6());
|
||||
}
|
||||
|
||||
ccl_device_forceinline int get_object_id()
|
||||
{
|
||||
#ifdef __OBJECT_MOTION__
|
||||
/* Always get the instance ID from the TLAS
|
||||
* There might be a motion transform node between TLAS and BLAS which does not have one. */
|
||||
return optixGetInstanceIdFromHandle(optixGetTransformListHandle(0));
|
||||
#else
|
||||
return optixGetInstanceId();
|
||||
#endif
|
||||
}
|
||||
|
||||
ccl_device_forceinline Intersection get_intersection()
|
||||
{
|
||||
Intersection isect;
|
||||
|
||||
isect.t = optixGetRayTmax();
|
||||
isect.prim = optixGetPrimitiveIndex();
|
||||
isect.object = get_object_id();
|
||||
|
||||
if (optixIsTriangleHit()) {
|
||||
/* Triangle. */
|
||||
const float2 barycentrics = optixGetTriangleBarycentrics();
|
||||
isect.u = barycentrics.x;
|
||||
isect.v = barycentrics.y;
|
||||
isect.type = kernel_data_fetch(objects, isect.object).primitive_type;
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
|
||||
/* Curve. */
|
||||
isect.u = __uint_as_float(optixGetAttribute_0());
|
||||
isect.v = __uint_as_float(optixGetAttribute_1());
|
||||
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, isect.prim);
|
||||
isect.type = segment.type;
|
||||
isect.prim = segment.prim;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* Point. */
|
||||
isect.u = 0.0f;
|
||||
isect.v = 0.0f;
|
||||
isect.type = kernel_data_fetch(objects, isect.object).primitive_type;
|
||||
}
|
||||
|
||||
return isect;
|
||||
}
|
||||
|
||||
/* Hit/miss functions. */
|
||||
|
||||
extern "C" __global__ void __miss__kernel_optix_miss()
|
||||
{
|
||||
/* 'kernel_path_lamp_emission' checks intersection distance, so need to set it even on a miss. */
|
||||
optixSetPayload_0(__float_as_uint(optixGetRayTmax()));
|
||||
optixSetPayload_5(PRIMITIVE_NONE);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_ignore()
|
||||
{
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
extern "C" __global__ void __closesthit__kernel_optix_ignore() {}
|
||||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_local_hit()
|
||||
{
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (!optixIsTriangleHit()) {
|
||||
/* Ignore curves and points. */
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __BVH_LOCAL__
|
||||
const int object = get_object_id();
|
||||
if (object != optixGetPayload_4() /* local_object */) {
|
||||
/* Only intersect with matching object. */
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
if (intersection_skip_self_local(ray->self, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
const uint max_hits = optixGetPayload_5();
|
||||
if (max_hits == 0) {
|
||||
/* Special case for when no hit information is requested, just report that something was hit */
|
||||
optixSetPayload_5(true);
|
||||
return optixTerminateRay();
|
||||
}
|
||||
|
||||
const float isect_t = optixGetRayTmax();
|
||||
uint *const lcg_state = get_payload_ptr_0<uint>();
|
||||
LocalIntersection *const local_isect = get_payload_ptr_2<LocalIntersection>();
|
||||
|
||||
const int hit_index = local_intersect_get_record_index(
|
||||
local_isect, isect_t, lcg_state, max_hits);
|
||||
if (hit_index == -1) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
Intersection *isect = &local_isect->hits[hit_index];
|
||||
isect->t = isect_t;
|
||||
isect->prim = prim;
|
||||
isect->object = get_object_id();
|
||||
isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
|
||||
|
||||
const float2 barycentrics = optixGetTriangleBarycentrics();
|
||||
isect->u = barycentrics.x;
|
||||
isect->v = barycentrics.y;
|
||||
|
||||
/* Record geometric normal. */
|
||||
const int position_offset = kernel_data_fetch(objects, object).position_offset;
|
||||
const packed_uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
|
||||
const float3 tri_a = kernel_data_fetch(tri_verts, position_offset + tri_vindex.x);
|
||||
const float3 tri_b = kernel_data_fetch(tri_verts, position_offset + tri_vindex.y);
|
||||
const float3 tri_c = kernel_data_fetch(tri_verts, position_offset + tri_vindex.z);
|
||||
|
||||
local_isect->Ng[hit_index] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
|
||||
|
||||
/* Continue tracing (without this the trace call would return after the first hit). */
|
||||
optixIgnoreIntersection();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
|
||||
{
|
||||
#ifdef __TRANSPARENT_SHADOWS__
|
||||
KernelGlobals kg = nullptr;
|
||||
|
||||
ccl_private BVHShadowAllPayload *payload = get_payload_ptr_0<BVHShadowAllPayload>();
|
||||
const uint ray_visibility = optixGetPayload_4();
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
|
||||
Intersection isect = get_intersection();
|
||||
if (!bvh_shadow_all_anyhit_filter<ISECT_TEST_ALL>(
|
||||
kg, payload->state, *payload, ray->self, ray_visibility, isect))
|
||||
{
|
||||
optixTerminateRay();
|
||||
return;
|
||||
}
|
||||
|
||||
/* The idea here is to accept the hit, so that traversal won't consider any more hits beyond the
|
||||
* distance of the current hit anymore.
|
||||
*
|
||||
* We could accept the hit which is furthest away from the ones that are already recorded (for
|
||||
* this `>` needs to be replaced with `>=`). However, doing so has a performance impact in the
|
||||
* pabellon benchmark scene. The hypothesis here is that allowing to traverse one extra hit after
|
||||
* the array is filled allows to hit an opaque surface and do early exit from the shadow shading.
|
||||
*
|
||||
* Similar to this logic (allowing an extra hit) was in the original OptiX integration, so we
|
||||
* just keep following it to avoid performance regression. There is no the correct solution here,
|
||||
* as it depends on the scene. For example, if there are many transparent surfaces with no opaque
|
||||
* hit then it is faster to start accepting hits as soon as possible. However, if there are many
|
||||
* transparent surfaces, followed up with an opaque surface, it is faster to not accept any hit
|
||||
* and allow the opaque optimization to lead to an early output from the intersect-shade loop. */
|
||||
if (isect.t > payload->max_record_isect_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
optixIgnoreIntersection();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_volume_test()
|
||||
{
|
||||
#if defined(__HAIR__) || defined(__POINTCLOUD__)
|
||||
if (!optixIsTriangleHit()) {
|
||||
/* Ignore curves. */
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
#endif
|
||||
|
||||
KernelGlobals kg = nullptr;
|
||||
|
||||
const int object = get_object_id();
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
const uint ray_visibility = optixGetPayload_4();
|
||||
|
||||
if (bvh_volume_anyhit_triangle_filter(kg, object, prim, ray->self, ray_visibility)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
|
||||
{
|
||||
const uint object = get_object_id();
|
||||
const uint visibility = optixGetPayload_4();
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
#endif
|
||||
|
||||
int prim = optixGetPrimitiveIndex();
|
||||
if (optixIsTriangleHit()) {
|
||||
/* Triangle. */
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
|
||||
/* Curve. */
|
||||
prim = kernel_data_fetch(curve_segments, prim).prim;
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
|
||||
if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE) {
|
||||
#ifdef __SHADOW_LINKING__
|
||||
if (intersection_skip_shadow_link(nullptr, ray->self, object)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intersection_skip_self_shadow(ray->self, object, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
else {
|
||||
/* Shadow ray early termination. */
|
||||
return optixTerminateRay();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (intersection_skip_self(ray->self, object, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __global__ void __closesthit__kernel_optix_hit()
|
||||
{
|
||||
const int object = get_object_id();
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
|
||||
optixSetPayload_0(__float_as_uint(optixGetRayTmax())); /* Intersection distance */
|
||||
optixSetPayload_4(object);
|
||||
|
||||
if (optixIsTriangleHit()) {
|
||||
const float2 barycentrics = optixGetTriangleBarycentrics();
|
||||
optixSetPayload_1(__float_as_uint(barycentrics.x));
|
||||
optixSetPayload_2(__float_as_uint(barycentrics.y));
|
||||
optixSetPayload_3(prim);
|
||||
optixSetPayload_5(kernel_data_fetch(objects, object).primitive_type);
|
||||
}
|
||||
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
|
||||
optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */
|
||||
optixSetPayload_2(optixGetAttribute_1());
|
||||
optixSetPayload_3(segment.prim);
|
||||
optixSetPayload_5(segment.type);
|
||||
}
|
||||
else {
|
||||
optixSetPayload_1(0);
|
||||
optixSetPayload_2(0);
|
||||
optixSetPayload_3(prim);
|
||||
optixSetPayload_5(kernel_data_fetch(objects, object).primitive_type);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom primitive intersection functions. */
|
||||
|
||||
#ifdef __HAIR__
|
||||
ccl_device_inline void optix_intersection_curve(const int prim, const int type)
|
||||
{
|
||||
const int object = get_object_id();
|
||||
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
const uint visibility = optixGetPayload_4();
|
||||
if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
const float3 ray_P = optixGetObjectRayOrigin();
|
||||
const float3 ray_D = optixGetObjectRayDirection();
|
||||
const float ray_tmin = optixGetRayTmin();
|
||||
|
||||
# ifdef __OBJECT_MOTION__
|
||||
const float time = optixGetRayTime();
|
||||
# else
|
||||
const float time = 0.0f;
|
||||
# endif
|
||||
|
||||
Intersection isect;
|
||||
isect.t = optixGetRayTmax();
|
||||
|
||||
if (curve_intersect(nullptr, &isect, ray_P, ray_D, ray_tmin, isect.t, object, prim, time, type))
|
||||
{
|
||||
static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
|
||||
optixReportIntersection(isect.t,
|
||||
type & PRIMITIVE_ALL,
|
||||
__float_as_int(isect.u), /* Attribute_0 */
|
||||
__float_as_int(isect.v)); /* Attribute_1 */
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __global__ void __intersection__curve_ribbon()
|
||||
{
|
||||
const KernelCurveSegment segment = kernel_data_fetch(curve_segments, optixGetPrimitiveIndex());
|
||||
const int prim = segment.prim;
|
||||
const int type = segment.type;
|
||||
if ((type & PRIMITIVE_CURVE) == PRIMITIVE_CURVE_RIBBON) {
|
||||
optix_intersection_curve(prim, type);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __POINTCLOUD__
|
||||
extern "C" __global__ void __intersection__point()
|
||||
{
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
const int object = get_object_id();
|
||||
const int type = kernel_data_fetch(objects, object).primitive_type;
|
||||
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
const uint visibility = optixGetPayload_4();
|
||||
if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
const float3 ray_P = optixGetObjectRayOrigin();
|
||||
const float3 ray_D = optixGetObjectRayDirection();
|
||||
const float ray_tmin = optixGetRayTmin();
|
||||
|
||||
# ifdef __OBJECT_MOTION__
|
||||
const float time = optixGetRayTime();
|
||||
# else
|
||||
const float time = 0.0f;
|
||||
# endif
|
||||
|
||||
Intersection isect;
|
||||
isect.t = optixGetRayTmax();
|
||||
|
||||
if (point_intersect(nullptr, &isect, ray_P, ray_D, ray_tmin, isect.t, object, prim, time, type))
|
||||
{
|
||||
static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
|
||||
optixReportIntersection(isect.t, type & PRIMITIVE_ALL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Scene intersection. */
|
||||
|
||||
ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility,
|
||||
ccl_private Intersection *isect)
|
||||
{
|
||||
/* Note: some registers have hardcoded meaning.
|
||||
* Be careful when changing the values here. See the note at the top of this file for more
|
||||
* details. */
|
||||
uint p0 = 0;
|
||||
uint p1 = 0;
|
||||
uint p2 = 0;
|
||||
uint p3 = 0;
|
||||
uint p4 = visibility;
|
||||
uint p5 = PRIMITIVE_NONE;
|
||||
uint p6 = pointer_pack_to_uint_0(ray);
|
||||
uint p7 = pointer_pack_to_uint_1(ray);
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
uint ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
else if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE) {
|
||||
ray_flags |= OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
|
||||
}
|
||||
|
||||
optixTrace(intersection_ray_valid(ray) ? kernel_data.device_bvh : 0,
|
||||
ray->P,
|
||||
ray->D,
|
||||
ray->tmin,
|
||||
ray->tmax,
|
||||
ray->time,
|
||||
ray_mask,
|
||||
ray_flags,
|
||||
0, /* SBT offset for PG_HITD */
|
||||
0,
|
||||
0,
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
isect->t = __uint_as_float(p0);
|
||||
isect->u = __uint_as_float(p1);
|
||||
isect->v = __uint_as_float(p2);
|
||||
isect->prim = p3;
|
||||
isect->object = p4;
|
||||
isect->type = p5;
|
||||
|
||||
return p5 != PRIMITIVE_NONE;
|
||||
}
|
||||
|
||||
ccl_device_intersect bool scene_intersect_shadow(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
const uint visibility)
|
||||
{
|
||||
/* Note: some registers have hardcoded meaning.
|
||||
* Be careful when changing the values here. See the note at the top of this file for more
|
||||
* details. */
|
||||
uint p0 = 0;
|
||||
uint p1 = 0;
|
||||
uint p2 = 0;
|
||||
uint p3 = 0;
|
||||
uint p4 = visibility;
|
||||
uint p5 = PRIMITIVE_NONE;
|
||||
uint p6 = pointer_pack_to_uint_0(ray);
|
||||
uint p7 = pointer_pack_to_uint_1(ray);
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
uint ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
else if (visibility & PATH_RAY_VISIBILITY_SHADOW_OPAQUE) {
|
||||
ray_flags |= OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
|
||||
}
|
||||
|
||||
optixTraverse(intersection_ray_valid(ray) ? kernel_data.device_bvh : 0,
|
||||
ray->P,
|
||||
ray->D,
|
||||
ray->tmin,
|
||||
ray->tmax,
|
||||
ray->time,
|
||||
ray_mask,
|
||||
ray_flags,
|
||||
0, /* SBT offset for PG_HITD */
|
||||
0,
|
||||
0,
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
return optixHitObjectIsHit();
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
/* Note: some registers have hardcoded meaning.
|
||||
* Be careful when changing the values here. See the note at the top of this file for more
|
||||
* details. */
|
||||
uint p0 = pointer_pack_to_uint_0(lcg_state);
|
||||
uint p1 = pointer_pack_to_uint_1(lcg_state);
|
||||
uint p2 = pointer_pack_to_uint_0(local_isect);
|
||||
uint p3 = pointer_pack_to_uint_1(local_isect);
|
||||
uint p4 = local_object;
|
||||
uint p6 = pointer_pack_to_uint_0(ray);
|
||||
uint p7 = pointer_pack_to_uint_1(ray);
|
||||
|
||||
/* Is set to zero on miss or if ray is aborted, so can be used as return value. */
|
||||
uint p5 = max_hits;
|
||||
|
||||
if (local_isect) {
|
||||
local_isect->num_hits = 0; /* Initialize hit count to zero. */
|
||||
}
|
||||
optixTraverse(intersection_ray_valid(ray) ? kernel_data.device_bvh : 0,
|
||||
ray->P,
|
||||
ray->D,
|
||||
ray->tmin,
|
||||
ray->tmax,
|
||||
ray->time,
|
||||
0xFF,
|
||||
/* Need to always call into __anyhit__kernel_optix_local_hit. */
|
||||
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
|
||||
2, /* SBT offset for PG_HITL */
|
||||
0,
|
||||
0,
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
return p5;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TRANSPARENT_SHADOWS__
|
||||
ccl_device_intersect void scene_intersect_shadow_all_optix(
|
||||
const ccl_private Ray *ccl_restrict ray,
|
||||
const uint ray_visibility,
|
||||
ccl_private BVHShadowAllPayload &ccl_restrict payload)
|
||||
{
|
||||
/* Note: some registers have hardcoded meaning.
|
||||
* Be careful when changing the values here. See the note at the top of this file for more
|
||||
* details. */
|
||||
uint p0 = pointer_pack_to_uint_0(&payload);
|
||||
uint p1 = pointer_pack_to_uint_1(&payload);
|
||||
uint p2 = 0;
|
||||
uint p3 = 0;
|
||||
uint p4 = ray_visibility;
|
||||
uint p5 = 0;
|
||||
uint p6 = pointer_pack_to_uint_0(ray);
|
||||
uint p7 = pointer_pack_to_uint_1(ray);
|
||||
|
||||
uint ray_mask = ray_visibility & 0xFF;
|
||||
if (0 == ray_mask && (ray_visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
|
||||
optixTraverse(intersection_ray_valid(ray) ? kernel_data.device_bvh : 0,
|
||||
ray->P,
|
||||
ray->D,
|
||||
ray->tmin,
|
||||
ray->tmax,
|
||||
ray->time,
|
||||
ray_mask,
|
||||
/* Need to always call into __anyhit__kernel_optix_shadow_all_hit. */
|
||||
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
|
||||
1, /* SBT offset for PG_HITS */
|
||||
0,
|
||||
0,
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
||||
const ccl_private Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
const uint visibility)
|
||||
{
|
||||
/* Note: some registers have hardcoded meaning.
|
||||
* Be careful when changing the values here. See the note at the top of this file for more
|
||||
* details. */
|
||||
uint p0 = 0;
|
||||
uint p1 = 0;
|
||||
uint p2 = 0;
|
||||
uint p3 = 0;
|
||||
uint p4 = visibility;
|
||||
uint p5 = PRIMITIVE_NONE;
|
||||
uint p6 = pointer_pack_to_uint_0(ray);
|
||||
uint p7 = pointer_pack_to_uint_1(ray);
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
}
|
||||
|
||||
optixTrace(intersection_ray_valid(ray) ? kernel_data.device_bvh : 0,
|
||||
ray->P,
|
||||
ray->D,
|
||||
ray->tmin,
|
||||
ray->tmax,
|
||||
ray->time,
|
||||
ray_mask,
|
||||
/* Need to always call into __anyhit__kernel_optix_volume_test. */
|
||||
OPTIX_RAY_FLAG_ENFORCE_ANYHIT,
|
||||
3, /* SBT offset for PG_HITV */
|
||||
0,
|
||||
0,
|
||||
p0,
|
||||
p1,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
isect->t = __uint_as_float(p0);
|
||||
isect->u = __uint_as_float(p1);
|
||||
isect->v = __uint_as_float(p2);
|
||||
isect->prim = p3;
|
||||
isect->object = p4;
|
||||
isect->type = p5;
|
||||
|
||||
return p5 != PRIMITIVE_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
100
blender-5.2.0/intern/cycles/kernel/device/optix/compat.h
Normal file
100
blender-5.2.0/intern/cycles/kernel/device/optix/compat.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* SPDX-FileCopyrightText: 2019 NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2019-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __KERNEL_GPU__
|
||||
#define __KERNEL_CUDA__ /* OptiX kernels are implicitly CUDA kernels too */
|
||||
#define __KERNEL_OPTIX__
|
||||
#define CCL_NAMESPACE_BEGIN
|
||||
#define CCL_NAMESPACE_END
|
||||
|
||||
#ifndef ATTR_FALLTHROUGH
|
||||
# define ATTR_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
/* Manual definitions so we can compile without CUDA toolkit. */
|
||||
|
||||
#ifdef __CUDACC_RTC__
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef CYCLES_CUBIN_CC
|
||||
# define FLT_MIN 1.175494350822287507969e-38f
|
||||
# define FLT_MAX 340282346638528859811704183484516925440.0f
|
||||
# define FLT_EPSILON 1.192092896e-07F
|
||||
#endif
|
||||
|
||||
#define ccl_device \
|
||||
static __device__ \
|
||||
__forceinline__ // Function calls are bad for OptiX performance, so inline everything
|
||||
#define ccl_device_extern extern "C" __device__
|
||||
#define ccl_device_inline ccl_device
|
||||
#define ccl_device_forceinline ccl_device
|
||||
#define ccl_device_inline_method __device__ __forceinline__
|
||||
#define ccl_device_template_spec template<> __device__ __forceinline__
|
||||
#define ccl_device_noinline static __device__ __noinline__
|
||||
#define ccl_device_noinline_cpu ccl_device
|
||||
#define ccl_global
|
||||
#define ccl_inline_constant static __constant__
|
||||
#define ccl_device_constant __constant__ __device__
|
||||
#define ccl_static_constexpr static constexpr
|
||||
#define ccl_constant const
|
||||
#define ccl_gpu_shared __shared__
|
||||
#define ccl_private
|
||||
#define ccl_ray_data ccl_private
|
||||
#define ccl_may_alias
|
||||
#define ccl_restrict __restrict__
|
||||
#define ccl_align(n) __align__(n)
|
||||
#define ccl_attr_maybe_unused [[maybe_unused]]
|
||||
|
||||
/* Zero initialize structs to help the compiler figure out scoping */
|
||||
#define ccl_optional_struct_init = {}
|
||||
|
||||
/* No assert supported for CUDA */
|
||||
|
||||
#define kernel_assert(cond)
|
||||
|
||||
/* GPU texture objects */
|
||||
|
||||
typedef unsigned long long CUtexObject;
|
||||
typedef CUtexObject ccl_gpu_image_object_2D;
|
||||
|
||||
template<typename T>
|
||||
ccl_device_forceinline T ccl_gpu_image_object_read_2D(const ccl_gpu_image_object_2D texobj,
|
||||
const float x,
|
||||
const float y)
|
||||
{
|
||||
return tex2D<T>(texobj, x, y);
|
||||
}
|
||||
|
||||
/* Half */
|
||||
|
||||
typedef unsigned short half;
|
||||
|
||||
ccl_device_forceinline half __float2half(const float f)
|
||||
{
|
||||
half val;
|
||||
asm("{ cvt.rn.f16.f32 %0, %1;}\n" : "=h"(val) : "f"(f));
|
||||
return val;
|
||||
}
|
||||
|
||||
ccl_device_forceinline float __half2float(const half h)
|
||||
{
|
||||
float val;
|
||||
asm("{ cvt.f32.f16 %0, %1;}\n" : "=f"(val) : "h"(h));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Types */
|
||||
|
||||
#include "util/half.h"
|
||||
#include "util/types.h"
|
||||
|
||||
#define OPTIX_DONT_INCLUDE_CUDA
|
||||
#include <optix.h>
|
||||
65
blender-5.2.0/intern/cycles/kernel/device/optix/globals.h
Normal file
65
blender-5.2.0/intern/cycles/kernel/device/optix/globals.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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"
|
||||
|
||||
#include "util/color.h"
|
||||
#include "util/types_image.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Not actually used, just a nullptr pointer that gets passed everywhere, which we
|
||||
* hope gets optimized out by the compiler. */
|
||||
struct KernelGlobalsGPU {
|
||||
int unused[1];
|
||||
};
|
||||
using KernelGlobals = const ccl_global KernelGlobalsGPU *ccl_restrict;
|
||||
|
||||
/* Launch parameters */
|
||||
struct KernelParamsOptiX {
|
||||
/* Kernel arguments */
|
||||
const int *path_index_array;
|
||||
float *render_buffer;
|
||||
uint *shader_eval_cache_miss;
|
||||
int shader_eval_offset;
|
||||
|
||||
/* Init kernel arguments */
|
||||
int num_tiles;
|
||||
int max_tile_work_size;
|
||||
|
||||
/* Global scene data and textures */
|
||||
KernelData data;
|
||||
#define KERNEL_DATA_ARRAY(type, name) const type *name;
|
||||
#define KERNEL_DATA_ARRAY_WRITABLE(type, name) type *name;
|
||||
#include "kernel/data_arrays.h"
|
||||
|
||||
/* Integrator state */
|
||||
IntegratorStateGPU integrator_state;
|
||||
|
||||
void *osl_colorsystem;
|
||||
};
|
||||
|
||||
#ifdef __NVCC__
|
||||
extern "C"
|
||||
# ifndef __CUDACC_RDC__
|
||||
static
|
||||
# endif
|
||||
__constant__ KernelParamsOptiX kernel_params;
|
||||
#endif
|
||||
|
||||
/* Abstraction macros */
|
||||
#define kernel_data kernel_params.data
|
||||
#define kernel_data_array(name) kernel_params.name
|
||||
#define kernel_data_fetch(name, index) kernel_params.name[(index)]
|
||||
#define kernel_data_write(name, index, value) kernel_params.name[(index)] = (value)
|
||||
#define kernel_integrator_state kernel_params.integrator_state
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
68
blender-5.2.0/intern/cycles/kernel/device/optix/kernel.cu
Normal file
68
blender-5.2.0/intern/cycles/kernel/device/optix/kernel.cu
Normal file
@@ -0,0 +1,68 @@
|
||||
/* SPDX-FileCopyrightText: 2019, NVIDIA Corporation
|
||||
* SPDX-FileCopyrightText: 2019-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
// clang-format off
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/device/gpu/image.h" /* Texture lookup uses normal CUDA intrinsics. */
|
||||
|
||||
#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_shadow.h"
|
||||
#include "kernel/integrator/intersect_subsurface.h"
|
||||
#include "kernel/integrator/intersect_volume_stack.h"
|
||||
#include "kernel/integrator/intersect_dedicated_light.h"
|
||||
// clang-format on
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_closest()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_closest(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_shadow()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_shadow(nullptr, path_index);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_subsurface()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_subsurface(nullptr, path_index);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_volume_stack()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_volume_stack(nullptr, path_index);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_dedicated_light()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_dedicated_light(nullptr, path_index);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/device/gpu/image.h" /* Texture lookup uses normal CUDA intrinsics. */
|
||||
|
||||
#include "kernel/integrator/intersect_mnee.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_mnee()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_mnee(nullptr, path_index);
|
||||
}
|
||||
108
blender-5.2.0/intern/cycles/kernel/device/optix/kernel_osl.cu
Normal file
108
blender-5.2.0/intern/cycles/kernel/device/optix/kernel_osl.cu
Normal file
@@ -0,0 +1,108 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#define WITH_OSL
|
||||
|
||||
/* Copy of the regular OptiX kernels with additional OSL support. */
|
||||
|
||||
#include "kernel/device/optix/kernel.cu"
|
||||
|
||||
#include "kernel/bake/bake.h"
|
||||
#include "kernel/integrator/shade_background.h"
|
||||
#include "kernel/integrator/shade_dedicated_light.h"
|
||||
#include "kernel/integrator/shade_light.h"
|
||||
#include "kernel/integrator/shade_shadow.h"
|
||||
#include "kernel/integrator/shade_surface.h"
|
||||
|
||||
#include "kernel/device/gpu/work_stealing.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_background()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_background(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_light_nee()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_light_nee(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_light_forward()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_light_forward(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_surface()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_surface(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_shadow()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_shadow(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_dedicated_light()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_dedicated_light(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_shader_eval_displace()
|
||||
{
|
||||
KernelShaderEvalInput *const input = (KernelShaderEvalInput *)kernel_params.path_index_array;
|
||||
float *const output = kernel_params.render_buffer;
|
||||
uint *const cache_miss = kernel_params.shader_eval_cache_miss;
|
||||
const int global_index = kernel_params.shader_eval_offset + optixGetLaunchIndex().x;
|
||||
kernel_displace_evaluate(nullptr, input, output, cache_miss, global_index);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_shader_eval_background()
|
||||
{
|
||||
KernelShaderEvalInput *const input = (KernelShaderEvalInput *)kernel_params.path_index_array;
|
||||
float *const output = kernel_params.render_buffer;
|
||||
uint *const cache_miss = kernel_params.shader_eval_cache_miss;
|
||||
const int global_index = kernel_params.shader_eval_offset + optixGetLaunchIndex().x;
|
||||
kernel_background_evaluate(nullptr, input, output, cache_miss, global_index);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_shader_eval_curve_shadow_transparency()
|
||||
{
|
||||
KernelShaderEvalInput *const input = (KernelShaderEvalInput *)kernel_params.path_index_array;
|
||||
float *const output = kernel_params.render_buffer;
|
||||
uint *const cache_miss = kernel_params.shader_eval_cache_miss;
|
||||
const int global_index = kernel_params.shader_eval_offset + optixGetLaunchIndex().x;
|
||||
kernel_curve_shadow_transparency_evaluate(nullptr, input, output, cache_miss, global_index);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_shader_eval_volume_density()
|
||||
{
|
||||
KernelShaderEvalInput *const input = (KernelShaderEvalInput *)kernel_params.path_index_array;
|
||||
float *const output = kernel_params.render_buffer;
|
||||
uint *const cache_miss = kernel_params.shader_eval_cache_miss;
|
||||
const int global_index = kernel_params.shader_eval_offset + optixGetLaunchIndex().x;
|
||||
kernel_volume_density_evaluate(nullptr, input, output, cache_miss, global_index);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2025 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#define WITH_OSL
|
||||
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/integrator/init_from_camera.h"
|
||||
|
||||
#include "kernel/device/gpu/work_stealing.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_init_from_camera()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
|
||||
const KernelWorkTile *tiles = (const KernelWorkTile *)kernel_params.path_index_array;
|
||||
|
||||
const int tile_index = global_index / kernel_params.max_tile_work_size;
|
||||
const int tile_work_index = global_index - tile_index * kernel_params.max_tile_work_size;
|
||||
|
||||
const KernelWorkTile *tile = &tiles[tile_index];
|
||||
|
||||
if (tile_work_index >= tile->work_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int path_index = tile->path_index_offset + tile_work_index;
|
||||
|
||||
uint x, y, sample;
|
||||
get_work_pixel(tile, tile_work_index, &x, &y, &sample);
|
||||
|
||||
integrator_init_from_camera(nullptr, path_index, tile, kernel_params.render_buffer, x, y, sample);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#define WITH_OSL
|
||||
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/bvh/bvh.h"
|
||||
#include "kernel/integrator/path_state.h"
|
||||
|
||||
#include "kernel/integrator/intersect_mnee.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_mnee()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_intersect_mnee(nullptr, path_index);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#define WITH_OSL
|
||||
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/integrator/shade_surface.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_surface_raytrace()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_surface_raytrace(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#define WITH_OSL
|
||||
|
||||
/* Volume shading raygens for OSL, loaded as a separate optix module so they
|
||||
* can be compiled in parallel with the base OSL module and skipped for
|
||||
* scenes without volumes. */
|
||||
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/film/data_passes.h"
|
||||
|
||||
#include "kernel/integrator/shade_volume.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_volume()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_volume(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_volume_ray_marching()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_volume_ray_marching(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2021-2026 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/* Copy of the regular kernels with additional shader ray-tracing kernel that takes
|
||||
* much longer to compiler. This is only loaded when needed by the scene. */
|
||||
|
||||
#include "kernel/device/optix/compat.h"
|
||||
#include "kernel/device/optix/globals.h"
|
||||
|
||||
#include "kernel/device/gpu/image.h"
|
||||
|
||||
#include "kernel/integrator/shade_surface.h"
|
||||
|
||||
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_surface_raytrace()
|
||||
{
|
||||
const int global_index = optixGetLaunchIndex().x;
|
||||
const int path_index = (kernel_params.path_index_array) ?
|
||||
kernel_params.path_index_array[global_index] :
|
||||
global_index;
|
||||
integrator_shade_surface_raytrace(nullptr, path_index, kernel_params.render_buffer);
|
||||
}
|
||||
Reference in New Issue
Block a user