Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
adf0db4
Restore EX31 precompiled shader flow
AnastaZIuk Mar 23, 2026
13f0920
Reorganize EX31 precompiled shader variants
AnastaZIuk Mar 23, 2026
6fec0e4
Add EX31 pipeline cache and warmup
AnastaZIuk Mar 23, 2026
25d3f00
Improve path tracer startup and UI
AnastaZIuk Mar 23, 2026
3b9b2f3
Fix path tracer debug warmup
AnastaZIuk Mar 23, 2026
f966e19
Add path tracer build mode switch
AnastaZIuk Mar 24, 2026
6b5ff68
Polish path tracer diagnostics
AnastaZIuk Mar 24, 2026
200cb4a
Trim trailing whitespace
AnastaZIuk Mar 24, 2026
b78500c
Clarify path tracer build mode comment
AnastaZIuk Mar 24, 2026
1a64e82
Persist path tracer validation markers
AnastaZIuk Mar 24, 2026
db1e1cf
Polish path tracer cache layout
AnastaZIuk Mar 24, 2026
20587db
Refine path tracer cleanup
AnastaZIuk Mar 24, 2026
764d4ef
Compact path tracer variant payload
AnastaZIuk Mar 24, 2026
9215e38
Trim path tracer example boilerplate
AnastaZIuk Mar 24, 2026
4a68db6
Remove dead path tracer shader roots
AnastaZIuk Mar 24, 2026
704ef5f
Use argparse in EX31 startup
AnastaZIuk Mar 24, 2026
3fd1ae6
Use generated keys header in EX31
AnastaZIuk Mar 24, 2026
bfaa4a2
Fix EX31 generated keys usage
AnastaZIuk Mar 24, 2026
615ae45
Align EX31 NSC rule usage
AnastaZIuk Mar 24, 2026
caaf16c
Fix EX31 generated keys include seam
AnastaZIuk Mar 24, 2026
079b6e4
Use standard EX31 generated keys seam
AnastaZIuk Mar 24, 2026
fc1ae32
Fix EX31 generated keys wrapper seam
AnastaZIuk Mar 25, 2026
8424767
Fix EX31 NSC include usage
AnastaZIuk Mar 25, 2026
018757b
Simplify EX31 NSC rule usage
AnastaZIuk Mar 25, 2026
a3ef360
Seed EX31 trimmer validation cache
AnastaZIuk Mar 25, 2026
339cb3e
Wire EX31 NSC rule dependencies
AnastaZIuk Mar 25, 2026
04863f9
Restore EX31 NSC direct include usage
AnastaZIuk Mar 25, 2026
7b6c154
Refine EX31 CMake helpers
AnastaZIuk Mar 25, 2026
520e26f
Simplify EX31 precompiled variants
AnastaZIuk Mar 25, 2026
7e0e7f9
Address EX31 review feedback locally
AnastaZIuk Mar 26, 2026
7c0858b
Commonize EX31 cached pipeline state
AnastaZIuk Mar 26, 2026
6b05636
Rename common cached pipeline seam
AnastaZIuk Mar 26, 2026
d50719c
Use system include workaround for builtin roots
AnastaZIuk Mar 26, 2026
2d663f5
Merge remote-tracking branch 'origin/master' into unroll
AnastaZIuk Mar 26, 2026
887100f
Merge remote-tracking branch 'origin/master' into unroll
AnastaZIuk Mar 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 104 additions & 22 deletions 31_HLSLPathTracer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
include(common RESULT_VARIABLE RES)

if(NOT RES)
message(FATAL_ERROR "common.cmake not found. Should be in {repo_root}/cmake directory")
endif()
include(common)
include("${CMAKE_CURRENT_SOURCE_DIR}/pt.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/pt.variant_ids.cmake")

if(NBL_BUILD_IMGUI)
# PT_BUILD_MODE controls how EX31 packages triangle polygon-method variants.
# WALLTIME_OPTIMIZED keeps triangle polygon-method selection inside one shared shader module.
# This preserves the same runtime feature surface while keeping triangle methods on one heavy backend compile path.
# SPECIALIZED bakes Area, SolidAngle and ProjectedSolidAngle into separate triangle entrypoints.
# That does not add only thin entrypoints. It multiplies the heavy triangle-side path tracing instantiations and pushes more work into the DXC/SPIR-V backend.
# On AMD Ryzen 5 5600G with Radeon Graphics (6C/12T),
# a Visual Studio Debug x64 full rebuild of the SPIR-V project completed in:
# WALLTIME_OPTIMIZED = 12.785 s
# SPECIALIZED = 18.314 s
# SPECIALIZED is +5.529 s slower which is +43.25%.
# Equivalently, WALLTIME_OPTIMIZED is 30.19% faster than SPECIALIZED.
# This comes from multiplying the heavy triangle-side path tracing instantiations
# and pushing more work into the DXC/SPIR-V backend.
# Therefore the default stays WALLTIME_OPTIMIZED.
set(PT_BUILD_MODE "WALLTIME_OPTIMIZED" CACHE STRING
"Choose the EX31 precompiled shader layout. WALLTIME_OPTIMIZED keeps polygon-method selection inside the shared triangle shader module to reduce compile wall time. SPECIALIZED bakes triangle polygon methods into distinct entrypoints, which increases backend work and rebuild time but keeps those variants as separate precompiled entrypoints."
)
set(PT_CACHE_ROOT "pipeline/cache" CACHE STRING
"Relative cache root written to path_tracer.runtime.json in the common bin directory. The runtime resolves this path relative to the JSON file location. Empty disables the generated dev-mode JSON and falls back to --pipeline-cache-dir or LocalAppData."
)
set_property(CACHE PT_BUILD_MODE PROPERTY STRINGS WALLTIME_OPTIMIZED SPECIALIZED)
set(_PT_BUILD_MODE_VALUES WALLTIME_OPTIMIZED SPECIALIZED)
if(NOT PT_BUILD_MODE IN_LIST _PT_BUILD_MODE_VALUES)
message(FATAL_ERROR "Unsupported PT_BUILD_MODE='${PT_BUILD_MODE}'. Expected one of: ${_PT_BUILD_MODE_VALUES}")
endif()
if(IS_ABSOLUTE "${PT_CACHE_ROOT}")
message(FATAL_ERROR "PT_CACHE_ROOT must stay relative because the runtime resolves it against path_tracer.runtime.json")
endif()

set(NBL_INCLUDE_SERACH_DIRECTORIES
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
Expand All @@ -16,25 +43,80 @@ if(NBL_BUILD_IMGUI)
)

nbl_create_executable_project("" "" "${NBL_INCLUDE_SERACH_DIRECTORIES}" "${NBL_LIBRARIES}" "${NBL_EXECUTABLE_PROJECT_CREATION_PCH_TARGET}")
add_dependencies(${EXECUTABLE_NAME} argparse)
target_include_directories(${EXECUTABLE_NAME} PUBLIC $<TARGET_PROPERTY:argparse,INTERFACE_INCLUDE_DIRECTORIES>)
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE PT_BUILD_CONFIG_NAME=\"$<CONFIG>\")
if(PT_BUILD_MODE STREQUAL "SPECIALIZED")
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE PT_BUILD_MODE_SPECIALIZED=1)
else()
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE PT_BUILD_MODE_WALLTIME_OPTIMIZED=1)
endif()
if(NOT PT_CACHE_ROOT STREQUAL "")
string(REPLACE "\\" "/" PT_CACHE_ROOT_JSON "${PT_CACHE_ROOT}")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/path_tracer.runtime.json.in"
"${CMAKE_CURRENT_BINARY_DIR}/path_tracer.runtime.json"
@ONLY
)
file(GENERATE
OUTPUT "$<TARGET_FILE_DIR:${EXECUTABLE_NAME}>/path_tracer.runtime.json"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/path_tracer.runtime.json"
)
endif()

if(NBL_EMBED_BUILTIN_RESOURCES)
set(_BR_TARGET_ ${EXECUTABLE_NAME}_builtinResourceData)
set(RESOURCE_DIR "app_resources")

get_filename_component(_SEARCH_DIRECTORIES_ "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
get_filename_component(_OUTPUT_DIRECTORY_SOURCE_ "${CMAKE_CURRENT_BINARY_DIR}/src" ABSOLUTE)
get_filename_component(_OUTPUT_DIRECTORY_HEADER_ "${CMAKE_CURRENT_BINARY_DIR}/include" ABSOLUTE)

file(GLOB_RECURSE BUILTIN_RESOURCE_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_DIR}/*")

foreach(RES_FILE ${BUILTIN_RESOURCE_FILES})
LIST_BUILTIN_RESOURCE(RESOURCES_TO_EMBED "${RES_FILE}")
endforeach()

ADD_CUSTOM_BUILTIN_RESOURCES(${_BR_TARGET_} RESOURCES_TO_EMBED "${_SEARCH_DIRECTORIES_}" "${RESOURCE_DIR}" "nbl::this_example::builtin" "${_OUTPUT_DIRECTORY_HEADER_}" "${_OUTPUT_DIRECTORY_SOURCE_}")
set(SM 6_8)
set(OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/auto-gen")
set(COMPILE_OPTIONS
-I "${CMAKE_CURRENT_SOURCE_DIR}/include"
-I "${CMAKE_CURRENT_SOURCE_DIR}/app_resources/hlsl"
-I "${NBL_ROOT_PATH}/include" # workaround, the same thing like in IES I will address this issue later
-T "lib_${SM}"
-Wno-conversion
-Wno-sign-conversion
-Wno-float-conversion
-Wno-shorten-64-to-32
-Wno-shadow
-Wno-literal-range
)

LINK_BUILTIN_RESOURCES_TO_TARGET(${EXECUTABLE_NAME} ${_BR_TARGET_})
# Keep the payload flat and explicit here. Once Nabla PR #988 lands, these per-rule compile axes should move to first-class packaged-variant support there.
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.sphere.proxy.hlsl" KEY "pt.compute.sphere" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=0" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_SPHERE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_RUNTIME_UNIFORM}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=0")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.sphere.rwmc.proxy.hlsl" KEY "pt.compute.sphere.rwmc" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_SPHERE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_RUNTIME_UNIFORM}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=0")
if(PT_BUILD_MODE STREQUAL "SPECIALIZED")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.triangle.linear.proxy.hlsl" KEY "pt.compute.triangle.linear" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=0" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_LINEAR}")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.triangle.persistent.proxy.hlsl" KEY "pt.compute.triangle.persistent" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=0" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_PERSISTENT}")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.triangle.rwmc.linear.proxy.hlsl" KEY "pt.compute.triangle.rwmc.linear" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_LINEAR}")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.triangle.rwmc.persistent.proxy.hlsl" KEY "pt.compute.triangle.rwmc.persistent" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_PERSISTENT}")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.rectangle.rwmc.linear.proxy.hlsl" KEY "pt.compute.rectangle.rwmc.linear" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_RECTANGLE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_LINEAR}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=1")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.rectangle.rwmc.persistent.proxy.hlsl" KEY "pt.compute.rectangle.rwmc.persistent" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_RECTANGLE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_PERSISTENT}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=1")
else()
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.triangle.proxy.hlsl" KEY "pt.compute.triangle" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=0" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_TRIANGLE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_RUNTIME_UNIFORM}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=1")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.triangle.rwmc.proxy.hlsl" KEY "pt.compute.triangle.rwmc" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_TRIANGLE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_RUNTIME_UNIFORM}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=1")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.rectangle.rwmc.proxy.hlsl" KEY "pt.compute.rectangle.rwmc" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=1" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_RECTANGLE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_RUNTIME_UNIFORM}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=1")
endif()
endif()
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.compute.rectangle.proxy.hlsl" KEY "pt.compute.rectangle" COMPILE_OPTIONS "-DPT_VARIANT_USE_RWMC=0" "-DPT_VARIANT_SCENE_KIND=${PT_SCENE_RECTANGLE}" "-DPT_VARIANT_ENTRYPOINT_KIND=${PT_ENTRYPOINT_RUNTIME_UNIFORM}" "-DPT_VARIANT_RUNTIME_POLYGON_METHOD=1")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/resolve.comp.hlsl" KEY "pt.compute.resolve")
PT_APPEND_SPIRV_RULE(VAR JSON INPUT "app_resources/hlsl/spirv/pt.misc.proxy.hlsl" KEY "pt.misc")
PT_FINALIZE_JSON_PAYLOAD(INOUT JSON)

NBL_CREATE_NSC_COMPILE_RULES(
TARGET ${EXECUTABLE_NAME}SPIRV
LINK_TO ${EXECUTABLE_NAME}
DEPENDS ${DEPENDS}
BINARY_DIR ${OUTPUT_DIRECTORY}
MOUNT_POINT_DEFINE NBL_THIS_EXAMPLE_BUILD_MOUNT_POINT
COMMON_OPTIONS ${COMPILE_OPTIONS}
OUTPUT_VAR KEYS
INCLUDE nbl/this_example/builtin/build/spirv/keys.hpp
NAMESPACE nbl::this_example::builtin::build
INPUTS ${JSON}
)

NBL_CREATE_RESOURCE_ARCHIVE(
NAMESPACE nbl::this_example::builtin::build
TARGET ${EXECUTABLE_NAME}_builtinsBuild
LINK_TO ${EXECUTABLE_NAME}
BIND ${OUTPUT_DIRECTORY}
BUILTINS ${KEYS}
)
endif()
62 changes: 62 additions & 0 deletions 31_HLSLPathTracer/app_resources/hlsl/compute.render.common.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#ifndef PATH_TRACER_USE_RWMC
#error PATH_TRACER_USE_RWMC must be defined before including compute.render.common.hlsl
#endif

#ifndef PATH_TRACER_ENABLE_LINEAR
#define PATH_TRACER_ENABLE_LINEAR 1
#endif

#ifndef PATH_TRACER_ENABLE_PERSISTENT
#define PATH_TRACER_ENABLE_PERSISTENT 1
#endif

#if !PATH_TRACER_ENABLE_LINEAR && !PATH_TRACER_ENABLE_PERSISTENT
#error At least one path tracer entrypoint mode must be enabled
#endif

#include "nbl/builtin/hlsl/cpp_compat.hlsl"
#include "nbl/builtin/hlsl/glsl_compat/core.hlsl"
#include "nbl/builtin/hlsl/random/pcg.hlsl"
#include "nbl/builtin/hlsl/random/xoroshiro.hlsl"
#if PATH_TRACER_ENABLE_PERSISTENT
#include "nbl/builtin/hlsl/morton.hlsl"
#endif
#include "nbl/builtin/hlsl/bxdf/reflection.hlsl"
#include "nbl/builtin/hlsl/bxdf/transmission.hlsl"
#include "nbl/builtin/hlsl/path_tracing/basic_ray_gen.hlsl"
#include "nbl/builtin/hlsl/path_tracing/unidirectional.hlsl"
#include "render_common.hlsl"

#if PATH_TRACER_USE_RWMC
#include "nbl/builtin/hlsl/rwmc/CascadeAccumulator.hlsl"
#include "render_rwmc_common.hlsl"
#else
#include "nbl/builtin/hlsl/path_tracing/default_accumulator.hlsl"
#endif

#if PATH_TRACER_USE_RWMC
[[vk::push_constant]] RenderRWMCPushConstants pc;
#else
[[vk::push_constant]] RenderPushConstants pc;
#endif

[[vk::combinedImageSampler]] [[vk::binding(0, 0)]] Texture2D<float3> envMap;
[[vk::combinedImageSampler]] [[vk::binding(0, 0)]] SamplerState envSampler;

[[vk::combinedImageSampler]] [[vk::binding(1, 0)]] Texture2D<uint2> scramblebuf;
[[vk::combinedImageSampler]] [[vk::binding(1, 0)]] SamplerState scrambleSampler;

[[vk::image_format("rgba16f")]] [[vk::binding(2, 0)]] RWTexture2DArray<float32_t4> outImage;

#if PATH_TRACER_USE_RWMC
[[vk::image_format("rgba16f")]] [[vk::binding(3, 0)]] RWTexture2DArray<float32_t4> cascade;
#endif

#include "example_common.hlsl"
#include "rand_gen.hlsl"
#include "intersector.hlsl"
#include "material_system.hlsl"
#include "next_event_estimator.hlsl"

using namespace nbl;
using namespace hlsl;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef PATH_TRACER_ENTRYPOINT_NAME
#define PATH_TRACER_ENTRYPOINT_NAME main
#endif

#ifndef PATH_TRACER_ENTRYPOINT_POLYGON_METHOD
#ifdef PATH_TRACER_RUNTIME_POLYGON_METHOD
#define PATH_TRACER_ENTRYPOINT_POLYGON_METHOD PATH_TRACER_RUNTIME_POLYGON_METHOD
#else
#define PATH_TRACER_ENTRYPOINT_POLYGON_METHOD PPM_APPROX_PROJECTED_SOLID_ANGLE
#endif
#endif

#if !PATH_TRACER_ENABLE_LINEAR
#error Linear entrypoint requested while PATH_TRACER_ENABLE_LINEAR is disabled
#endif

[numthreads(RenderWorkgroupSize, 1, 1)]
[shader("compute")]
void PATH_TRACER_ENTRYPOINT_NAME(uint32_t3 threadID : SV_DispatchThreadID)
{
pathtracer_render_variant::runLinear(threadID, PATH_TRACER_ENTRYPOINT_POLYGON_METHOD);
}

#undef PATH_TRACER_ENTRYPOINT_POLYGON_METHOD
#undef PATH_TRACER_ENTRYPOINT_NAME
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef PATH_TRACER_ENTRYPOINT_NAME
#define PATH_TRACER_ENTRYPOINT_NAME mainPersistent
#endif

#ifndef PATH_TRACER_ENTRYPOINT_POLYGON_METHOD
#ifdef PATH_TRACER_RUNTIME_POLYGON_METHOD
#define PATH_TRACER_ENTRYPOINT_POLYGON_METHOD PATH_TRACER_RUNTIME_POLYGON_METHOD
#else
#define PATH_TRACER_ENTRYPOINT_POLYGON_METHOD PPM_APPROX_PROJECTED_SOLID_ANGLE
#endif
#endif

#if !PATH_TRACER_ENABLE_PERSISTENT
#error Persistent entrypoint requested while PATH_TRACER_ENABLE_PERSISTENT is disabled
#endif
Comment on lines +1 to +11

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just make a Config struct with NBL_CONSTEXPR_STATIC_INLINE members and then we don't need to change definitions, so:

  1. Boost Wave preprocessing is reusable
  2. Clang-AST actually spots similar instantiations
  3. Unity Build is possible


[numthreads(RenderWorkgroupSize, 1, 1)]
[shader("compute")]
void PATH_TRACER_ENTRYPOINT_NAME(uint32_t3 threadID : SV_DispatchThreadID)
{
pathtracer_render_variant::runPersistent(PATH_TRACER_ENTRYPOINT_POLYGON_METHOD);
}

#undef PATH_TRACER_ENTRYPOINT_POLYGON_METHOD
#undef PATH_TRACER_ENTRYPOINT_NAME
Loading