Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/integrator/integrator_intersect_closest.h
| Show All 23 Lines | |||||
| #include "kernel/geom/geom.h" | #include "kernel/geom/geom.h" | ||||
| #include "kernel/bvh/bvh.h" | #include "kernel/bvh/bvh.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| template<uint32_t current_kernel> | template<uint32_t current_kernel> | ||||
| ccl_device_forceinline bool integrator_intersect_terminate(INTEGRATOR_STATE_ARGS, | ccl_device_forceinline bool integrator_intersect_terminate(KernelGlobals kg, | ||||
| IntegratorState state, | |||||
| const int shader_flags) | const int shader_flags) | ||||
| { | { | ||||
| /* Optional AO bounce termination. | /* Optional AO bounce termination. | ||||
| * We continue evaluating emissive/transparent surfaces and volumes, similar | * We continue evaluating emissive/transparent surfaces and volumes, similar | ||||
| * to direct lighting. Only if we know there are none can we terminate the | * to direct lighting. Only if we know there are none can we terminate the | ||||
| * path immediately. */ | * path immediately. */ | ||||
| if (path_state_ao_bounce(INTEGRATOR_STATE_PASS)) { | if (path_state_ao_bounce(kg, state)) { | ||||
| if (shader_flags & (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) { | if (shader_flags & (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) { | ||||
| INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; | INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_AFTER_TRANSPARENT; | ||||
| } | } | ||||
| else if (!integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_PASS)) { | else if (!integrator_state_volume_stack_is_empty(kg, state)) { | ||||
| INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_TERMINATE_AFTER_VOLUME; | INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_AFTER_VOLUME; | ||||
| } | } | ||||
| else { | else { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| /* Load random number state. */ | /* Load random number state. */ | ||||
| RNGState rng_state; | RNGState rng_state; | ||||
| path_state_rng_load(INTEGRATOR_STATE_PASS, &rng_state); | path_state_rng_load(state, &rng_state); | ||||
| /* We perform path termination in this kernel to avoid launching shade_surface | /* We perform path termination in this kernel to avoid launching shade_surface | ||||
| * and evaluating the shader when not needed. Only for emission and transparent | * and evaluating the shader when not needed. Only for emission and transparent | ||||
| * surfaces in front of emission do we need to evaluate the shader, since we | * surfaces in front of emission do we need to evaluate the shader, since we | ||||
| * perform MIS as part of indirect rays. */ | * perform MIS as part of indirect rays. */ | ||||
| const int path_flag = INTEGRATOR_STATE(path, flag); | const int path_flag = INTEGRATOR_STATE(state, path, flag); | ||||
| const float probability = path_state_continuation_probability(INTEGRATOR_STATE_PASS, path_flag); | const float probability = path_state_continuation_probability(kg, state, path_flag); | ||||
| if (probability != 1.0f) { | if (probability != 1.0f) { | ||||
| const float terminate = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE); | const float terminate = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE); | ||||
| if (probability == 0.0f || terminate >= probability) { | if (probability == 0.0f || terminate >= probability) { | ||||
| if (shader_flags & SD_HAS_EMISSION) { | if (shader_flags & SD_HAS_EMISSION) { | ||||
| /* Mark path to be terminated right after shader evaluation on the surface. */ | /* Mark path to be terminated right after shader evaluation on the surface. */ | ||||
| INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE; | INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_ON_NEXT_SURFACE; | ||||
| } | } | ||||
| else if (!integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_PASS)) { | else if (!integrator_state_volume_stack_is_empty(kg, state)) { | ||||
| /* TODO: only do this for emissive volumes. */ | /* TODO: only do this for emissive volumes. */ | ||||
| INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_TERMINATE_IN_NEXT_VOLUME; | INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_TERMINATE_IN_NEXT_VOLUME; | ||||
| } | } | ||||
| else { | else { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Note that current_kernel is a template value since making this a variable | /* Note that current_kernel is a template value since making this a variable | ||||
| * leads to poor performance with CUDA atomics. */ | * leads to poor performance with CUDA atomics. */ | ||||
| template<uint32_t current_kernel> | template<uint32_t current_kernel> | ||||
| ccl_device_forceinline void integrator_intersect_shader_next_kernel( | ccl_device_forceinline void integrator_intersect_shader_next_kernel( | ||||
| INTEGRATOR_STATE_ARGS, | KernelGlobals kg, | ||||
| IntegratorState state, | |||||
| ccl_private const Intersection *ccl_restrict isect, | ccl_private const Intersection *ccl_restrict isect, | ||||
| const int shader, | const int shader, | ||||
| const int shader_flags) | const int shader_flags) | ||||
| { | { | ||||
| /* Note on scheduling. | /* Note on scheduling. | ||||
| * | * | ||||
| * When there is no shadow catcher split the scheduling is simple: schedule surface shading with | * When there is no shadow catcher split the scheduling is simple: schedule surface shading with | ||||
| * or without raytrace support, depending on the shader used. | * or without raytrace support, depending on the shader used. | ||||
| Show All 20 Lines | INTEGRATOR_PATH_NEXT_SORTED( | ||||
| current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader); | current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader); | ||||
| } | } | ||||
| else { | else { | ||||
| INTEGRATOR_PATH_NEXT_SORTED(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader); | INTEGRATOR_PATH_NEXT_SORTED(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader); | ||||
| } | } | ||||
| #ifdef __SHADOW_CATCHER__ | #ifdef __SHADOW_CATCHER__ | ||||
| const int object_flags = intersection_get_object_flags(kg, isect); | const int object_flags = intersection_get_object_flags(kg, isect); | ||||
| if (kernel_shadow_catcher_split(INTEGRATOR_STATE_PASS, object_flags)) { | if (kernel_shadow_catcher_split(kg, state, object_flags)) { | ||||
| if (kernel_data.film.pass_background != PASS_UNUSED && !kernel_data.background.transparent) { | if (kernel_data.film.pass_background != PASS_UNUSED && !kernel_data.background.transparent) { | ||||
| INTEGRATOR_STATE_WRITE(path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND; | INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND; | ||||
| INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND); | INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND); | ||||
| } | } | ||||
| else if (use_raytrace_kernel) { | else if (use_raytrace_kernel) { | ||||
| INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader); | INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader); | ||||
| } | } | ||||
| else { | else { | ||||
| INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader); | INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader); | ||||
| } | } | ||||
| /* If the split happened after bounce through a transparent object it's possible to have shadow | /* If the split happened after bounce through a transparent object it's possible to have shadow | ||||
| * patch. Make sure it is properly re-scheduled on the split path. */ | * patch. Make sure it is properly re-scheduled on the split path. */ | ||||
| const int shadow_kernel = INTEGRATOR_STATE(shadow_path, queued_kernel); | const int shadow_kernel = INTEGRATOR_STATE(state, shadow_path, queued_kernel); | ||||
| if (shadow_kernel != 0) { | if (shadow_kernel != 0) { | ||||
| INTEGRATOR_SHADOW_PATH_INIT(shadow_kernel); | INTEGRATOR_SHADOW_PATH_INIT(shadow_kernel); | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| } | } | ||||
| ccl_device void integrator_intersect_closest(INTEGRATOR_STATE_ARGS) | ccl_device void integrator_intersect_closest(KernelGlobals kg, IntegratorState state) | ||||
| { | { | ||||
| PROFILING_INIT(kg, PROFILING_INTERSECT_CLOSEST); | PROFILING_INIT(kg, PROFILING_INTERSECT_CLOSEST); | ||||
| /* Read ray from integrator state into local memory. */ | /* Read ray from integrator state into local memory. */ | ||||
| Ray ray ccl_optional_struct_init; | Ray ray ccl_optional_struct_init; | ||||
| integrator_state_read_ray(INTEGRATOR_STATE_PASS, &ray); | integrator_state_read_ray(kg, state, &ray); | ||||
| kernel_assert(ray.t != 0.0f); | kernel_assert(ray.t != 0.0f); | ||||
| const uint visibility = path_state_ray_visibility(INTEGRATOR_STATE_PASS); | const uint visibility = path_state_ray_visibility(state); | ||||
| const int last_isect_prim = INTEGRATOR_STATE(isect, prim); | const int last_isect_prim = INTEGRATOR_STATE(state, isect, prim); | ||||
| const int last_isect_object = INTEGRATOR_STATE(isect, object); | const int last_isect_object = INTEGRATOR_STATE(state, isect, object); | ||||
| /* Trick to use short AO rays to approximate indirect light at the end of the path. */ | /* Trick to use short AO rays to approximate indirect light at the end of the path. */ | ||||
| if (path_state_ao_bounce(INTEGRATOR_STATE_PASS)) { | if (path_state_ao_bounce(kg, state)) { | ||||
| ray.t = kernel_data.integrator.ao_bounces_distance; | ray.t = kernel_data.integrator.ao_bounces_distance; | ||||
| const float object_ao_distance = kernel_tex_fetch(__objects, last_isect_object).ao_distance; | const float object_ao_distance = kernel_tex_fetch(__objects, last_isect_object).ao_distance; | ||||
| if (object_ao_distance != 0.0f) { | if (object_ao_distance != 0.0f) { | ||||
| ray.t = object_ao_distance; | ray.t = object_ao_distance; | ||||
| } | } | ||||
| } | } | ||||
| /* Scene Intersection. */ | /* Scene Intersection. */ | ||||
| Intersection isect ccl_optional_struct_init; | Intersection isect ccl_optional_struct_init; | ||||
| bool hit = scene_intersect(kg, &ray, visibility, &isect); | bool hit = scene_intersect(kg, &ray, visibility, &isect); | ||||
| /* TODO: remove this and do it in the various intersection functions instead. */ | /* TODO: remove this and do it in the various intersection functions instead. */ | ||||
| if (!hit) { | if (!hit) { | ||||
| isect.prim = PRIM_NONE; | isect.prim = PRIM_NONE; | ||||
| } | } | ||||
| /* Light intersection for MIS. */ | /* Light intersection for MIS. */ | ||||
| if (kernel_data.integrator.use_lamp_mis) { | if (kernel_data.integrator.use_lamp_mis) { | ||||
| /* NOTE: if we make lights visible to camera rays, we'll need to initialize | /* NOTE: if we make lights visible to camera rays, we'll need to initialize | ||||
| * these in the path_state_init. */ | * these in the path_state_init. */ | ||||
| const int last_type = INTEGRATOR_STATE(isect, type); | const int last_type = INTEGRATOR_STATE(state, isect, type); | ||||
| const int path_flag = INTEGRATOR_STATE(path, flag); | const int path_flag = INTEGRATOR_STATE(state, path, flag); | ||||
| hit = lights_intersect( | hit = lights_intersect( | ||||
| kg, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) || | kg, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) || | ||||
| hit; | hit; | ||||
| } | } | ||||
| /* Write intersection result into global integrator state memory. */ | /* Write intersection result into global integrator state memory. */ | ||||
| integrator_state_write_isect(INTEGRATOR_STATE_PASS, &isect); | integrator_state_write_isect(kg, state, &isect); | ||||
| #ifdef __VOLUME__ | #ifdef __VOLUME__ | ||||
| if (!integrator_state_volume_stack_is_empty(INTEGRATOR_STATE_PASS)) { | if (!integrator_state_volume_stack_is_empty(kg, state)) { | ||||
| const bool hit_surface = hit && !(isect.type & PRIMITIVE_LAMP); | const bool hit_surface = hit && !(isect.type & PRIMITIVE_LAMP); | ||||
| const int shader = (hit_surface) ? intersection_get_shader(kg, &isect) : SHADER_NONE; | const int shader = (hit_surface) ? intersection_get_shader(kg, &isect) : SHADER_NONE; | ||||
| const int flags = (hit_surface) ? kernel_tex_fetch(__shaders, shader).flags : 0; | const int flags = (hit_surface) ? kernel_tex_fetch(__shaders, shader).flags : 0; | ||||
| if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>( | if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>( | ||||
| INTEGRATOR_STATE_PASS, flags)) { | kg, state, flags)) { | ||||
| /* Continue with volume kernel if we are inside a volume, regardless | /* Continue with volume kernel if we are inside a volume, regardless | ||||
| * if we hit anything. */ | * if we hit anything. */ | ||||
| INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST, | INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST, | ||||
| DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME); | DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME); | ||||
| } | } | ||||
| else { | else { | ||||
| INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST); | INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST); | ||||
| } | } | ||||
| Show All 9 Lines | if (isect.type & PRIMITIVE_LAMP) { | ||||
| return; | return; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Hit a surface, continue with surface kernel unless terminated. */ | /* Hit a surface, continue with surface kernel unless terminated. */ | ||||
| const int shader = intersection_get_shader(kg, &isect); | const int shader = intersection_get_shader(kg, &isect); | ||||
| const int flags = kernel_tex_fetch(__shaders, shader).flags; | const int flags = kernel_tex_fetch(__shaders, shader).flags; | ||||
| if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>( | if (!integrator_intersect_terminate<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>( | ||||
| INTEGRATOR_STATE_PASS, flags)) { | kg, state, flags)) { | ||||
| integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>( | integrator_intersect_shader_next_kernel<DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST>( | ||||
| INTEGRATOR_STATE_PASS, &isect, shader, flags); | kg, state, &isect, shader, flags); | ||||
| return; | return; | ||||
| } | } | ||||
| else { | else { | ||||
| INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST); | INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST); | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 9 Lines | |||||