Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/integrator/path_automata.h
- This file was added.
| /* SPDX-License-Identifier: Apache-2.0 | |||||
| * Copyright 2011-2022 Blender Foundation */ | |||||
| #pragma once | |||||
| CCL_NAMESPACE_BEGIN | |||||
| /* Find transition from one state to another given the symbol. The symbol can either be an object | |||||
| * or light tag, or a path event. */ | |||||
| ccl_device_inline int path_automata_get_transition(KernelGlobals kg, | |||||
| const int state, | |||||
| const int symbol) | |||||
| { | |||||
| const KernelLightPathState light_path_state = kernel_data_fetch(light_path_states, state); | |||||
| int begin = light_path_state.start_transition; | |||||
| int end = begin + light_path_state.num_transitions; | |||||
| /* Find potential transition using binary search. */ | |||||
| while (begin < end) { | |||||
| const int middle = begin + ((end - begin) / 2); | |||||
| const KernelLightPathTransition trans = kernel_data_fetch(light_path_transitions, middle); | |||||
| if (symbol < trans.symbol) { | |||||
| end = middle; | |||||
| } | |||||
| else if (trans.symbol < symbol) { | |||||
| begin = middle + 1; | |||||
| } | |||||
| else { | |||||
| /* We have a match. */ | |||||
| return trans.state; | |||||
| } | |||||
| } | |||||
| return light_path_state.wildcard_transition; | |||||
| } | |||||
| ccl_device_inline int path_automata_get_aovs_in_state(KernelGlobals kg, | |||||
| const int state, | |||||
| uint *count) | |||||
| { | |||||
| KernelLightPathState light_path_state = kernel_data_fetch(light_path_states, state); | |||||
| *count = light_path_state.num_aovs; | |||||
| return light_path_state.start_aovs; | |||||
| } | |||||
| ccl_device_inline int path_automata_try_move_transition(KernelGlobals kg, | |||||
| const int lpe_state, | |||||
| const int event) | |||||
| { | |||||
| if (lpe_state < 0) { | |||||
| return lpe_state; | |||||
| } | |||||
| return path_automata_get_transition(kg, lpe_state, event); | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_camera_event(KernelGlobals kg, IntegratorState state) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_CAMERA); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_WILDCARD); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_STOP); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline int path_automata_ligh_event_transition(KernelGlobals kg, | |||||
| int state, | |||||
| int path_event_type, | |||||
| int path_event_label) | |||||
| { | |||||
| state = path_automata_try_move_transition(kg, state, path_event_type); | |||||
| state = path_automata_try_move_transition(kg, state, PATH_EVENT_WILDCARD); | |||||
| if (path_event_label != PATH_EVENT_LABEL_NONE) { | |||||
| kernel_assert(path_event_label >= NUM_DEFAULT_PATH_EVENTS); | |||||
| state = path_automata_try_move_transition(kg, state, path_event_label); | |||||
| } | |||||
| state = path_automata_try_move_transition(kg, state, PATH_EVENT_STOP); | |||||
| return state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_light_event(KernelGlobals kg, | |||||
| IntegratorState state, | |||||
| int light_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_ligh_event_transition(kg, lpe_state, PATH_EVENT_LIGHT, light_label); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_light_event_shadow(KernelGlobals kg, | |||||
| IntegratorShadowState state, | |||||
| int light_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, shadow_path, lpe_state); | |||||
| lpe_state = path_automata_ligh_event_transition(kg, lpe_state, PATH_EVENT_LIGHT, light_label); | |||||
| INTEGRATOR_STATE_WRITE(state, shadow_path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_emissive_object_event(KernelGlobals kg, | |||||
| IntegratorState state, | |||||
| int object_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_ligh_event_transition( | |||||
| kg, lpe_state, PATH_EVENT_EMISSION_OBJECT, object_label); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_emissive_object_event_shadow(KernelGlobals kg, | |||||
| IntegratorShadowState state, | |||||
| int object_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, shadow_path, lpe_state); | |||||
| lpe_state = path_automata_ligh_event_transition( | |||||
| kg, lpe_state, PATH_EVENT_EMISSION_OBJECT, object_label); | |||||
| INTEGRATOR_STATE_WRITE(state, shadow_path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_background_event(KernelGlobals kg, IntegratorState state) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_BACKGROUND); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_WILDCARD); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_STOP); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_volume_scatter_event(KernelGlobals kg, | |||||
| IntegratorState state, | |||||
| int object_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_VOLUME_SCATTER); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_WILDCARD); | |||||
| if (object_label != PATH_EVENT_LABEL_NONE) { | |||||
| kernel_assert(object_label >= NUM_DEFAULT_PATH_EVENTS); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, object_label); | |||||
| } | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_STOP); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_albedo_event(KernelGlobals kg, | |||||
| ConstIntegratorState state, | |||||
| int object_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_ALBEDO); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_WILDCARD); | |||||
| if (object_label != PATH_EVENT_LABEL_NONE) { | |||||
| kernel_assert(object_label >= NUM_DEFAULT_PATH_EVENTS); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, object_label); | |||||
| } | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_STOP); | |||||
| // INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline int path_event_from_label(const int label) | |||||
| { | |||||
| if (label & LABEL_TRANSMIT) { | |||||
| return PATH_EVENT_TRANSMIT; | |||||
| } | |||||
| else if (label & LABEL_REFLECT) { | |||||
| return PATH_EVENT_REFLECT; | |||||
| } | |||||
| else if (label & LABEL_VOLUME_SCATTER) { | |||||
| return PATH_EVENT_VOLUME_SCATTER; | |||||
| } | |||||
| else { | |||||
| return PATH_EVENT_INVALID; | |||||
| } | |||||
| } | |||||
| ccl_device_inline int path_scattering_event_from_label(const int label) | |||||
| { | |||||
| if (label & LABEL_DIFFUSE) { | |||||
| return PATH_EVENT_SCATTERING_DIFFUSE; | |||||
| } | |||||
| else if (label & LABEL_GLOSSY) { | |||||
| return PATH_EVENT_SCATTERING_GLOSSY; | |||||
| } | |||||
| else if (label & LABEL_SINGULAR) { | |||||
| return PATH_EVENT_SCATTERING_SINGULAR; | |||||
| } | |||||
| else { | |||||
| /* May happen when called from the volume integration. */ | |||||
| return PATH_EVENT_INVALID; | |||||
| } | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_straight_event(KernelGlobals kg, | |||||
| IntegratorState state, | |||||
| const int label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| const int path_event = path_event_from_label(label); | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, path_event); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_SCATTERING_STRAIGHT); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_STOP); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| ccl_device_inline void path_automata_emit_bounce(KernelGlobals kg, | |||||
| IntegratorState state, | |||||
| int label, | |||||
| int object_label) | |||||
| { | |||||
| if (!kernel_data.has_lpes) { | |||||
| return; | |||||
| } | |||||
| int lpe_state = INTEGRATOR_STATE(state, path, lpe_state); | |||||
| if (lpe_state < 0) { | |||||
| /* This path might not be valid for any expressions. */ | |||||
| return; | |||||
| } | |||||
| /* Note: we may have invalid event and scattering types if the label does not have the right bits | |||||
| * set when emitting a bounce after hitting an emissive object. In this case, we still go through | |||||
| * the state machine which will set the path as invalid for any ray that does not end on an | |||||
| * emissive object directly, and AOVs will not be written to. */ | |||||
| const int event_type = path_event_from_label(label); | |||||
| const int scattering_type = path_scattering_event_from_label(label); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, event_type); | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, scattering_type); | |||||
| if (object_label != PATH_EVENT_LABEL_NONE) { | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, object_label); | |||||
| } | |||||
| lpe_state = path_automata_try_move_transition(kg, lpe_state, PATH_EVENT_STOP); | |||||
| INTEGRATOR_STATE_WRITE(state, path, lpe_state) = lpe_state; | |||||
| } | |||||
| CCL_NAMESPACE_END | |||||