diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b90222..ede34d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,13 +382,43 @@ add_dependencies(donut_interop check_interop_types) # The functions have no dllexport, so export all of core/donut_interop.cpp's symbols; its import library # is renamed so it doesn't overwrite the static donut_interop.lib. # There is no JIT on Android, so no shared build there either. +# Under the JIT this one library is all an example gets, so it also holds the C++ modules that only +# some examples link into their executables (their add_tslang_example sources), with what those +# need: the OBJ, SDKMESH and meshlet loaders, the PBRT scene, DirectXCollision, Basis Universal's +# transcoder, the fast block compressor, the paged images, and (Windows) the video player. +set(JIT_MODULE_SOURCES + core/obj_model.cpp + core/sdkmesh.cpp + core/meshlet_model.cpp + core/denoised_rtao.cpp + core/pbrt/PBRTParser.cpp + core/pbrt/PlyParser.cpp + core/directx_collision.cpp + core/basis_transcoder.cpp + core/fast_block_compress.cpp + core/fbc_cpu.cpp + core/paged_images.cpp) +if (WIN32) + list(APPEND JIT_MODULE_SOURCES core/video_player.cpp) +endif() if (NOT ANDROID) - add_library(donut_interop_shared SHARED core/donut_interop.cpp) + add_library(donut_interop_shared SHARED core/donut_interop.cpp ${JIT_MODULE_SOURCES}) configure_donut_interop(donut_interop_shared) set_target_properties(donut_interop_shared PROPERTIES OUTPUT_NAME donut_interop ARCHIVE_OUTPUT_NAME donut_interop_shared WINDOWS_EXPORT_ALL_SYMBOLS ON) + target_link_libraries(donut_interop_shared PRIVATE basisu_transcoder) + # The Agility SDK runtime for the examples whose executables opt into it (see + # UseAgilitySdkUnderJit): tslang.exe doesn't. + if (DONUT_D3D_AGILITY_SDK_VERSION) + target_compile_definitions(donut_interop_shared PRIVATE DONUT_JIT_AGILITY_SDK_VERSION=${DONUT_D3D_AGILITY_SDK_VERSION}) + endif() + if (WIN32) + # As video_texture's: mfplat.dll delay-loaded (Windows N editions lack it). + target_link_libraries(donut_interop_shared PRIVATE delayimp) + target_link_options(donut_interop_shared PRIVATE /DELAYLOAD:mfplat.dll) + endif() endif() # With DONUT_WITH_DLSS, NGX loads nvngx_dlss.dll from the directory of the executable (of diff --git a/README.md b/README.md index cbe89d7..7d32237 100644 --- a/README.md +++ b/README.md @@ -205,12 +205,22 @@ does for `.cpp`. - tslang can't write a depfile, so the files a `.ts` imports or references aren't tracked for it: list them as its `OBJECT_DEPENDS`, as `CMakeLists.txt` does for `core/`. -The examples can also run under tslang's JIT, against the shared build of the interop layer: +The examples can also run under tslang's JIT, against the shared build of the interop layer +(`run_jit.bat examples/.ts [-- args]` does this from the repo root): ``` -tslang --emit=jit --shared-libs=build/bin/donut_interop.dll examples/basic_triangle.ts +tslang --emit=jit --jit-cache=false --shared-libs=build/bin/donut_interop.dll examples/basic_triangle.ts -- -dx12 ``` +- Program arguments go after `--`. +- `--jit-cache=false`: tslang pre-alpha93's JIT cache crashes in a run that compiles two or more + modules, so an example (with its imports) crashed on its first two runs + ([TypeScriptCompiler#548](https://github.com/ASDAlexander77/TypeScriptCompiler/pull/548)). +- The shared library also holds the C++ modules some examples link (`core/sdkmesh.cpp`, + `core/meshlet_model.cpp`, `core/paged_images.cpp`, ...), and applies the D3D12 Agility SDK + runtime from `bin/D3D12` (the executables that need it opt in through their exports, which + `tslang.exe` doesn't have). + ### Passing flags ```cmake diff --git a/core/donut_interop.cpp b/core/donut_interop.cpp index a2e0fe8..62c0b0d 100644 --- a/core/donut_interop.cpp +++ b/core/donut_interop.cpp @@ -2328,6 +2328,39 @@ extern "C" { // --- Application ----------------------------------------------------------------------- +#if defined(DONUT_JIT_AGILITY_SDK_VERSION) && DONUT_WITH_DX12 + // The executables that need the Agility SDK runtime (D3D12Core.dll in bin/D3D12) export its + // version and path (core/d3d12_agility_sdk.cpp), which D3D12 looks up in the process's + // executable. Under tslang's JIT that's tslang.exe, which doesn't, so this library (the JIT's + // build only) makes a device factory for that runtime and applies it to D3D12's global state + // before the first device: devices made afterwards (Donut's) use it. Once per process, and only + // when the executable doesn't opt in itself. + static void UseAgilitySdkUnderJit() + { + static bool s_Done = false; + if (s_Done) + return; + s_Done = true; + if (GetProcAddress(GetModuleHandleW(nullptr), "D3D12SDKVersion")) + return; + const std::filesystem::path sdkPath = GetExecutablePath().parent_path() / "D3D12"; + if (!std::filesystem::exists(sdkPath / "D3D12Core.dll")) + return; + Microsoft::WRL::ComPtr configuration; + Microsoft::WRL::ComPtr factory; + // The path is the runtime's folder, with a trailing separator. + const std::string path = sdkPath.string() + "\\"; + if (FAILED(D3D12GetInterface(CLSID_D3D12SDKConfiguration, IID_PPV_ARGS(&configuration))) + || FAILED(configuration->CreateDeviceFactory(DONUT_JIT_AGILITY_SDK_VERSION, path.c_str(), IID_PPV_ARGS(&factory))) + || FAILED(factory->ApplyToGlobalState())) + { + donut::log::warning("Cannot use the D3D12 Agility SDK runtime in %s; the system's runtime is used", path.c_str()); + return; + } + donut::log::info("Using the D3D12 Agility SDK runtime %d in %s", DONUT_JIT_AGILITY_SDK_VERSION, path.c_str()); + } +#endif + // Values of the `options` bit mask of Donut_CreateAppWithOptions. enum AppOptions { @@ -2352,6 +2385,10 @@ extern "C" donut::log::ConsoleApplicationMode(); const auto api = static_cast(graphicsApi); +#if defined(DONUT_JIT_AGILITY_SDK_VERSION) && DONUT_WITH_DX12 + if (api == nvrhi::GraphicsAPI::D3D12) + UseAgilitySdkUnderJit(); +#endif std::unique_ptr deviceManager(DeviceManager::Create(api)); if (!deviceManager) return nullptr; diff --git a/examples/bokeh.ts b/examples/bokeh.ts index 60fe125..3bbff3c 100644 --- a/examples/bokeh.ts +++ b/examples/bokeh.ts @@ -1238,7 +1238,7 @@ namespace Bokeh { // -preset N: start with preset scene N (0..3; Down cycles them). // -slow: start with the full (not the fast) bokeh geometry shader (Up toggles it). let options = AppOptions.UnormBackBuffer; - let preset = 0; + let preset: int = 0; let slow = false; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); diff --git a/examples/calibrated_timestamps.ts b/examples/calibrated_timestamps.ts index 6d6b59f..43ec284 100644 --- a/examples/calibrated_timestamps.ts +++ b/examples/calibrated_timestamps.ts @@ -748,7 +748,7 @@ namespace CalibratedTimestampsSample { // and the times (see checkFrame). let options = AppOptions.None; let withUI = true; - let objectIndex = 0; + let objectIndex: int = 0; let bloom = true; let displaySkybox = true; for (let i = 1; i < argc; i++) { diff --git a/examples/collision.ts b/examples/collision.ts index bca547a..e2c8291 100644 --- a/examples/collision.ts +++ b/examples/collision.ts @@ -1151,7 +1151,7 @@ namespace Collision { // -group <1..4>: the group looked at first. -time : the objects frozen at that time. // -help: start with the help screen. let options = AppOptions.UnormBackBuffer; - let group = 0; + let group: int = 0; let fixedTime = -1.0; let showHelp = false; for (let i = 1; i < argc; i++) { diff --git a/examples/dynamic_multisample_rasterization.ts b/examples/dynamic_multisample_rasterization.ts index 56a5522..ae13a1c 100644 --- a/examples/dynamic_multisample_rasterization.ts +++ b/examples/dynamic_multisample_rasterization.ts @@ -423,7 +423,7 @@ namespace DynamicMultisampleRasterization { let indices: int[] = []; let firstIndex: int[] = []; let baseVertex: int[] = []; - let meshCount = 0; + let meshCount: int = 0; for (let p = 0; p < primitiveCount; p++) { const vertexCount = scene.getVertexCount(p); const indexCount = scene.getIndexCount(p); diff --git a/examples/dynamic_primitive_clipping.ts b/examples/dynamic_primitive_clipping.ts index da8c739..004d1bf 100644 --- a/examples/dynamic_primitive_clipping.ts +++ b/examples/dynamic_primitive_clipping.ts @@ -423,8 +423,8 @@ namespace DynamicPrimitiveClipping { // object 1 or 2. let options = AppOptions.None; let withUI = true; - let objectIndex = 0; - let visualization = 0; + let objectIndex: int = 0; + let visualization: int = 0; let clipping = true; let depthClip = false; let only = 0; diff --git a/examples/dynamic_rendering_local_read.ts b/examples/dynamic_rendering_local_read.ts index 6cd006a..d6c84c8 100644 --- a/examples/dynamic_rendering_local_read.ts +++ b/examples/dynamic_rendering_local_read.ts @@ -228,7 +228,7 @@ namespace DynamicRenderingLocalRead { let indices: int[] = []; let firstIndex: int[] = []; let baseVertex: int[] = []; - let meshCount = 0; + let meshCount: int = 0; for (let p = 0; p < primitiveCount; p++) { const vertexCount = model.getVertexCount(p); const indexCount = model.getIndexCount(p); diff --git a/examples/fast_block_compress.ts b/examples/fast_block_compress.ts index 06685d5..f82350a 100644 --- a/examples/fast_block_compress.ts +++ b/examples/fast_block_compress.ts @@ -835,9 +835,9 @@ namespace FastBlockCompress { // The back buffers are UNORM, as the sample's (B8G8R8A8_UNORM): values shown as stored. let options = AppOptions.UnormBackBuffer; let withUI = true; - let image = 0; - let method = 0; - let mip = 0; + let image: int = 0; + let method: int = 0; + let mip: int = 0; let fullscreen = false; let original = false; let highlight = false; diff --git a/examples/fragment_shader_barycentric.ts b/examples/fragment_shader_barycentric.ts index df94eee..ff5ba76 100644 --- a/examples/fragment_shader_barycentric.ts +++ b/examples/fragment_shader_barycentric.ts @@ -406,7 +406,7 @@ namespace FragmentShaderBarycentric { // -effect <0..4>: the effect selected at start. let options = AppOptions.None; let withUI = true; - let effect = 0; + let effect: int = 0; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); if (arg == "-debug") { diff --git a/examples/fragment_shading_rate_dynamic.ts b/examples/fragment_shading_rate_dynamic.ts index 15bb035..09de7d2 100644 --- a/examples/fragment_shading_rate_dynamic.ts +++ b/examples/fragment_shading_rate_dynamic.ts @@ -409,8 +409,8 @@ namespace FragmentShadingRateDynamic { // The compute shader's parameters: the frequency (reduced size) and shading rate images' // sizes, the largest rate, the rate count, the rates. - let maxRateX = 0; - let maxRateY = 0; + let maxRateX: int = 0; + let maxRateY: int = 0; for (let r = 0; r < this.rateCount; r++) { maxRateX = Math.max(maxRateX, this.rates[r * 2]); maxRateY = Math.max(maxRateY, this.rates[r * 2 + 1]); @@ -686,8 +686,8 @@ namespace FragmentShadingRateDynamic { // everywhere. -nosky: without the sky sphere. let options = AppOptions.None; let withUI = true; - let visualize = 0; - let ratio = 4; + let visualize: int = 0; + let ratio: int = 4; let noAttachment = false; let noSky = false; for (let i = 1; i < argc; i++) { diff --git a/examples/graphics_pipeline_library.ts b/examples/graphics_pipeline_library.ts index 80a0a89..8e1e217 100644 --- a/examples/graphics_pipeline_library.ts +++ b/examples/graphics_pipeline_library.ts @@ -432,8 +432,8 @@ namespace GraphicsPipelineLibrary { // -benchmark: 1/60 second per frame (as vulkan_samples' --benchmark). let options = AppOptions.None; let withUI = true; - let pipelines = 1; - let seed = -1; + let pipelines: int = 1; + let seed: int = -1; let benchmark = false; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); diff --git a/examples/hdr.ts b/examples/hdr.ts index 977209c..95deb1c 100644 --- a/examples/hdr.ts +++ b/examples/hdr.ts @@ -552,7 +552,7 @@ namespace Hdr { // -object <0..2>, -exposure , -nobloom, -noskybox: the settings' initial values. let options = AppOptions.None; let withUI = true; - let objectIndex = 0; + let objectIndex: int = 0; let exposure = 1.0; let bloom = true; let displaySkybox = true; diff --git a/examples/mesh_shader_culling.ts b/examples/mesh_shader_culling.ts index 733b37f..489b34b 100644 --- a/examples/mesh_shader_culling.ts +++ b/examples/mesh_shader_culling.ts @@ -250,7 +250,7 @@ namespace MeshShaderCulling { let options = AppOptions.None; let withUI = true; let cullRadius = 1.0; - let densityLevel = 2; + let densityLevel: int = 2; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); if (arg == "-debug") { diff --git a/examples/multi_draw_indirect.ts b/examples/multi_draw_indirect.ts index be557c3..5b99a27 100644 --- a/examples/multi_draw_indirect.ts +++ b/examples/multi_draw_indirect.ts @@ -692,7 +692,7 @@ namespace MultiDrawIndirect { // -freeze: culling frozen. let options = AppOptions.None; let withUI = true; - let renderMode = RENDER_GPU; + let renderMode: int = RENDER_GPU; let enableMdi = true; let freezeCull = false; for (let i = 1; i < argc; i++) { diff --git a/examples/multithreading.ts b/examples/multithreading.ts index 1590a0d..a3da66a 100644 --- a/examples/multithreading.ts +++ b/examples/multithreading.ts @@ -502,7 +502,7 @@ namespace Multithreading { if (app.readBackBufferRGBA8(Ref(pixels[0]), pixels.length) == 0) { return "cannot read the back buffer"; } - let sum = 0; + let sum: number = 0; let lit = 0; for (let i = 0; i < width * height; i++) { const p = pixels[i]; diff --git a/examples/oit_depth_peeling.ts b/examples/oit_depth_peeling.ts index 40ca2e9..7728e48 100644 --- a/examples/oit_depth_peeling.ts +++ b/examples/oit_depth_peeling.ts @@ -519,7 +519,7 @@ namespace OitDepthPeeling { // -rotate: start with the camera's auto-rotation on. let options = AppOptions.None; let withUI = true; - let frontLayer = 0; + let frontLayer: int = 0; let backLayer = LAYER_MAX_COUNT - 1; let alpha = 0.5; let grayscale = 0.3; diff --git a/examples/oit_linked_lists.ts b/examples/oit_linked_lists.ts index 0a7bb05..34a737e 100644 --- a/examples/oit_linked_lists.ts +++ b/examples/oit_linked_lists.ts @@ -567,7 +567,7 @@ namespace OitLinkedLists { let options = AppOptions.None; let withUI = true; let sortFragments = true; - let sortedFragmentCount = SORTED_FRAGMENT_MAX_COUNT; + let sortedFragmentCount: int = SORTED_FRAGMENT_MAX_COUNT; let cameraAutoRotation = false; let backgroundGrayscale = 0.3; let benchmark = false; diff --git a/examples/ray_tracing_extended.ts b/examples/ray_tracing_extended.ts index 1d81fa5..e7734f8 100644 --- a/examples/ray_tracing_extended.ts +++ b/examples/ray_tracing_extended.ts @@ -787,7 +787,7 @@ namespace RayTracingExtended { // (as in the sample, 5 and 6 show the hit's texture: its ray generation shader stops before // their shadow and AO output). let options = AppOptions.RayTracing; - let renderMode = RENDER_DEFAULT; + let renderMode: int = RENDER_DEFAULT; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); if (arg == "-debug") { diff --git a/examples/ray_tracing_invocation_reorder.ts b/examples/ray_tracing_invocation_reorder.ts index 45e399d..7c92611 100644 --- a/examples/ray_tracing_invocation_reorder.ts +++ b/examples/ray_tracing_invocation_reorder.ts @@ -859,7 +859,7 @@ namespace RayTracingInvocationReorder { // -noser, -nohint: SER, its coherence hint off at start. // -noui: without the settings window. let options = AppOptions.RayTracing; - let renderMode = RENDER_DEFAULT; + let renderMode: int = RENDER_DEFAULT; let ser = true; let hint = true; let withUI = true; diff --git a/examples/ray_tracing_position_fetch.ts b/examples/ray_tracing_position_fetch.ts index 089d3ba..3c143a5 100644 --- a/examples/ray_tracing_position_fetch.ts +++ b/examples/ray_tracing_position_fetch.ts @@ -418,7 +418,7 @@ namespace RayTracingPositionFetch { // -mode : display mode 0 (geometric normal) or 1 (vertex position). let options = AppOptions.RayTracing; let withUI = true; - let displayMode = 0; + let displayMode: int = 0; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); if (arg == "-debug") { diff --git a/examples/shader_object.ts b/examples/shader_object.ts index ad611dc..aa10803 100644 --- a/examples/shader_object.ts +++ b/examples/shader_object.ts @@ -602,7 +602,7 @@ namespace ShaderObjectSample { } let vs = this.skyboxVS; let ps = this.skyboxPS; - let gs = -1; + let gs: int = -1; let cullMode = CullMode.None; let depthWrite = 1; if (combo == COMBO_SKYBOX) { diff --git a/examples/simple_bezier.ts b/examples/simple_bezier.ts index eca0e84..d9f8d35 100644 --- a/examples/simple_bezier.ts +++ b/examples/simple_bezier.ts @@ -569,7 +569,7 @@ namespace SimpleBezier { // steps, the help screen). let options = AppOptions.None; let wireframe = false; - let partitionMode = PARTITION_INTEGER; + let partitionMode: int = PARTITION_INTEGER; let subdivs = DEFAULT_SUBDIVS; let rotateSteps = 0; let showHelp = false; diff --git a/examples/simple_pbr.ts b/examples/simple_pbr.ts index 97dac14..62be9b2 100644 --- a/examples/simple_pbr.ts +++ b/examples/simple_pbr.ts @@ -224,7 +224,7 @@ namespace SimplePbr { const i1 = pairs[e * 2 + 1]; const a = Math.max(i0, i1); const b = Math.min(i0, i1); - let found = -1; + let found: int = -1; for (let k = 0; k < edgeA.length; k++) { if (edgeA[k] == a && edgeB[k] == b) { found = edgeMid[k]; diff --git a/examples/sparse_image.ts b/examples/sparse_image.ts index b930a37..732ece5 100644 --- a/examples/sparse_image.ts +++ b/examples/sparse_image.ts @@ -124,7 +124,7 @@ namespace SparseImage { // The first position whose value isn't below value. function lowerBound(values: int[], value: int): int { - let low = 0; + let low: int = 0; let high = values.length; while (low < high) { const middle = Math.floor((low + high) / 2); @@ -902,7 +902,7 @@ namespace SparseImage { reallocate.push(false); } let anyToReallocate = false; - let sectorsToReallocate = 0; + let sectorsToReallocate: int = 0; let kept: int[] = []; for (let i = 0; i < this.sectorList.length; i++) { diff --git a/examples/texture_compression_basisu.ts b/examples/texture_compression_basisu.ts index a8c477b..b85c2da 100644 --- a/examples/texture_compression_basisu.ts +++ b/examples/texture_compression_basisu.ts @@ -507,8 +507,8 @@ namespace TextureCompressionBasisu { // (an index into the device's list), both transcoded at start. let options = AppOptions.None; let withUI = true; - let image = 0; - let target = 0; + let image: int = 0; + let target: int = 0; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); if (arg == "-debug") { diff --git a/examples/texture_compression_comparison.ts b/examples/texture_compression_comparison.ts index 33a06dd..aed614b 100644 --- a/examples/texture_compression_comparison.ts +++ b/examples/texture_compression_comparison.ts @@ -635,7 +635,7 @@ namespace TextureCompressionComparison { // -format : 0 RGBA 32 (the default), 1 BC7, 2 BC3, 3 ASTC 4x4, 4 ETC2. let options = AppOptions.None; let withUI = true; - let format = 0; + let format: int = 0; for (let i = 1; i < argc; i++) { const arg = Donut_GetArg(argv, i); if (arg == "-debug") { diff --git a/examples/texture_mipmap_generation.ts b/examples/texture_mipmap_generation.ts index bf6c36b..84f685e 100644 --- a/examples/texture_mipmap_generation.ts +++ b/examples/texture_mipmap_generation.ts @@ -494,7 +494,7 @@ namespace TextureMipmapGeneration { // -lodbias : the level of detail bias. -rotate: the scene rotating. let options = AppOptions.None; let withUI = true; - let samplerIndex = 2; + let samplerIndex: int = 2; let lodBias = 0.0; let rotateScene = false; for (let i = 1; i < argc; i++) { diff --git a/examples/timestamp_queries.ts b/examples/timestamp_queries.ts index 1d78e56..59ec918 100644 --- a/examples/timestamp_queries.ts +++ b/examples/timestamp_queries.ts @@ -640,7 +640,7 @@ namespace TimestampQueries { // -object <0..2>, -exposure , -nobloom, -noskybox: the settings' initial values. let options = AppOptions.None; let withUI = true; - let objectIndex = 0; + let objectIndex: int = 0; let exposure = 1.0; let bloom = true; let displaySkybox = true; diff --git a/run_jit.bat b/run_jit.bat index 1d27e32..ac53a84 100644 --- a/run_jit.bat +++ b/run_jit.bat @@ -1,9 +1,11 @@ -@rem Runs an example under the JIT (run_jit.bat examples/.ts [args]), against %D%: donut_interop.dll, +@rem Runs an example under the JIT (run_jit.bat examples/.ts [-- args]), against %D%: donut_interop.dll, @rem and input_pass.dll (with the default library it links) for the shared InputPass the example @rem imports. From the repo root, where no ../core/input_pass.dll is, so the import reads @rem core/input_pass.ts for its declarations. @pushd %~dp0 rem set D=build-release-dlss/bin set D=build/bin -tslang --shared-libs=%D%/donut_interop.dll %* +@rem --jit-cache=false: tslang pre-alpha93's JIT cache crashes (0xC0000005) in a run that compiles +@rem two or more modules (TypeScriptCompiler#548): an example's first two runs, with its imports. +tslang --jit-cache=false --shared-libs=%D%/donut_interop.dll %* @popd