Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/device/optix/device_impl.cpp
| Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | switch (level) { | ||||
| LOG_IF(WARNING, VLOG_IS_ON(1)) << message; | LOG_IF(WARNING, VLOG_IS_ON(1)) << message; | ||||
| break; | break; | ||||
| case 4: | case 4: | ||||
| LOG_IF(INFO, VLOG_IS_ON(1)) << message; | LOG_IF(INFO, VLOG_IS_ON(1)) << message; | ||||
| break; | break; | ||||
| } | } | ||||
| }; | }; | ||||
| # endif | # endif | ||||
| # if OPTIX_ABI_VERSION >= 41 | |||||
| if (DebugFlags().optix.use_debug) { | if (DebugFlags().optix.use_debug) { | ||||
| options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; | options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL; | ||||
| } | } | ||||
| # endif | |||||
| optix_assert(optixDeviceContextCreate(cuContext, &options, &context)); | optix_assert(optixDeviceContextCreate(cuContext, &options, &context)); | ||||
| # ifdef WITH_CYCLES_LOGGING | # ifdef WITH_CYCLES_LOGGING | ||||
| optix_assert(optixDeviceContextSetLogCallback( | optix_assert(optixDeviceContextSetLogCallback( | ||||
| context, options.logCallbackFunction, options.logCallbackData, options.logCallbackLevel)); | context, options.logCallbackFunction, options.logCallbackData, options.logCallbackLevel)); | ||||
| # endif | # endif | ||||
| /* Fix weird compiler bug that assigns wrong size. */ | /* Fix weird compiler bug that assigns wrong size. */ | ||||
| launch_params.data_elements = sizeof(KernelParamsOptiX); | launch_params.data_elements = sizeof(KernelParamsOptiX); | ||||
| ▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | if (DebugFlags().optix.use_debug) { | ||||
| module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; | module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_0; | ||||
| module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; | module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; | ||||
| } | } | ||||
| else { | else { | ||||
| module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_3; | module_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_LEVEL_3; | ||||
| module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; | module_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; | ||||
| } | } | ||||
| # if OPTIX_ABI_VERSION >= 41 | |||||
| module_options.boundValues = nullptr; | module_options.boundValues = nullptr; | ||||
| module_options.numBoundValues = 0; | module_options.numBoundValues = 0; | ||||
| # endif | |||||
| OptixPipelineCompileOptions pipeline_options = {}; | OptixPipelineCompileOptions pipeline_options = {}; | ||||
| /* Default to no motion blur and two-level graph, since it is the fastest option. */ | /* Default to no motion blur and two-level graph, since it is the fastest option. */ | ||||
| pipeline_options.usesMotionBlur = false; | pipeline_options.usesMotionBlur = false; | ||||
| pipeline_options.traversableGraphFlags = | pipeline_options.traversableGraphFlags = | ||||
| OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; | OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; | ||||
| pipeline_options.numPayloadValues = 6; | pipeline_options.numPayloadValues = 6; | ||||
| pipeline_options.numAttributeValues = 2; /* u, v */ | pipeline_options.numAttributeValues = 2; /* u, v */ | ||||
| pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; | pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; | ||||
| pipeline_options.pipelineLaunchParamsVariableName = "__params"; /* See globals.h */ | pipeline_options.pipelineLaunchParamsVariableName = "__params"; /* See globals.h */ | ||||
| # if OPTIX_ABI_VERSION >= 36 | |||||
| pipeline_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; | pipeline_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; | ||||
| if (requested_features.use_hair) { | if (requested_features.use_hair) { | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (requested_features.use_hair_thick) { | if (requested_features.use_hair_thick) { | ||||
| pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE; | pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_ROUND_CUBIC_BSPLINE; | ||||
| } | } | ||||
| else | else | ||||
| # endif | |||||
| pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM; | pipeline_options.usesPrimitiveTypeFlags |= OPTIX_PRIMITIVE_TYPE_FLAGS_CUSTOM; | ||||
| } | } | ||||
| # endif | |||||
| /* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds | /* Keep track of whether motion blur is enabled, so to enable/disable motion in BVH builds | ||||
| * This is necessary since objects may be reported to have motion if the Vector pass is | * This is necessary since objects may be reported to have motion if the Vector pass is | ||||
| * active, but may still need to be rendered without motion blur if that isn't active as well. */ | * active, but may still need to be rendered without motion blur if that isn't active as well. */ | ||||
| motion_blur = requested_features.use_object_motion; | motion_blur = requested_features.use_object_motion; | ||||
| if (motion_blur) { | if (motion_blur) { | ||||
| pipeline_options.usesMotionBlur = true; | pipeline_options.usesMotionBlur = true; | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | bool OptiXDevice::load_kernels(const DeviceRequestedFeatures &requested_features) | ||||
| group_descs[PG_HITD].hitgroup.entryFunctionNameCH = "__closesthit__kernel_optix_hit"; | group_descs[PG_HITD].hitgroup.entryFunctionNameCH = "__closesthit__kernel_optix_hit"; | ||||
| group_descs[PG_HITD].hitgroup.moduleAH = optix_module; | group_descs[PG_HITD].hitgroup.moduleAH = optix_module; | ||||
| group_descs[PG_HITD].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_visibility_test"; | group_descs[PG_HITD].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_visibility_test"; | ||||
| group_descs[PG_HITS].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; | group_descs[PG_HITS].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; | ||||
| group_descs[PG_HITS].hitgroup.moduleAH = optix_module; | group_descs[PG_HITS].hitgroup.moduleAH = optix_module; | ||||
| group_descs[PG_HITS].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_shadow_all_hit"; | group_descs[PG_HITS].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_shadow_all_hit"; | ||||
| if (requested_features.use_hair) { | if (requested_features.use_hair) { | ||||
| group_descs[PG_HITD].hitgroup.moduleIS = optix_module; | |||||
| group_descs[PG_HITS].hitgroup.moduleIS = optix_module; | |||||
| /* Add curve intersection programs. */ | |||||
| if (requested_features.use_hair_thick) { | |||||
| /* Slower programs for thick hair since that also slows down ribbons. | |||||
| * Ideally this should not be needed. */ | |||||
| group_descs[PG_HITD].hitgroup.entryFunctionNameIS = "__intersection__curve_all"; | |||||
| group_descs[PG_HITS].hitgroup.entryFunctionNameIS = "__intersection__curve_all"; | |||||
| } | |||||
| else { | |||||
| group_descs[PG_HITD].hitgroup.entryFunctionNameIS = "__intersection__curve_ribbon"; | |||||
| group_descs[PG_HITS].hitgroup.entryFunctionNameIS = "__intersection__curve_ribbon"; | |||||
| } | |||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (requested_features.use_hair_thick) { | if (requested_features.use_hair_thick) { | ||||
| /* Built-in thick curve intersection. */ | |||||
| OptixBuiltinISOptions builtin_options = {}; | OptixBuiltinISOptions builtin_options = {}; | ||||
| builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; | builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; | ||||
| builtin_options.usesMotionBlur = false; | builtin_options.usesMotionBlur = false; | ||||
| optix_assert(optixBuiltinISModuleGet( | optix_assert(optixBuiltinISModuleGet( | ||||
| context, &module_options, &pipeline_options, &builtin_options, &builtin_modules[0])); | context, &module_options, &pipeline_options, &builtin_options, &builtin_modules[0])); | ||||
| group_descs[PG_HITD].hitgroup.moduleIS = builtin_modules[0]; | group_descs[PG_HITD].hitgroup.moduleIS = builtin_modules[0]; | ||||
| group_descs[PG_HITD].hitgroup.entryFunctionNameIS = nullptr; | group_descs[PG_HITD].hitgroup.entryFunctionNameIS = nullptr; | ||||
| group_descs[PG_HITS].hitgroup.moduleIS = builtin_modules[0]; | group_descs[PG_HITS].hitgroup.moduleIS = builtin_modules[0]; | ||||
| group_descs[PG_HITS].hitgroup.entryFunctionNameIS = nullptr; | group_descs[PG_HITS].hitgroup.entryFunctionNameIS = nullptr; | ||||
| if (motion_blur) { | if (motion_blur) { | ||||
| builtin_options.usesMotionBlur = true; | builtin_options.usesMotionBlur = true; | ||||
| optix_assert(optixBuiltinISModuleGet( | optix_assert(optixBuiltinISModuleGet( | ||||
| context, &module_options, &pipeline_options, &builtin_options, &builtin_modules[1])); | context, &module_options, &pipeline_options, &builtin_options, &builtin_modules[1])); | ||||
| group_descs[PG_HITD_MOTION] = group_descs[PG_HITD]; | group_descs[PG_HITD_MOTION] = group_descs[PG_HITD]; | ||||
| group_descs[PG_HITD_MOTION].hitgroup.moduleIS = builtin_modules[1]; | group_descs[PG_HITD_MOTION].hitgroup.moduleIS = builtin_modules[1]; | ||||
| group_descs[PG_HITS_MOTION] = group_descs[PG_HITS]; | group_descs[PG_HITS_MOTION] = group_descs[PG_HITS]; | ||||
| group_descs[PG_HITS_MOTION].hitgroup.moduleIS = builtin_modules[1]; | group_descs[PG_HITS_MOTION].hitgroup.moduleIS = builtin_modules[1]; | ||||
| } | } | ||||
| } | } | ||||
| # endif | else { | ||||
| /* Custom ribbon intersection. */ | |||||
| group_descs[PG_HITD].hitgroup.moduleIS = optix_module; | |||||
| group_descs[PG_HITS].hitgroup.moduleIS = optix_module; | |||||
| group_descs[PG_HITD].hitgroup.entryFunctionNameIS = "__intersection__curve_ribbon"; | |||||
| group_descs[PG_HITS].hitgroup.entryFunctionNameIS = "__intersection__curve_ribbon"; | |||||
| } | |||||
| } | } | ||||
| if (requested_features.use_subsurface || | if (requested_features.use_subsurface || | ||||
| (requested_features.nodes_features & NODE_FEATURE_RAYTRACE)) { | (requested_features.nodes_features & NODE_FEATURE_RAYTRACE)) { | ||||
| /* Add hit group for local intersections. */ | /* Add hit group for local intersections. */ | ||||
| group_descs[PG_HITL].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; | group_descs[PG_HITL].kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; | ||||
| group_descs[PG_HITL].hitgroup.moduleAH = optix_module; | group_descs[PG_HITL].hitgroup.moduleAH = optix_module; | ||||
| group_descs[PG_HITL].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_local_hit"; | group_descs[PG_HITL].hitgroup.entryFunctionNameAH = "__anyhit__kernel_optix_local_hit"; | ||||
| Show All 29 Lines | bool OptiXDevice::load_kernels(const DeviceRequestedFeatures &requested_features) | ||||
| sbt_data.copy_to_device(); /* Upload SBT to device. */ | sbt_data.copy_to_device(); /* Upload SBT to device. */ | ||||
| /* Calculate maximum trace continuation stack size. */ | /* Calculate maximum trace continuation stack size. */ | ||||
| unsigned int trace_css = stack_size[PG_HITD].cssCH; | unsigned int trace_css = stack_size[PG_HITD].cssCH; | ||||
| /* This is based on the maximum of closest-hit and any-hit/intersection programs. */ | /* This is based on the maximum of closest-hit and any-hit/intersection programs. */ | ||||
| trace_css = std::max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH); | trace_css = std::max(trace_css, stack_size[PG_HITD].cssIS + stack_size[PG_HITD].cssAH); | ||||
| trace_css = std::max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH); | trace_css = std::max(trace_css, stack_size[PG_HITS].cssIS + stack_size[PG_HITS].cssAH); | ||||
| trace_css = std::max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH); | trace_css = std::max(trace_css, stack_size[PG_HITL].cssIS + stack_size[PG_HITL].cssAH); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| trace_css = std::max(trace_css, | trace_css = std::max(trace_css, | ||||
| stack_size[PG_HITD_MOTION].cssIS + stack_size[PG_HITD_MOTION].cssAH); | stack_size[PG_HITD_MOTION].cssIS + stack_size[PG_HITD_MOTION].cssAH); | ||||
| trace_css = std::max(trace_css, | trace_css = std::max(trace_css, | ||||
| stack_size[PG_HITS_MOTION].cssIS + stack_size[PG_HITS_MOTION].cssAH); | stack_size[PG_HITS_MOTION].cssIS + stack_size[PG_HITS_MOTION].cssAH); | ||||
| # endif | |||||
| OptixPipelineLinkOptions link_options = {}; | OptixPipelineLinkOptions link_options = {}; | ||||
| link_options.maxTraceDepth = 1; | link_options.maxTraceDepth = 1; | ||||
| if (DebugFlags().optix.use_debug) { | if (DebugFlags().optix.use_debug) { | ||||
| link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; | link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; | ||||
| } | } | ||||
| else { | else { | ||||
| link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; | link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; | ||||
| } | } | ||||
| # if OPTIX_ABI_VERSION < 24 | |||||
| link_options.overrideUsesMotionBlur = motion_blur; | |||||
| # endif | |||||
| if (requested_features.nodes_features & NODE_FEATURE_RAYTRACE) { | if (requested_features.nodes_features & NODE_FEATURE_RAYTRACE) { | ||||
| /* Create shader raytracing pipeline. */ | /* Create shader raytracing pipeline. */ | ||||
| vector<OptixProgramGroup> pipeline_groups; | vector<OptixProgramGroup> pipeline_groups; | ||||
| pipeline_groups.reserve(NUM_PROGRAM_GROUPS); | pipeline_groups.reserve(NUM_PROGRAM_GROUPS); | ||||
| pipeline_groups.push_back(groups[PG_RGEN_SHADE_SURFACE_RAYTRACE]); | pipeline_groups.push_back(groups[PG_RGEN_SHADE_SURFACE_RAYTRACE]); | ||||
| pipeline_groups.push_back(groups[PG_MISS]); | pipeline_groups.push_back(groups[PG_MISS]); | ||||
| pipeline_groups.push_back(groups[PG_HITD]); | pipeline_groups.push_back(groups[PG_HITD]); | ||||
| pipeline_groups.push_back(groups[PG_HITS]); | pipeline_groups.push_back(groups[PG_HITS]); | ||||
| pipeline_groups.push_back(groups[PG_HITL]); | pipeline_groups.push_back(groups[PG_HITL]); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (motion_blur) { | if (motion_blur) { | ||||
| pipeline_groups.push_back(groups[PG_HITD_MOTION]); | pipeline_groups.push_back(groups[PG_HITD_MOTION]); | ||||
| pipeline_groups.push_back(groups[PG_HITS_MOTION]); | pipeline_groups.push_back(groups[PG_HITS_MOTION]); | ||||
| } | } | ||||
| # endif | |||||
| pipeline_groups.push_back(groups[PG_CALL_SVM_AO]); | pipeline_groups.push_back(groups[PG_CALL_SVM_AO]); | ||||
| pipeline_groups.push_back(groups[PG_CALL_SVM_BEVEL]); | pipeline_groups.push_back(groups[PG_CALL_SVM_BEVEL]); | ||||
| optix_assert(optixPipelineCreate(context, | optix_assert(optixPipelineCreate(context, | ||||
| &pipeline_options, | &pipeline_options, | ||||
| &link_options, | &link_options, | ||||
| pipeline_groups.data(), | pipeline_groups.data(), | ||||
| pipeline_groups.size(), | pipeline_groups.size(), | ||||
| Show All 17 Lines | if (requested_features.nodes_features & NODE_FEATURE_RAYTRACE) { | ||||
| pipeline_groups.reserve(NUM_PROGRAM_GROUPS); | pipeline_groups.reserve(NUM_PROGRAM_GROUPS); | ||||
| pipeline_groups.push_back(groups[PG_RGEN_INTERSECT_CLOSEST]); | pipeline_groups.push_back(groups[PG_RGEN_INTERSECT_CLOSEST]); | ||||
| pipeline_groups.push_back(groups[PG_RGEN_INTERSECT_SHADOW]); | pipeline_groups.push_back(groups[PG_RGEN_INTERSECT_SHADOW]); | ||||
| pipeline_groups.push_back(groups[PG_RGEN_INTERSECT_SUBSURFACE]); | pipeline_groups.push_back(groups[PG_RGEN_INTERSECT_SUBSURFACE]); | ||||
| pipeline_groups.push_back(groups[PG_MISS]); | pipeline_groups.push_back(groups[PG_MISS]); | ||||
| pipeline_groups.push_back(groups[PG_HITD]); | pipeline_groups.push_back(groups[PG_HITD]); | ||||
| pipeline_groups.push_back(groups[PG_HITS]); | pipeline_groups.push_back(groups[PG_HITS]); | ||||
| pipeline_groups.push_back(groups[PG_HITL]); | pipeline_groups.push_back(groups[PG_HITL]); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (motion_blur) { | if (motion_blur) { | ||||
| pipeline_groups.push_back(groups[PG_HITD_MOTION]); | pipeline_groups.push_back(groups[PG_HITD_MOTION]); | ||||
| pipeline_groups.push_back(groups[PG_HITS_MOTION]); | pipeline_groups.push_back(groups[PG_HITS_MOTION]); | ||||
| } | } | ||||
| # endif | |||||
| optix_assert(optixPipelineCreate(context, | optix_assert(optixPipelineCreate(context, | ||||
| &pipeline_options, | &pipeline_options, | ||||
| &link_options, | &link_options, | ||||
| pipeline_groups.data(), | pipeline_groups.data(), | ||||
| pipeline_groups.size(), | pipeline_groups.size(), | ||||
| nullptr, | nullptr, | ||||
| 0, | 0, | ||||
| ▲ Show 20 Lines • Show All 251 Lines • ▼ Show 20 Lines | bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context) | ||||
| /* Destroy existing handle before creating new one. */ | /* Destroy existing handle before creating new one. */ | ||||
| if (denoiser_.optix_denoiser) { | if (denoiser_.optix_denoiser) { | ||||
| optixDenoiserDestroy(denoiser_.optix_denoiser); | optixDenoiserDestroy(denoiser_.optix_denoiser); | ||||
| } | } | ||||
| /* Create OptiX denoiser handle on demand when it is first used. */ | /* Create OptiX denoiser handle on demand when it is first used. */ | ||||
| OptixDenoiserOptions denoiser_options = {}; | OptixDenoiserOptions denoiser_options = {}; | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| denoiser_options.guideAlbedo = context.use_pass_albedo; | denoiser_options.guideAlbedo = context.use_pass_albedo; | ||||
| denoiser_options.guideNormal = context.use_pass_normal; | denoiser_options.guideNormal = context.use_pass_normal; | ||||
| const OptixResult result = optixDenoiserCreate( | const OptixResult result = optixDenoiserCreate( | ||||
| this->context, OPTIX_DENOISER_MODEL_KIND_HDR, &denoiser_options, &denoiser_.optix_denoiser); | this->context, OPTIX_DENOISER_MODEL_KIND_HDR, &denoiser_options, &denoiser_.optix_denoiser); | ||||
| # else | |||||
| denoiser_options.inputKind = static_cast<OptixDenoiserInputKind>(OPTIX_DENOISER_INPUT_RGB + | |||||
| (context.num_input_passes - 1)); | |||||
| # if OPTIX_ABI_VERSION < 28 | |||||
| denoiser_options.pixelFormat = OPTIX_PIXEL_FORMAT_FLOAT3; | |||||
| # endif | |||||
| const OptixResult result = optixDenoiserCreate( | |||||
| this->context, &denoiser_options, &denoiser_.optix_denoiser); | |||||
| # endif | |||||
| if (result != OPTIX_SUCCESS) { | if (result != OPTIX_SUCCESS) { | ||||
| set_error("Failed to create OptiX denoiser"); | set_error("Failed to create OptiX denoiser"); | ||||
| return false; | return false; | ||||
| } | } | ||||
| # if OPTIX_ABI_VERSION < 47 | |||||
| optix_assert( | |||||
| optixDenoiserSetModel(denoiser_.optix_denoiser, OPTIX_DENOISER_MODEL_KIND_HDR, nullptr, 0)); | |||||
| # endif | |||||
| /* OptiX denoiser handle was created with the requested number of input passes. */ | /* OptiX denoiser handle was created with the requested number of input passes. */ | ||||
| denoiser_.use_pass_albedo = context.use_pass_albedo; | denoiser_.use_pass_albedo = context.use_pass_albedo; | ||||
| denoiser_.use_pass_normal = context.use_pass_normal; | denoiser_.use_pass_normal = context.use_pass_normal; | ||||
| /* OptiX denoiser has been created, but it needs configuration. */ | /* OptiX denoiser has been created, but it needs configuration. */ | ||||
| denoiser_.is_configured = false; | denoiser_.is_configured = false; | ||||
| return true; | return true; | ||||
| } | } | ||||
| bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context) | bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context) | ||||
| { | { | ||||
| if (denoiser_.is_configured && (denoiser_.configured_size.x == context.buffer_params.width && | if (denoiser_.is_configured && (denoiser_.configured_size.x == context.buffer_params.width && | ||||
| denoiser_.configured_size.y == context.buffer_params.height)) { | denoiser_.configured_size.y == context.buffer_params.height)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| const BufferParams &buffer_params = context.buffer_params; | const BufferParams &buffer_params = context.buffer_params; | ||||
| OptixDenoiserSizes sizes = {}; | OptixDenoiserSizes sizes = {}; | ||||
| optix_assert(optixDenoiserComputeMemoryResources( | optix_assert(optixDenoiserComputeMemoryResources( | ||||
| denoiser_.optix_denoiser, buffer_params.width, buffer_params.height, &sizes)); | denoiser_.optix_denoiser, buffer_params.width, buffer_params.height, &sizes)); | ||||
| # if OPTIX_ABI_VERSION < 28 | |||||
| denoiser_.scratch_size = sizes.recommendedScratchSizeInBytes; | |||||
| # else | |||||
| denoiser_.scratch_size = sizes.withOverlapScratchSizeInBytes; | denoiser_.scratch_size = sizes.withOverlapScratchSizeInBytes; | ||||
| # endif | |||||
| denoiser_.scratch_offset = sizes.stateSizeInBytes; | denoiser_.scratch_offset = sizes.stateSizeInBytes; | ||||
| /* Allocate denoiser state if tile size has changed since last setup. */ | /* Allocate denoiser state if tile size has changed since last setup. */ | ||||
| denoiser_.state.alloc_to_device(denoiser_.scratch_offset + denoiser_.scratch_size); | denoiser_.state.alloc_to_device(denoiser_.scratch_offset + denoiser_.scratch_size); | ||||
| /* Initialize denoiser state for the current tile size. */ | /* Initialize denoiser state for the current tile size. */ | ||||
| const OptixResult result = optixDenoiserSetup(denoiser_.optix_denoiser, | const OptixResult result = optixDenoiserSetup(denoiser_.optix_denoiser, | ||||
| denoiser_.queue.stream(), | denoiser_.queue.stream(), | ||||
| ▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | /* Optional albedo and color passes. */ | ||||
| } | } | ||||
| } | } | ||||
| /* Denoise in-place of the noisy input in the render buffers. */ | /* Denoise in-place of the noisy input in the render buffers. */ | ||||
| output_layers[0] = input_layers[0]; | output_layers[0] = input_layers[0]; | ||||
| /* Finally run denonising. */ | /* Finally run denonising. */ | ||||
| OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */ | OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */ | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| OptixDenoiserLayer image_layers = {}; | OptixDenoiserLayer image_layers = {}; | ||||
| image_layers.input = input_layers[0]; | image_layers.input = input_layers[0]; | ||||
| image_layers.output = output_layers[0]; | image_layers.output = output_layers[0]; | ||||
| OptixDenoiserGuideLayer guide_layers = {}; | OptixDenoiserGuideLayer guide_layers = {}; | ||||
| guide_layers.albedo = input_layers[1]; | guide_layers.albedo = input_layers[1]; | ||||
| guide_layers.normal = input_layers[2]; | guide_layers.normal = input_layers[2]; | ||||
| optix_assert(optixDenoiserInvoke(denoiser_.optix_denoiser, | optix_assert(optixDenoiserInvoke(denoiser_.optix_denoiser, | ||||
| denoiser_.queue.stream(), | denoiser_.queue.stream(), | ||||
| ¶ms, | ¶ms, | ||||
| denoiser_.state.device_pointer, | denoiser_.state.device_pointer, | ||||
| denoiser_.scratch_offset, | denoiser_.scratch_offset, | ||||
| &guide_layers, | &guide_layers, | ||||
| &image_layers, | &image_layers, | ||||
| 1, | 1, | ||||
| 0, | 0, | ||||
| 0, | 0, | ||||
| denoiser_.state.device_pointer + denoiser_.scratch_offset, | denoiser_.state.device_pointer + denoiser_.scratch_offset, | ||||
| denoiser_.scratch_size)); | denoiser_.scratch_size)); | ||||
| # else | |||||
| const int input_passes = denoise_buffer_num_passes(context.denoise_params); | |||||
| optix_assert(optixDenoiserInvoke(denoiser_.optix_denoiser, | |||||
| denoiser_.queue.stream(), | |||||
| ¶ms, | |||||
| denoiser_.state.device_pointer, | |||||
| denoiser_.scratch_offset, | |||||
| input_layers, | |||||
| input_passes, | |||||
| 0, | |||||
| 0, | |||||
| output_layers, | |||||
| denoiser_.state.device_pointer + denoiser_.scratch_offset, | |||||
| denoiser_.scratch_size)); | |||||
| # endif | |||||
| return true; | return true; | ||||
| } | } | ||||
| bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh, | bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh, | ||||
| OptixBuildOperation operation, | OptixBuildOperation operation, | ||||
| const OptixBuildInput &build_input, | const OptixBuildInput &build_input, | ||||
| uint16_t num_motion_steps) | uint16_t num_motion_steps) | ||||
| ▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | if (geom->geometry_type == Geometry::HAIR) { | ||||
| size_t num_motion_steps = 1; | size_t num_motion_steps = 1; | ||||
| Attribute *motion_keys = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); | Attribute *motion_keys = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); | ||||
| if (motion_blur && hair->get_use_motion_blur() && motion_keys) { | if (motion_blur && hair->get_use_motion_blur() && motion_keys) { | ||||
| num_motion_steps = hair->get_motion_steps(); | num_motion_steps = hair->get_motion_steps(); | ||||
| } | } | ||||
| device_vector<OptixAabb> aabb_data(this, "optix temp aabb data", MEM_READ_ONLY); | device_vector<OptixAabb> aabb_data(this, "optix temp aabb data", MEM_READ_ONLY); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| device_vector<int> index_data(this, "optix temp index data", MEM_READ_ONLY); | device_vector<int> index_data(this, "optix temp index data", MEM_READ_ONLY); | ||||
| device_vector<float4> vertex_data(this, "optix temp vertex data", MEM_READ_ONLY); | device_vector<float4> vertex_data(this, "optix temp vertex data", MEM_READ_ONLY); | ||||
| /* Four control points for each curve segment. */ | /* Four control points for each curve segment. */ | ||||
| const size_t num_vertices = num_segments * 4; | const size_t num_vertices = num_segments * 4; | ||||
| if (hair->curve_shape == CURVE_THICK) { | if (hair->curve_shape == CURVE_THICK) { | ||||
| index_data.alloc(num_segments); | index_data.alloc(num_segments); | ||||
| vertex_data.alloc(num_vertices * num_motion_steps); | vertex_data.alloc(num_vertices * num_motion_steps); | ||||
| } | } | ||||
| else | else | ||||
| # endif | |||||
| aabb_data.alloc(num_segments * num_motion_steps); | aabb_data.alloc(num_segments * num_motion_steps); | ||||
| /* Get AABBs for each motion step. */ | /* Get AABBs for each motion step. */ | ||||
| for (size_t step = 0; step < num_motion_steps; ++step) { | for (size_t step = 0; step < num_motion_steps; ++step) { | ||||
| /* The center step for motion vertices is not stored in the attribute. */ | /* The center step for motion vertices is not stored in the attribute. */ | ||||
| const float3 *keys = hair->get_curve_keys().data(); | const float3 *keys = hair->get_curve_keys().data(); | ||||
| size_t center_step = (num_motion_steps - 1) / 2; | size_t center_step = (num_motion_steps - 1) / 2; | ||||
| if (step != center_step) { | if (step != center_step) { | ||||
| size_t attr_offset = (step > center_step) ? step - 1 : step; | size_t attr_offset = (step > center_step) ? step - 1 : step; | ||||
| /* Technically this is a float4 array, but sizeof(float3) == sizeof(float4). */ | /* Technically this is a float4 array, but sizeof(float3) == sizeof(float4). */ | ||||
| keys = motion_keys->data_float3() + attr_offset * hair->get_curve_keys().size(); | keys = motion_keys->data_float3() + attr_offset * hair->get_curve_keys().size(); | ||||
| } | } | ||||
| for (size_t j = 0, i = 0; j < hair->num_curves(); ++j) { | for (size_t j = 0, i = 0; j < hair->num_curves(); ++j) { | ||||
| const Hair::Curve curve = hair->get_curve(j); | const Hair::Curve curve = hair->get_curve(j); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| const array<float> &curve_radius = hair->get_curve_radius(); | const array<float> &curve_radius = hair->get_curve_radius(); | ||||
| # endif | |||||
| for (int segment = 0; segment < curve.num_segments(); ++segment, ++i) { | for (int segment = 0; segment < curve.num_segments(); ++segment, ++i) { | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (hair->curve_shape == CURVE_THICK) { | if (hair->curve_shape == CURVE_THICK) { | ||||
| int k0 = curve.first_key + segment; | int k0 = curve.first_key + segment; | ||||
| int k1 = k0 + 1; | int k1 = k0 + 1; | ||||
| int ka = max(k0 - 1, curve.first_key); | int ka = max(k0 - 1, curve.first_key); | ||||
| int kb = min(k1 + 1, curve.first_key + curve.num_keys - 1); | int kb = min(k1 + 1, curve.first_key + curve.num_keys - 1); | ||||
| const float4 px = make_float4(keys[ka].x, keys[k0].x, keys[k1].x, keys[kb].x); | const float4 px = make_float4(keys[ka].x, keys[k0].x, keys[k1].x, keys[kb].x); | ||||
| const float4 py = make_float4(keys[ka].y, keys[k0].y, keys[k1].y, keys[kb].y); | const float4 py = make_float4(keys[ka].y, keys[k0].y, keys[k1].y, keys[kb].y); | ||||
| Show All 13 Lines | if (geom->geometry_type == Geometry::HAIR) { | ||||
| dot(cr2bsp0, px), dot(cr2bsp0, py), dot(cr2bsp0, pz), dot(cr2bsp0, pw)); | dot(cr2bsp0, px), dot(cr2bsp0, py), dot(cr2bsp0, pz), dot(cr2bsp0, pw)); | ||||
| v[1] = make_float4( | v[1] = make_float4( | ||||
| dot(cr2bsp1, px), dot(cr2bsp1, py), dot(cr2bsp1, pz), dot(cr2bsp1, pw)); | dot(cr2bsp1, px), dot(cr2bsp1, py), dot(cr2bsp1, pz), dot(cr2bsp1, pw)); | ||||
| v[2] = make_float4( | v[2] = make_float4( | ||||
| dot(cr2bsp2, px), dot(cr2bsp2, py), dot(cr2bsp2, pz), dot(cr2bsp2, pw)); | dot(cr2bsp2, px), dot(cr2bsp2, py), dot(cr2bsp2, pz), dot(cr2bsp2, pw)); | ||||
| v[3] = make_float4( | v[3] = make_float4( | ||||
| dot(cr2bsp3, px), dot(cr2bsp3, py), dot(cr2bsp3, pz), dot(cr2bsp3, pw)); | dot(cr2bsp3, px), dot(cr2bsp3, py), dot(cr2bsp3, pz), dot(cr2bsp3, pw)); | ||||
| } | } | ||||
| else | else { | ||||
| # endif | |||||
| { | |||||
| BoundBox bounds = BoundBox::empty; | BoundBox bounds = BoundBox::empty; | ||||
| curve.bounds_grow(segment, keys, hair->get_curve_radius().data(), bounds); | curve.bounds_grow(segment, keys, hair->get_curve_radius().data(), bounds); | ||||
| const size_t index = step * num_segments + i; | const size_t index = step * num_segments + i; | ||||
| aabb_data[index].minX = bounds.min.x; | aabb_data[index].minX = bounds.min.x; | ||||
| aabb_data[index].minY = bounds.min.y; | aabb_data[index].minY = bounds.min.y; | ||||
| aabb_data[index].minZ = bounds.min.z; | aabb_data[index].minZ = bounds.min.z; | ||||
| aabb_data[index].maxX = bounds.max.x; | aabb_data[index].maxX = bounds.max.x; | ||||
| aabb_data[index].maxY = bounds.max.y; | aabb_data[index].maxY = bounds.max.y; | ||||
| aabb_data[index].maxZ = bounds.max.z; | aabb_data[index].maxZ = bounds.max.z; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Upload AABB data to GPU. */ | /* Upload AABB data to GPU. */ | ||||
| aabb_data.copy_to_device(); | aabb_data.copy_to_device(); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| index_data.copy_to_device(); | index_data.copy_to_device(); | ||||
| vertex_data.copy_to_device(); | vertex_data.copy_to_device(); | ||||
| # endif | |||||
| vector<device_ptr> aabb_ptrs; | vector<device_ptr> aabb_ptrs; | ||||
| aabb_ptrs.reserve(num_motion_steps); | aabb_ptrs.reserve(num_motion_steps); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| vector<device_ptr> width_ptrs; | vector<device_ptr> width_ptrs; | ||||
| vector<device_ptr> vertex_ptrs; | vector<device_ptr> vertex_ptrs; | ||||
| width_ptrs.reserve(num_motion_steps); | width_ptrs.reserve(num_motion_steps); | ||||
| vertex_ptrs.reserve(num_motion_steps); | vertex_ptrs.reserve(num_motion_steps); | ||||
| # endif | |||||
| for (size_t step = 0; step < num_motion_steps; ++step) { | for (size_t step = 0; step < num_motion_steps; ++step) { | ||||
| aabb_ptrs.push_back(aabb_data.device_pointer + step * num_segments * sizeof(OptixAabb)); | aabb_ptrs.push_back(aabb_data.device_pointer + step * num_segments * sizeof(OptixAabb)); | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| const device_ptr base_ptr = vertex_data.device_pointer + | const device_ptr base_ptr = vertex_data.device_pointer + | ||||
| step * num_vertices * sizeof(float4); | step * num_vertices * sizeof(float4); | ||||
| width_ptrs.push_back(base_ptr + 3 * sizeof(float)); /* Offset by vertex size. */ | width_ptrs.push_back(base_ptr + 3 * sizeof(float)); /* Offset by vertex size. */ | ||||
| vertex_ptrs.push_back(base_ptr); | vertex_ptrs.push_back(base_ptr); | ||||
| # endif | |||||
| } | } | ||||
| /* Force a single any-hit call, so shadow record-all behavior works correctly. */ | /* Force a single any-hit call, so shadow record-all behavior works correctly. */ | ||||
| unsigned int build_flags = OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL; | unsigned int build_flags = OPTIX_GEOMETRY_FLAG_REQUIRE_SINGLE_ANYHIT_CALL; | ||||
| OptixBuildInput build_input = {}; | OptixBuildInput build_input = {}; | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (hair->curve_shape == CURVE_THICK) { | if (hair->curve_shape == CURVE_THICK) { | ||||
| build_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES; | build_input.type = OPTIX_BUILD_INPUT_TYPE_CURVES; | ||||
| build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; | build_input.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; | ||||
| build_input.curveArray.numPrimitives = num_segments; | build_input.curveArray.numPrimitives = num_segments; | ||||
| build_input.curveArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data(); | build_input.curveArray.vertexBuffers = (CUdeviceptr *)vertex_ptrs.data(); | ||||
| build_input.curveArray.numVertices = num_vertices; | build_input.curveArray.numVertices = num_vertices; | ||||
| build_input.curveArray.vertexStrideInBytes = sizeof(float4); | build_input.curveArray.vertexStrideInBytes = sizeof(float4); | ||||
| build_input.curveArray.widthBuffers = (CUdeviceptr *)width_ptrs.data(); | build_input.curveArray.widthBuffers = (CUdeviceptr *)width_ptrs.data(); | ||||
| build_input.curveArray.widthStrideInBytes = sizeof(float4); | build_input.curveArray.widthStrideInBytes = sizeof(float4); | ||||
| build_input.curveArray.indexBuffer = (CUdeviceptr)index_data.device_pointer; | build_input.curveArray.indexBuffer = (CUdeviceptr)index_data.device_pointer; | ||||
| build_input.curveArray.indexStrideInBytes = sizeof(int); | build_input.curveArray.indexStrideInBytes = sizeof(int); | ||||
| build_input.curveArray.flag = build_flags; | build_input.curveArray.flag = build_flags; | ||||
| build_input.curveArray.primitiveIndexOffset = hair->optix_prim_offset; | build_input.curveArray.primitiveIndexOffset = hair->optix_prim_offset; | ||||
| } | } | ||||
| else | else { | ||||
| # endif | |||||
| { | |||||
| /* Disable visibility test any-hit program, since it is already checked during | /* Disable visibility test any-hit program, since it is already checked during | ||||
| * intersection. Those trace calls that require anyhit can force it with a ray flag. */ | * intersection. Those trace calls that require anyhit can force it with a ray flag. */ | ||||
| build_flags |= OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; | build_flags |= OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT; | ||||
| build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; | build_input.type = OPTIX_BUILD_INPUT_TYPE_CUSTOM_PRIMITIVES; | ||||
| # if OPTIX_ABI_VERSION < 23 | |||||
| build_input.aabbArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data(); | |||||
| build_input.aabbArray.numPrimitives = num_segments; | |||||
| build_input.aabbArray.strideInBytes = sizeof(OptixAabb); | |||||
| build_input.aabbArray.flags = &build_flags; | |||||
| build_input.aabbArray.numSbtRecords = 1; | |||||
| build_input.aabbArray.primitiveIndexOffset = hair->optix_prim_offset; | |||||
| # else | |||||
| build_input.customPrimitiveArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data(); | build_input.customPrimitiveArray.aabbBuffers = (CUdeviceptr *)aabb_ptrs.data(); | ||||
| build_input.customPrimitiveArray.numPrimitives = num_segments; | build_input.customPrimitiveArray.numPrimitives = num_segments; | ||||
| build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb); | build_input.customPrimitiveArray.strideInBytes = sizeof(OptixAabb); | ||||
| build_input.customPrimitiveArray.flags = &build_flags; | build_input.customPrimitiveArray.flags = &build_flags; | ||||
| build_input.customPrimitiveArray.numSbtRecords = 1; | build_input.customPrimitiveArray.numSbtRecords = 1; | ||||
| build_input.customPrimitiveArray.primitiveIndexOffset = hair->optix_prim_offset; | build_input.customPrimitiveArray.primitiveIndexOffset = hair->optix_prim_offset; | ||||
| # endif | |||||
| } | } | ||||
| if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) { | if (!build_optix_bvh(bvh_optix, operation, build_input, num_motion_steps)) { | ||||
| progress.set_error("Failed to build OptiX acceleration structure"); | progress.set_error("Failed to build OptiX acceleration structure"); | ||||
| } | } | ||||
| } | } | ||||
| else if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { | else if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) { | ||||
| /* Build BLAS for triangle primitives. */ | /* Build BLAS for triangle primitives. */ | ||||
| ▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | else { | ||||
| max_num_instances >>= 1; | max_num_instances >>= 1; | ||||
| if (bvh->objects.size() > max_num_instances) { | if (bvh->objects.size() > max_num_instances) { | ||||
| progress.set_error( | progress.set_error( | ||||
| "Failed to build OptiX acceleration structure because there are too many instances"); | "Failed to build OptiX acceleration structure because there are too many instances"); | ||||
| return; | return; | ||||
| } | } | ||||
| /* Fill instance descriptions. */ | /* Fill instance descriptions. */ | ||||
| # if OPTIX_ABI_VERSION < 41 | |||||
| device_vector<OptixAabb> aabbs(this, "optix tlas aabbs", MEM_READ_ONLY); | |||||
| aabbs.alloc(bvh->objects.size()); | |||||
| # endif | |||||
| device_vector<OptixInstance> instances(this, "optix tlas instances", MEM_READ_ONLY); | device_vector<OptixInstance> instances(this, "optix tlas instances", MEM_READ_ONLY); | ||||
| instances.alloc(bvh->objects.size()); | instances.alloc(bvh->objects.size()); | ||||
| /* Calculate total motion transform size and allocate memory for them. */ | /* Calculate total motion transform size and allocate memory for them. */ | ||||
| size_t motion_transform_offset = 0; | size_t motion_transform_offset = 0; | ||||
| if (motion_blur) { | if (motion_blur) { | ||||
| size_t total_motion_transform_size = 0; | size_t total_motion_transform_size = 0; | ||||
| for (Object *const ob : bvh->objects) { | for (Object *const ob : bvh->objects) { | ||||
| Show All 15 Lines | for (Object *ob : bvh->objects) { | ||||
| /* Skip non-traceable objects. */ | /* Skip non-traceable objects. */ | ||||
| if (!ob->is_traceable()) { | if (!ob->is_traceable()) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| BVHOptiX *const blas = static_cast<BVHOptiX *>(ob->get_geometry()->bvh); | BVHOptiX *const blas = static_cast<BVHOptiX *>(ob->get_geometry()->bvh); | ||||
| OptixTraversableHandle handle = blas->traversable_handle; | OptixTraversableHandle handle = blas->traversable_handle; | ||||
| # if OPTIX_ABI_VERSION < 41 | |||||
| OptixAabb &aabb = aabbs[num_instances]; | |||||
| aabb.minX = ob->bounds.min.x; | |||||
| aabb.minY = ob->bounds.min.y; | |||||
| aabb.minZ = ob->bounds.min.z; | |||||
| aabb.maxX = ob->bounds.max.x; | |||||
| aabb.maxY = ob->bounds.max.y; | |||||
| aabb.maxZ = ob->bounds.max.z; | |||||
| # endif | |||||
| OptixInstance &instance = instances[num_instances++]; | OptixInstance &instance = instances[num_instances++]; | ||||
| memset(&instance, 0, sizeof(instance)); | memset(&instance, 0, sizeof(instance)); | ||||
| /* Clear transform to identity matrix. */ | /* Clear transform to identity matrix. */ | ||||
| instance.transform[0] = 1.0f; | instance.transform[0] = 1.0f; | ||||
| instance.transform[5] = 1.0f; | instance.transform[5] = 1.0f; | ||||
| instance.transform[10] = 1.0f; | instance.transform[10] = 1.0f; | ||||
| /* Set user instance ID to object index (but leave low bit blank). */ | /* Set user instance ID to object index (but leave low bit blank). */ | ||||
| instance.instanceId = ob->get_device_index() << 1; | instance.instanceId = ob->get_device_index() << 1; | ||||
| /* Have to have at least one bit in the mask, or else instance would always be culled. */ | /* Have to have at least one bit in the mask, or else instance would always be culled. */ | ||||
| instance.visibilityMask = 1; | instance.visibilityMask = 1; | ||||
| if (ob->get_geometry()->has_volume) { | if (ob->get_geometry()->has_volume) { | ||||
| /* Volumes have a special bit set in the visibility mask so a trace can mask only volumes. | /* Volumes have a special bit set in the visibility mask so a trace can mask only volumes. | ||||
| */ | */ | ||||
| instance.visibilityMask |= 2; | instance.visibilityMask |= 2; | ||||
| } | } | ||||
| if (ob->get_geometry()->geometry_type == Geometry::HAIR) { | if (ob->get_geometry()->geometry_type == Geometry::HAIR) { | ||||
| /* Same applies to curves (so they can be skipped in local trace calls). */ | /* Same applies to curves (so they can be skipped in local trace calls). */ | ||||
| instance.visibilityMask |= 4; | instance.visibilityMask |= 4; | ||||
| # if OPTIX_ABI_VERSION >= 47 | |||||
| if (motion_blur && ob->get_geometry()->has_motion_blur() && | if (motion_blur && ob->get_geometry()->has_motion_blur() && | ||||
| static_cast<const Hair *>(ob->get_geometry())->curve_shape == CURVE_THICK) { | static_cast<const Hair *>(ob->get_geometry())->curve_shape == CURVE_THICK) { | ||||
| /* Select between motion blur and non-motion blur built-in intersection module. */ | /* Select between motion blur and non-motion blur built-in intersection module. */ | ||||
| instance.sbtOffset = PG_HITD_MOTION - PG_HITD; | instance.sbtOffset = PG_HITD_MOTION - PG_HITD; | ||||
| } | } | ||||
| # endif | |||||
| } | } | ||||
| /* Insert motion traversable if object has motion. */ | /* Insert motion traversable if object has motion. */ | ||||
| if (motion_blur && ob->use_motion()) { | if (motion_blur && ob->use_motion()) { | ||||
| size_t motion_keys = max(ob->get_motion().size(), 2) - 2; | size_t motion_keys = max(ob->get_motion().size(), 2) - 2; | ||||
| size_t motion_transform_size = sizeof(OptixSRTMotionTransform) + | size_t motion_transform_size = sizeof(OptixSRTMotionTransform) + | ||||
| motion_keys * sizeof(OptixSRTData); | motion_keys * sizeof(OptixSRTData); | ||||
| ▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | for (Object *ob : bvh->objects) { | ||||
| /* Non-instanced objects read ID from 'prim_object', so distinguish | /* Non-instanced objects read ID from 'prim_object', so distinguish | ||||
| * them from instanced objects with the low bit set. */ | * them from instanced objects with the low bit set. */ | ||||
| instance.instanceId |= 1; | instance.instanceId |= 1; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Upload instance descriptions. */ | /* Upload instance descriptions. */ | ||||
| # if OPTIX_ABI_VERSION < 41 | |||||
| aabbs.resize(num_instances); | |||||
| aabbs.copy_to_device(); | |||||
| # endif | |||||
| instances.resize(num_instances); | instances.resize(num_instances); | ||||
| instances.copy_to_device(); | instances.copy_to_device(); | ||||
| /* Build top-level acceleration structure (TLAS) */ | /* Build top-level acceleration structure (TLAS) */ | ||||
| OptixBuildInput build_input = {}; | OptixBuildInput build_input = {}; | ||||
| build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; | build_input.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; | ||||
| # if OPTIX_ABI_VERSION < 41 /* Instance AABBs no longer need to be set since OptiX 7.2 */ | |||||
| build_input.instanceArray.aabbs = aabbs.device_pointer; | |||||
| build_input.instanceArray.numAabbs = num_instances; | |||||
| # endif | |||||
| build_input.instanceArray.instances = instances.device_pointer; | build_input.instanceArray.instances = instances.device_pointer; | ||||
| build_input.instanceArray.numInstances = num_instances; | build_input.instanceArray.numInstances = num_instances; | ||||
| if (!build_optix_bvh(bvh_optix, OPTIX_BUILD_OPERATION_BUILD, build_input, 0)) { | if (!build_optix_bvh(bvh_optix, OPTIX_BUILD_OPERATION_BUILD, build_input, 0)) { | ||||
| progress.set_error("Failed to build OptiX acceleration structure"); | progress.set_error("Failed to build OptiX acceleration structure"); | ||||
| } | } | ||||
| tlas_handle = bvh_optix->traversable_handle; | tlas_handle = bvh_optix->traversable_handle; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines | |||||