diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..241004e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# git apply needs the patches as they are stored (LF): with core.autocrlf, a checkout would +# give them CRLF, and one with an empty context line is then "corrupt" and skipped. +*.patch text eol=lf diff --git a/CMakeLists.txt b/CMakeLists.txt index 452f605..d062404 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -549,6 +549,18 @@ function(add_tslang_android_app name media) if (TARGET donut_shaders) add_dependencies(${name}_apk donut_shaders) endif() + # What the executable is made to depend on after this (the copies of the media of the samples' + # checkouts: _media and the like), the APK packages too, and `tools/android.py build` + # builds APKs, not executables: taken at the end of the file, when all of it is known. (A + # deferred call's arguments are evaluated when it runs, hence the EVAL.) + cmake_language(EVAL CODE "cmake_language(DEFER CALL add_tslang_apk_dependencies [[${name}]])") +endfunction() + +function(add_tslang_apk_dependencies name) + get_target_property(dependencies ${name} MANUALLY_ADDED_DEPENDENCIES) + if (dependencies) + add_dependencies(${name}_apk ${dependencies}) + endif() endfunction() # The files the examples' .ts files compile in, which their objects have to be rebuilt after: a @@ -2639,6 +2651,19 @@ donut_compile_shaders_all_platforms( SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/collision.hlsl OUTPUT_BASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/shaders/collision ) +# DirectXMath is the Windows SDK's; on Android it is fetched at configure time (DIRECTXMATH_FETCH_TAG; +# headers only, not its CMake project), with core/sal/sal.h for the annotations it uses. +if (ANDROID) + set(DIRECTXMATH_FETCH_TAG "jun2026" CACHE STRING "Git tag of DirectXMath, which collision uses on Android") + FetchContent_Declare(directxmath + GIT_REPOSITORY https://github.com/microsoft/DirectXMath.git + GIT_TAG ${DIRECTXMATH_FETCH_TAG} + GIT_SHALLOW TRUE + SOURCE_SUBDIR Inc) + FetchContent_MakeAvailable(directxmath) + set_source_files_properties(core/directx_collision.cpp PROPERTIES + INCLUDE_DIRECTORIES "${directxmath_SOURCE_DIR}/Inc;${CMAKE_CURRENT_SOURCE_DIR}/core/sal") +endif() add_tslang_example(collision core/directx_collision.cpp MEDIA fonts) # Port of NVIDIA's DXR tutorial 14 (Refit, github.com/NVIDIAGameWorks/DxrTutorials): three @@ -2901,24 +2926,27 @@ endfunction() # over a scene of PBRT models (a house, cars, a dragon, a spaceship: the sample's parser, in # core/pbrt) and procedural grass a compute shader regenerates every frame; a specular path tracer # makes the G-buffer. Its assets (~140 MB) are the sample's, from DIRECTX_GRAPHICS_SAMPLES_DIR. -# Ray tracing pipelines: D3D12 or Vulkan. -file(GLOB DENOISED_RTAO_SHADER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/denoised_rtao/*) -donut_compile_shaders( - TARGET denoised_rtao_shaders - PROJECT_NAME "Denoised RTAO" - CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/shaders/denoised_rtao.cfg - SOURCES ${DENOISED_RTAO_SHADER_SOURCES} - DXIL ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/shaders/denoised_rtao/dxil - SPIRV_DXC ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/shaders/denoised_rtao/spirv - SHADERMAKE_OPTIONS_SPIRV "--vulkanMemoryLayout dx" -) -add_tslang_example(denoised_rtao core/directx_math.ts core/pbrt_scene.ts core/denoised_rtao.cpp core/pbrt/PBRTParser.cpp core/pbrt/PlyParser.cpp - MEDIA denoised_rtao) -add_dxgs_media_directory(denoised_rtao denoised_rtao - Samples/Desktop/D3D12Raytracing/src/D3D12RaytracingRealTimeDenoisedAmbientOcclusion/Assets) -add_tslang_example_test(denoised_rtao) -add_tslang_example_test(denoised_rtao SUFFIX raw ARGS -raw) -add_tslang_example_test(denoised_rtao SUFFIX shaded ARGS -shaded) +# Ray tracing pipelines: D3D12 or Vulkan. Windows only: the textures are loaded through WIC, and the +# PBRT parser takes its definitions from windows.h. +if (WIN32) + file(GLOB DENOISED_RTAO_SHADER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/denoised_rtao/*) + donut_compile_shaders( + TARGET denoised_rtao_shaders + PROJECT_NAME "Denoised RTAO" + CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/shaders/denoised_rtao.cfg + SOURCES ${DENOISED_RTAO_SHADER_SOURCES} + DXIL ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/shaders/denoised_rtao/dxil + SPIRV_DXC ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/shaders/denoised_rtao/spirv + SHADERMAKE_OPTIONS_SPIRV "--vulkanMemoryLayout dx" + ) + add_tslang_example(denoised_rtao core/directx_math.ts core/pbrt_scene.ts core/denoised_rtao.cpp core/pbrt/PBRTParser.cpp core/pbrt/PlyParser.cpp + MEDIA denoised_rtao) + add_dxgs_media_directory(denoised_rtao denoised_rtao + Samples/Desktop/D3D12Raytracing/src/D3D12RaytracingRealTimeDenoisedAmbientOcclusion/Assets) + add_tslang_example_test(denoised_rtao) + add_tslang_example_test(denoised_rtao SUFFIX raw ARGS -raw) + add_tslang_example_test(denoised_rtao SUFFIX shaded ARGS -shaded) +endif() # Port of DirectX-Graphics-Samples' D3D12Multithreading: a room of 1025 draws lit by three moving # spotlights, the first casting shadows, its shadow pass and scene pass recorded by three worker diff --git a/core/fbc_cpu.cpp b/core/fbc_cpu.cpp index 9deea15..9c5fd80 100644 --- a/core/fbc_cpu.cpp +++ b/core/fbc_cpu.cpp @@ -134,10 +134,10 @@ namespace #define INSET_BC5_BBOX() \ static const int INSET_ALPHA_SHIFT = 5; \ - __declspec(align(16)) static const uint16_t s_insetNormal3DcRound[8] = { ((1<<(INSET_ALPHA_SHIFT-1))-1), ((1<<(INSET_ALPHA_SHIFT-1))-1), 0, 0, 0, 0, 0, 0 }; \ - __declspec(align(16)) static const uint16_t s_insetNormal3DcMask[8] = { 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; \ - __declspec(align(16)) static const uint16_t s_insetNormal3DcShiftUp[8] = { 1 << INSET_ALPHA_SHIFT, 1 << INSET_ALPHA_SHIFT, 1, 1, 1, 1, 1, 1 }; \ - __declspec(align(16)) static const uint16_t s_insetNormal3DcShiftDown[8] = { 1 << (16 - INSET_ALPHA_SHIFT), 1 << (16 - INSET_ALPHA_SHIFT), 0, 0, 0, 0, 0, 0 }; \ + alignas(16) static const uint16_t s_insetNormal3DcRound[8] = { ((1<<(INSET_ALPHA_SHIFT-1))-1), ((1<<(INSET_ALPHA_SHIFT-1))-1), 0, 0, 0, 0, 0, 0 }; \ + alignas(16) static const uint16_t s_insetNormal3DcMask[8] = { 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; \ + alignas(16) static const uint16_t s_insetNormal3DcShiftUp[8] = { 1 << INSET_ALPHA_SHIFT, 1 << INSET_ALPHA_SHIFT, 1, 1, 1, 1, 1, 1 }; \ + alignas(16) static const uint16_t s_insetNormal3DcShiftDown[8] = { 1 << (16 - INSET_ALPHA_SHIFT), 1 << (16 - INSET_ALPHA_SHIFT), 0, 0, 0, 0, 0, 0 }; \ \ const __m128i zero = _mm_setzero_si128(); \ minColor = _mm_unpacklo_epi8( minColor, zero ); \ @@ -163,10 +163,10 @@ namespace maxColor = _mm_packus_epi16( maxColor, maxColor ); #define EMIT_COLOR_INDICES() \ - __declspec(align(16)) static const uint8_t s_colorMask[16] = { 0xF8, 0xFC, 0xF8, 0, 0, 0, 0, 0, 0xF8, 0xFC, 0xF8, 0, 0, 0, 0, 0 }; \ - __declspec(align(16)) static const uint16_t s_word_div3[8] = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 }; \ - __declspec(align(16)) static const uint16_t s_word_1[8] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; \ - __declspec(align(16)) static const uint16_t s_word_2[8] = { 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2 }; \ + alignas(16) static const uint8_t s_colorMask[16] = { 0xF8, 0xFC, 0xF8, 0, 0, 0, 0, 0, 0xF8, 0xFC, 0xF8, 0, 0, 0, 0, 0 }; \ + alignas(16) static const uint16_t s_word_div3[8] = { (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1, (1<<16)/3+1 }; \ + alignas(16) static const uint16_t s_word_1[8] = { 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1 }; \ + alignas(16) static const uint16_t s_word_2[8] = { 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2 }; \ \ maxColor = _mm_and_si128( maxColor, reinterpret_cast(s_colorMask)[0] ); \ maxColor = _mm_unpacklo_epi8( maxColor, zero ); \ @@ -365,21 +365,21 @@ namespace result = _mm_or_si128(result, t2); #define EMIT_ALPHA_INDICES_VARS() \ - __declspec(align(16)) static const uint8_t s_byte_1[16] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; \ - __declspec(align(16)) static const uint8_t s_byte_2[16] = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }; \ - __declspec(align(16)) static const uint8_t s_byte_7[16] = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }; \ - __declspec(align(16)) static const uint16_t s_word_div7[8] = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 }; \ - __declspec(align(16)) static const uint16_t s_word_div14[8] = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 }; \ - __declspec(align(16)) static const uint16_t s_word_scaleA[8] = { 6, 6, 5, 5, 4, 4, 0, 0 }; \ - __declspec(align(16)) static const uint16_t s_word_scaleB[8] = { 1, 1, 2, 2, 3, 3, 0, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask0[4] = { 7<<0, 0, 7<<0, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask1[4] = { 7<<3, 0, 7<<3, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask2[4] = { 7<<6, 0, 7<<6, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask3[4] = { 7<<9, 0, 7<<9, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask4[4] = { 7<<12, 0, 7<<12, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask5[4] = { 7<<15, 0, 7<<15, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask6[4] = { 7<<18, 0, 7<<18, 0 }; \ - __declspec(align(16)) static const uint32_t s_alphaMask7[4] = { 7<<21, 0, 7<<21, 0 }; \ + alignas(16) static const uint8_t s_byte_1[16] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; \ + alignas(16) static const uint8_t s_byte_2[16] = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }; \ + alignas(16) static const uint8_t s_byte_7[16] = { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }; \ + alignas(16) static const uint16_t s_word_div7[8] = { (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1, (1<<16)/7+1 }; \ + alignas(16) static const uint16_t s_word_div14[8] = { (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1, (1<<16)/14+1 }; \ + alignas(16) static const uint16_t s_word_scaleA[8] = { 6, 6, 5, 5, 4, 4, 0, 0 }; \ + alignas(16) static const uint16_t s_word_scaleB[8] = { 1, 1, 2, 2, 3, 3, 0, 0 }; \ + alignas(16) static const uint32_t s_alphaMask0[4] = { 7<<0, 0, 7<<0, 0 }; \ + alignas(16) static const uint32_t s_alphaMask1[4] = { 7<<3, 0, 7<<3, 0 }; \ + alignas(16) static const uint32_t s_alphaMask2[4] = { 7<<6, 0, 7<<6, 0 }; \ + alignas(16) static const uint32_t s_alphaMask3[4] = { 7<<9, 0, 7<<9, 0 }; \ + alignas(16) static const uint32_t s_alphaMask4[4] = { 7<<12, 0, 7<<12, 0 }; \ + alignas(16) static const uint32_t s_alphaMask5[4] = { 7<<15, 0, 7<<15, 0 }; \ + alignas(16) static const uint32_t s_alphaMask6[4] = { 7<<18, 0, 7<<18, 0 }; \ + alignas(16) static const uint32_t s_alphaMask7[4] = { 7<<21, 0, 7<<21, 0 }; \ __m128i maxa, mina, mid, mid_div_14, ab1, ab2, ab3, ab4, ab5, ab6, ab7, resulta; #define EMIT_ALPHA_INDICES(alpha) \ @@ -592,7 +592,7 @@ namespace void CompressBC5U(const Image& src, Image& dst) { - __declspec(align(16)) static const uint32_t s_mask[4] = { 0xff, 0xff, 0xff, 0xff }; + alignas(16) static const uint32_t s_mask[4] = { 0xff, 0xff, 0xff, 0xff }; const uint8_t* pSource = src.pixels; uint8_t* pDestination = dst.pixels; diff --git a/core/fbc_cpu_compat.h b/core/fbc_cpu_compat.h index e50c241..219cc64 100644 --- a/core/fbc_cpu_compat.h +++ b/core/fbc_cpu_compat.h @@ -1,7 +1,7 @@ // What the Xbox ATG FastBlockCompress sample's CPU compressor (fbc_cpu.cpp, fbc_cpu.h) took from the // sample's precompiled header: the few DXGI / D3D12 / COM definitions it uses, with the values of // the Windows SDK, without Windows headers (the example builds for Android too), plus aligned -// allocation and SSE2. +// allocation, SSE2, and (the compressor without SSE2: ARM) memcpy_s. #pragma once @@ -79,6 +79,17 @@ inline void FbcAlignedFree(void* p) #endif } +#ifndef _WIN32 +// The CRT's bounds-checked copy, which the compressor's C fallback uses. +inline int memcpy_s(void* dest, size_t destSize, const void* src, size_t count) +{ + if (count > destSize) + return 34; // ERANGE + memcpy(dest, src, count); + return 0; +} +#endif + #define _aligned_malloc FbcAlignedMalloc struct aligned_deleter { void operator()(void* p) { FbcAlignedFree(p); } }; diff --git a/core/sal/sal.h b/core/sal/sal.h new file mode 100644 index 0000000..6141572 --- /dev/null +++ b/core/sal/sal.h @@ -0,0 +1,16 @@ +// The Microsoft source-code annotations DirectXMath and DirectXCollision use, as nothing: DirectXMath +// includes "sal.h", which only the Windows SDK has. Its README asks non-Windows builds to provide +// one; this is on core/directx_collision.cpp's include path on Android only (see CMakeLists.txt). + +#pragma once + +#define _Analysis_assume_(expr) +#define _In_ +#define _In_reads_(size) +#define _In_reads_bytes_(size) +#define _Out_ +#define _Out_opt_ +#define _Out_writes_(size) +#define _Out_writes_bytes_(size) +#define _Success_(expr) +#define _Use_decl_annotations_ diff --git a/examples/fast_block_compress.ts b/examples/fast_block_compress.ts index f82350a..27c0599 100644 --- a/examples/fast_block_compress.ts +++ b/examples/fast_block_compress.ts @@ -12,7 +12,9 @@ namespace FastBlockCompress { // interior), alpha (1024x1024 RGBA: the recycle bin and book with alpha), normal (1024x1024 RG: // normal map texture). Each comes with offline BC and BC7 versions, named after it. const IMAGE_NAMES = ["opaque_1024", "opaque_512", "alpha", "normal"]; + // Their files' extensions, as the sample has them (Android's file names are case-sensitive). const IMAGE_EXTENSIONS = [".DDS", ".dds", ".DDS", ".dds"]; + const IMAGE_OFFLINE_EXTENSIONS = [".DDS", ".DDS", ".DDS", ".DDS"]; const IMAGE_BC7_EXTENSIONS = [".dds", ".dds", ".dds", ".dds"]; const IMAGE_FORMATS = [Format.BC1_UNORM, Format.BC1_UNORM, Format.BC3_UNORM, Format.BC5_UNORM]; @@ -512,7 +514,7 @@ namespace FastBlockCompress { } const bcName = formatName(image.format).toLowerCase(); - const offlineBC = this.app.loadTexture(commandList, MEDIA_DIR + name + "_offline_" + bcName + IMAGE_EXTENSIONS[index], 0); + const offlineBC = this.app.loadTexture(commandList, MEDIA_DIR + name + "_offline_" + bcName + IMAGE_OFFLINE_EXTENSIONS[index], 0); const offlineBC7 = this.app.loadTexture(commandList, MEDIA_DIR + name + "_offline_bc7" + IMAGE_BC7_EXTENSIONS[index], 0); if (!offlineBC || !offlineBC7) { return null;