From 3248914ca91345c905f1d706eacb6d1663df954f Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 25 Feb 2026 16:03:24 +0800 Subject: [PATCH 1/4] Add linux arm64 support --- .github/workflows/build.yml | 24 ++++++++++++++---- .github/workflows/dist.yml | 18 ++++++++------ 3rdparty/sx/CMakeLists.txt | 49 ------------------------------------- README.md | 4 +++ 4 files changed, 34 insertions(+), 61 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a0ce6a2d..e11e609c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,7 +6,7 @@ on: '.github/workflows/dist.yml' jobs: - win64: + win-x64: runs-on: windows-latest steps: - uses: actions/checkout@v6 @@ -19,9 +19,9 @@ jobs: uses: actions/upload-artifact@v6 with: path: ./build/src/Release/axslcc.exe - name: axslcc-win64 - linux: - runs-on: debian-11 # self-hosted on org simdsoft, @halx99 personal machine + name: axslcc-win-x64 + linux-x64: + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v6 - name: build @@ -33,7 +33,21 @@ jobs: uses: actions/upload-artifact@v6 with: path: ./build/src/axslcc - name: axslcc-linux + name: axslcc-linux-x64 + linux-arm64: + runs-on: ubuntu-22.04-arm + steps: + - uses: actions/checkout@v6 + - name: build + shell: pwsh + run: | + cmake -B build -DCMAKE_BUILD_TYPE=Release + cmake --build build --config Release --target axslcc + - name: Upload + uses: actions/upload-artifact@v6 + with: + path: ./build/src/axslcc + name: axslcc-linux-arm64 osx-arm64: runs-on: macos-latest steps: diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index ddffca3c..c8ffacf4 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -57,23 +57,27 @@ jobs: - name: Create packages if: ${{ steps.check_ver.outputs.release_ver != '' }} run: | - curl -L https://github.com/simdsoft/1kiss/releases/download/devtools/d3dcompiler_47.dll -o ./axslcc-win64/d3dcompiler_47.dll - ls -l ./axslcc-win64 + curl -L https://github.com/simdsoft/1kiss/releases/download/devtools/d3dcompiler_47.dll -o ./axslcc-win-x64/d3dcompiler_47.dll + ls -l ./axslcc-win-x64 mkdir -p pkg_dir prefix=axslcc-${{ steps.check_ver.outputs.release_ver }} - ls -l axslcc-linux + ls -l axslcc-linux-x64 + ls -l axslcc-linux-arm64 ls -l axslcc-osx-x64 ls -l axslcc-osx-arm64 - sudo chmod u+x ./axslcc-linux/axslcc + sudo chmod u+x ./axslcc-linux-x64/axslcc + sudo chmod u+x ./axslcc-linux-arm64/axslcc sudo chmod u+x ./axslcc-osx-x64/axslcc sudo chmod u+x ./axslcc-osx-arm64/axslcc - ls -l axslcc-linux + ls -l axslcc-linux-x64 + ls -l axslcc-linux-arm64 ls -l axslcc-osx-x64 ls -l axslcc-osx-arm64 - tar -czvf ./pkg_dir/$prefix-linux.tar.gz -C ./axslcc-linux axslcc + tar -czvf ./pkg_dir/$prefix-linux-x64.tar.gz -C ./axslcc-linux-x64 axslcc + tar -czvf ./pkg_dir/$prefix-linux-arm64.tar.gz -C ./axslcc-linux-arm64 axslcc tar -czvf ./pkg_dir/$prefix-osx-x64.tar.gz -C ./axslcc-osx-x64 axslcc tar -czvf ./pkg_dir/$prefix-osx-arm64.tar.gz -C ./axslcc-osx-arm64 axslcc - sh -c "cd ./axslcc-win64; zip ../pkg_dir/$prefix-win64.zip axslcc.exe d3dcompiler_47.dll" + sh -c "cd ./axslcc-win-x64; zip ../pkg_dir/$prefix-win-x64.zip axslcc.exe d3dcompiler_47.dll" - name: Publish to github release page if: ${{ steps.check_ver.outputs.release_ver != '' }} uses: softprops/action-gh-release@v2 diff --git a/3rdparty/sx/CMakeLists.txt b/3rdparty/sx/CMakeLists.txt index dde1fffe..9848a0cc 100644 --- a/3rdparty/sx/CMakeLists.txt +++ b/3rdparty/sx/CMakeLists.txt @@ -99,55 +99,6 @@ if (EMSCRIPTEN) list(REMOVE_ITEM SOURCE_FILES include/sx/fiber.h) endif() -#################################################################################################### -# Assembly files for fcontext -if (APPLE) - # Apple comboned, include based on arch - set(CPU_ARCH "combined") - set(ASM_EXT "all_macho_gas.S") -elseif (ANDROID) - # Android (Arm/x86_64/Arm64) - if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm") - set(CPU_ARCH "arm") - set(ASM_EXT "aapcs_elf_gas.S") - elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") - set(CPU_ARCH "arm64") - set(ASM_EXT "aapcs_elf_gas.S") - elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686") - set(CPU_ARCH "i386") - set(ASM_EXT "sysv_elf_gas.S") - elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64") - set(CPU_ARCH "x86_64") - set(ASM_EXT "sysv_elf_gas.S") - endif() -elseif (UNIX) - # Unix systems (x86/x64) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(CPU_ARCH "x86_64") - else() - set(CPU_ARCH "i386") - endif() - set(ASM_EXT "sysv_elf_gas.S") -elseif (WIN32) - # Windows (x86/64) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(CPU_ARCH "x86_64") - else() - set(CPU_ARCH "i386") - endif() - set(ASM_EXT "ms_pe_masm.asm") -endif() - -set(ASM_SOURCES "asm/make_${CPU_ARCH}_${ASM_EXT}" - "asm/jump_${CPU_ARCH}_${ASM_EXT}" - "asm/ontop_${CPU_ARCH}_${ASM_EXT}") -set_source_files_properties(${ASM_SOURCES} PROPERTIES COMPILE_DEFINITIONS BOOST_CONTEXT_EXPORT=) - -if (EMSCRIPTEN) - unset(ASM_SOURCES) -endif() -#################################################################################################### - add_definitions(-D__STDC_LIMIT_MACROS) add_definitions(-D__STDC_FORMAT_MACROS) add_definitions(-D__STDC_CONSTANT_MACROS) diff --git a/README.md b/README.md index c9082003..d069d2df 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ It uses [glslang](https://github.com/KhronosGroup/glslang) for parsing GLSL and ## ChangeLog +### 3.5.0 + +- Add support for running on linux-arm64 + ### 3.4.0 - Add support for compiling to multi shader targets with option `--cross-args` From a4012e30dbec846247a6d69eb68dae679b6926c0 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 25 Feb 2026 22:16:14 +0800 Subject: [PATCH 2/4] Update spriv-cross and glslang --- 3rdparty/spirv-cross/CMakeLists.txt | 14 +- 3rdparty/spirv-cross/main.cpp | 4 + 3rdparty/spirv-cross/spirv.h | 4 +- 3rdparty/spirv-cross/spirv.hpp | 2 +- 3rdparty/spirv-cross/spirv_cfg.cpp | 51 ++- 3rdparty/spirv-cross/spirv_cfg.hpp | 2 + 3rdparty/spirv-cross/spirv_common.hpp | 20 +- 3rdparty/spirv-cross/spirv_cross.cpp | 6 +- 3rdparty/spirv-cross/spirv_cross.hpp | 4 +- 3rdparty/spirv-cross/spirv_cross_c.cpp | 4 + 3rdparty/spirv-cross/spirv_cross_c.h | 4 +- .../spirv-cross/spirv_cross_parsed_ir.cpp | 29 +- .../spirv-cross/spirv_cross_parsed_ir.hpp | 19 +- 3rdparty/spirv-cross/spirv_glsl.cpp | 119 ++++--- 3rdparty/spirv-cross/spirv_glsl.hpp | 3 +- 3rdparty/spirv-cross/spirv_hlsl.cpp | 51 ++- 3rdparty/spirv-cross/spirv_hlsl.hpp | 3 + 3rdparty/spirv-cross/spirv_msl.cpp | 297 ++++++++++++++---- 3rdparty/spirv-cross/spirv_msl.hpp | 19 +- 3rdparty/spirv-cross/spirv_parser.cpp | 139 ++++++-- CMakeLists.txt | 10 +- README.md | 6 +- glslang.patch | 68 +--- spirv-cross.patch | 48 +-- 24 files changed, 652 insertions(+), 274 deletions(-) diff --git a/3rdparty/spirv-cross/CMakeLists.txt b/3rdparty/spirv-cross/CMakeLists.txt index 707c9dec..8e5129c8 100644 --- a/3rdparty/spirv-cross/CMakeLists.txt +++ b/3rdparty/spirv-cross/CMakeLists.txt @@ -255,7 +255,7 @@ set(spirv-cross-util-sources ${CMAKE_CURRENT_SOURCE_DIR}/spirv_cross_util.hpp) set(spirv-cross-abi-major 0) -set(spirv-cross-abi-minor 67) +set(spirv-cross-abi-minor 68) set(spirv-cross-abi-patch 0) set(SPIRV_CROSS_VERSION ${spirv-cross-abi-major}.${spirv-cross-abi-minor}.${spirv-cross-abi-patch}) @@ -551,6 +551,14 @@ if (SPIRV_CROSS_CLI) target_link_libraries(spirv-cross-typed-id-test spirv-cross-core) set_target_properties(spirv-cross-typed-id-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + add_executable(spirv-cross-debug-lines-test tests-other/debug-lines.cpp) + target_link_libraries(spirv-cross-debug-lines-test spirv-cross-core) + set_target_properties(spirv-cross-debug-lines-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + + add_executable(spirv-cross-debug-info-test tests-other/debug-info.cpp) + target_link_libraries(spirv-cross-debug-info-test spirv-cross-core) + set_target_properties(spirv-cross-debug-info-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) target_compile_options(spirv-cross-c-api-test PRIVATE -std=c89 -Wall -Wextra) endif() @@ -573,6 +581,10 @@ if (SPIRV_CROSS_CLI) COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_ycbcr_conversion_test_2.spv) add_test(NAME spirv-cross-typed-id-test COMMAND $) + add_test(NAME spirv-cross-debug-lines-test + COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/debug-lines.spv) + add_test(NAME spirv-cross-debug-info-test + COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/debug-info.spv) add_test(NAME spirv-cross-test COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel ${spirv-cross-externals} diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 4442dbff..b48c1c3c 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -744,6 +744,7 @@ struct CLIArguments bool hlsl_enable_16bit_types = false; bool hlsl_flatten_matrix_vertex_input_semantics = false; bool hlsl_preserve_structured_buffers = false; + bool hlsl_user_semantic = false; HLSLBindingFlags hlsl_binding_flags = 0; bool vulkan_semantics = false; bool flatten_multidimensional_arrays = false; @@ -852,6 +853,7 @@ static void print_help_hlsl() "\t[--hlsl-enable-16bit-types]:\n\t\tEnables native use of half/int16_t/uint16_t and ByteAddressBuffer interaction with these types. Requires SM 6.2.\n" "\t[--hlsl-flatten-matrix-vertex-input-semantics]:\n\t\tEmits matrix vertex inputs with input semantics as if they were independent vectors, e.g. TEXCOORD{2,3,4} rather than matrix form TEXCOORD2_{0,1,2}.\n" "\t[--hlsl-preserve-structured-buffers]:\n\t\tEmit SturucturedBuffer rather than ByteAddressBuffer. Requires UserTypeGOOGLE to be emitted. Intended for DXC roundtrips.\n" + "\t[--hlsl-user-semantic]:\n\t\tUses UserSemantic decoration to generate vertex input and output semantics.\n" ); // clang-format on } @@ -1471,6 +1473,7 @@ static string compile_iteration(const CLIArguments &args, std::vector hlsl_opts.enable_16bit_types = args.hlsl_enable_16bit_types; hlsl_opts.flatten_matrix_vertex_input_semantics = args.hlsl_flatten_matrix_vertex_input_semantics; hlsl_opts.preserve_structured_buffers = args.hlsl_preserve_structured_buffers; + hlsl_opts.user_semantic = args.hlsl_user_semantic; hlsl->set_hlsl_options(hlsl_opts); hlsl->set_resource_binding_flags(args.hlsl_binding_flags); if (args.hlsl_base_vertex_index_explicit_binding) @@ -1673,6 +1676,7 @@ static int main_inner(int argc, char *argv[]) cbs.add("--hlsl-flatten-matrix-vertex-input-semantics", [&args](CLIParser &) { args.hlsl_flatten_matrix_vertex_input_semantics = true; }); cbs.add("--hlsl-preserve-structured-buffers", [&args](CLIParser &) { args.hlsl_preserve_structured_buffers = true; }); + cbs.add("--hlsl-user-semantic", [&args](CLIParser &) { args.hlsl_user_semantic = true; }); cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; }); cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; }); cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; }); diff --git a/3rdparty/spirv-cross/spirv.h b/3rdparty/spirv-cross/spirv.h index 7bb01b3e..9f067765 100644 --- a/3rdparty/spirv-cross/spirv.h +++ b/3rdparty/spirv-cross/spirv.h @@ -645,7 +645,7 @@ typedef enum SpvDecoration_ { SpvDecorationConditionalINTEL = 6247, SpvDecorationCacheControlLoadINTEL = 6442, SpvDecorationCacheControlStoreINTEL = 6443, - SpvDecorationSamplerSlot = 7000, // axslcc spec + SpvDecorationSamplerSlot = 7000, // axslcc spec SpvDecorationMax = 0x7fffffff, } SpvDecoration; @@ -3694,7 +3694,7 @@ inline const char* SpvDecorationToString(SpvDecoration value) { case SpvDecorationIndex: return "Index"; case SpvDecorationBinding: return "Binding"; case SpvDecorationDescriptorSet: return "DescriptorSet"; - case SpvDecorationSamplerSlot: return "SamplerSlot"; // axslcc spec + case SpvDecorationSamplerSlot: return "SamplerSlot"; // axslcc spec case SpvDecorationOffset: return "Offset"; case SpvDecorationXfbBuffer: return "XfbBuffer"; case SpvDecorationXfbStride: return "XfbStride"; diff --git a/3rdparty/spirv-cross/spirv.hpp b/3rdparty/spirv-cross/spirv.hpp index 1c0a6735..c3ce94c9 100644 --- a/3rdparty/spirv-cross/spirv.hpp +++ b/3rdparty/spirv-cross/spirv.hpp @@ -641,7 +641,7 @@ enum Decoration { DecorationConditionalINTEL = 6247, DecorationCacheControlLoadINTEL = 6442, DecorationCacheControlStoreINTEL = 6443, - DecorationSamplerSlot = 7000, // axslcc spec + DecorationSamplerSlot = 7000, // axslcc spec DecorationMax = 0x7fffffff, }; diff --git a/3rdparty/spirv-cross/spirv_cfg.cpp b/3rdparty/spirv-cross/spirv_cfg.cpp index c68886d9..ae928a03 100644 --- a/3rdparty/spirv-cross/spirv_cfg.cpp +++ b/3rdparty/spirv-cross/spirv_cfg.cpp @@ -59,20 +59,26 @@ void CFG::build_immediate_dominators() for (auto i = post_order.size(); i; i--) { uint32_t block = post_order[i - 1]; - auto &pred = preceding_edges[block]; - if (pred.empty()) // This is for the entry block, but we've already set up the dominators. - continue; - for (auto &edge : pred) + const auto resolve_preds = [&](const SmallVector &pred) { - if (immediate_dominators[block]) + if (pred.empty()) // This is for the entry block, but we've already set up the dominators. + return; + + for (auto &edge : pred) { - assert(immediate_dominators[edge]); - immediate_dominators[block] = find_common_dominator(immediate_dominators[block], edge); + if (immediate_dominators[block]) + { + assert(immediate_dominators[edge]); + immediate_dominators[block] = find_common_dominator(immediate_dominators[block], edge); + } + else + immediate_dominators[block] = edge; } - else - immediate_dominators[block] = edge; - } + }; + + resolve_preds(preceding_edges[block]); + resolve_preds(virtual_dominance_preceding_edges[block]); } } @@ -193,6 +199,13 @@ void CFG::post_order_visit_resolve(uint32_t block_id) if (block.merge == SPIRBlock::MergeLoop && !is_back_edge(block.merge_block)) add_branch(block_id, block.merge_block); + // Similar case as do/while loops, but expressed in a different form. + // if (true) { foo = 1; } else { return/unreachable/kill/blah; } access(foo); + // Only consider this branch when computing dominance to avoid breaking other analysis like + // parameter preservation. + if (block.merge == SPIRBlock::MergeSelection && !is_back_edge(block.next_block)) + add_virtual_dominance_branch(block_id, block.next_block); + // First visit our branch targets. switch (block.terminator) { @@ -289,18 +302,26 @@ void CFG::build_post_order_visit_order() post_order_visit_entry(block); } +static void add_unique(SmallVector &l, uint32_t value) +{ + auto itr = find(begin(l), end(l), value); + if (itr == end(l)) + l.push_back(value); +} + void CFG::add_branch(uint32_t from, uint32_t to) { assert(from && to); - const auto add_unique = [](SmallVector &l, uint32_t value) { - auto itr = find(begin(l), end(l), value); - if (itr == end(l)) - l.push_back(value); - }; add_unique(preceding_edges[to], from); add_unique(succeeding_edges[from], to); } +void CFG::add_virtual_dominance_branch(uint32_t from, uint32_t to) +{ + assert(from && to); + add_unique(virtual_dominance_preceding_edges[to], from); +} + uint32_t CFG::find_loop_dominator(uint32_t block_id) const { while (block_id != SPIRBlock::NoDominator) diff --git a/3rdparty/spirv-cross/spirv_cfg.hpp b/3rdparty/spirv-cross/spirv_cfg.hpp index 1c21ea07..9e6141bb 100644 --- a/3rdparty/spirv-cross/spirv_cfg.hpp +++ b/3rdparty/spirv-cross/spirv_cfg.hpp @@ -122,6 +122,7 @@ class CFG Compiler &compiler; const SPIRFunction &func; std::unordered_map> preceding_edges; + std::unordered_map> virtual_dominance_preceding_edges; std::unordered_map> succeeding_edges; std::unordered_map immediate_dominators; std::unordered_map visit_order; @@ -129,6 +130,7 @@ class CFG SmallVector empty_vector; void add_branch(uint32_t from, uint32_t to); + void add_virtual_dominance_branch(uint32_t from, uint32_t to); void build_post_order_visit_order(); void build_immediate_dominators(); void post_order_visit_branches(uint32_t block); diff --git a/3rdparty/spirv-cross/spirv_common.hpp b/3rdparty/spirv-cross/spirv_common.hpp index 5e81d9a4..1d20d762 100644 --- a/3rdparty/spirv-cross/spirv_common.hpp +++ b/3rdparty/spirv-cross/spirv_common.hpp @@ -377,6 +377,7 @@ enum Types TypeAccessChain, TypeUndef, TypeString, + TypeDebugLocalVariable, TypeCount }; @@ -506,6 +507,18 @@ struct SPIRString : IVariant SPIRV_CROSS_DECLARE_CLONE(SPIRString) }; +struct SPIRDebugLocalVariable : IVariant +{ + enum + { + type = TypeDebugLocalVariable + }; + + uint32_t name_id; + + SPIRV_CROSS_DECLARE_CLONE(SPIRDebugLocalVariable) +}; + // This type is only used by backends which need to access the combined image and sampler IDs separately after // the OpSampledImage opcode. struct SPIRCombinedImageSampler : IVariant @@ -1163,6 +1176,9 @@ struct SPIRVariable : IVariant // Temporaries which can remain forwarded as long as this variable is not modified. SmallVector dependees; + // ShaderDebugInfo local variables attached to this variable via DebugDeclare + SmallVector debug_local_variables; + bool deferred_declaration = false; bool phi_variable = false; @@ -1355,7 +1371,7 @@ struct SPIRConstant : IVariant inline float scalar_bf8(uint32_t col = 0, uint32_t row = 0) const { - return f16_to_f32(scalar_u8(col, row) << 8); + return f16_to_f32(uint16_t(scalar_u8(col, row) << 8)); } inline float scalar_f32(uint32_t col = 0, uint32_t row = 0) const @@ -1790,7 +1806,7 @@ struct Meta { std::string alias; std::string qualified_alias; - std::string hlsl_semantic; + std::string user_semantic; std::string user_type; Bitset decoration_flags; spv::BuiltIn builtin_type = spv::BuiltInMax; diff --git a/3rdparty/spirv-cross/spirv_cross.cpp b/3rdparty/spirv-cross/spirv_cross.cpp index 2204e391..1031d3ff 100644 --- a/3rdparty/spirv-cross/spirv_cross.cpp +++ b/3rdparty/spirv-cross/spirv_cross.cpp @@ -3611,7 +3611,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(Op op, const uint32_t * case OpCopyObject: { - // OpCopyObject copies the underlying non-pointer type, + // OpCopyObject copies the underlying non-pointer type, // so any temp variable should be declared using the underlying type. // If the type is a pointer, get its base type and overwrite the result type mapping. auto &type = compiler.get(result_type); @@ -5078,12 +5078,12 @@ std::string Compiler::get_remapped_declared_block_name(uint32_t id, bool fallbac bool Compiler::reflection_ssbo_instance_name_is_significant() const { - if (ir.source.known) + if (!ir.sources.empty() && ir.sources[0].known) { // UAVs from HLSL source tend to be declared in a way where the type is reused // but the instance name is significant, and that's the name we should report. // For GLSL, SSBOs each have their own block type as that's how GLSL is written. - return ir.source.hlsl; + return ir.sources[0].hlsl; } unordered_set ssbo_type_ids; diff --git a/3rdparty/spirv-cross/spirv_cross.hpp b/3rdparty/spirv-cross/spirv_cross.hpp index 06f2b73f..f72d7997 100644 --- a/3rdparty/spirv-cross/spirv_cross.hpp +++ b/3rdparty/spirv-cross/spirv_cross.hpp @@ -549,6 +549,9 @@ class Compiler return position_invariant; } + const ParsedIR &get_ir() const { return ir; } + uint32_t evaluate_constant_u32(uint32_t id) const; + protected: const uint32_t *stream(const Instruction &instr) const { @@ -1197,7 +1200,6 @@ class Compiler bool flush_phi_required(BlockID from, BlockID to) const; uint32_t evaluate_spec_constant_u32(const SPIRConstantOp &spec) const; - uint32_t evaluate_constant_u32(uint32_t id) const; bool is_vertex_like_shader() const; diff --git a/3rdparty/spirv-cross/spirv_cross_c.cpp b/3rdparty/spirv-cross/spirv_cross_c.cpp index e1b7b1d1..1604385e 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.cpp +++ b/3rdparty/spirv-cross/spirv_cross_c.cpp @@ -529,6 +529,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_HLSL_PRESERVE_STRUCTURED_BUFFERS: options->hlsl.preserve_structured_buffers = value != 0; break; + + case SPVC_COMPILER_OPTION_HLSL_USER_SEMANTIC: + options->hlsl.user_semantic = value != 0; + break; #endif #if SPIRV_CROSS_C_API_MSL diff --git a/3rdparty/spirv-cross/spirv_cross_c.h b/3rdparty/spirv-cross/spirv_cross_c.h index f360711e..30f1c459 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.h +++ b/3rdparty/spirv-cross/spirv_cross_c.h @@ -40,7 +40,7 @@ extern "C" { /* Bumped if ABI or API breaks backwards compatibility. */ #define SPVC_C_API_VERSION_MAJOR 0 /* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 67 +#define SPVC_C_API_VERSION_MINOR 68 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -753,6 +753,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_DEFAULT = 93 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_HLSL_USER_SEMANTIC = 94 | SPVC_COMPILER_OPTION_HLSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp index 449c6655..5e1f58a3 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp @@ -49,6 +49,7 @@ ParsedIR::ParsedIR() pool_group->pools[TypeAccessChain].reset(new ObjectPool); pool_group->pools[TypeUndef].reset(new ObjectPool); pool_group->pools[TypeString].reset(new ObjectPool); + pool_group->pools[TypeDebugLocalVariable].reset(new ObjectPool); } // Should have been default-implemented, but need this on MSVC 2013. @@ -78,7 +79,7 @@ ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT memory_model = other.memory_model; default_entry_point = other.default_entry_point; - source = other.source; + sources = std::move(other.sources); loop_iteration_depth_hard = other.loop_iteration_depth_hard; loop_iteration_depth_soft = other.loop_iteration_depth_soft; @@ -110,7 +111,7 @@ ParsedIR &ParsedIR::operator=(const ParsedIR &other) continue_block_to_loop_header = other.continue_block_to_loop_header; entry_points = other.entry_points; default_entry_point = other.default_entry_point; - source = other.source; + sources = other.sources; loop_iteration_depth_hard = other.loop_iteration_depth_hard; loop_iteration_depth_soft = other.loop_iteration_depth_soft; addressing_model = other.addressing_model; @@ -366,8 +367,8 @@ void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string switch (decoration) { - case DecorationHlslSemanticGOOGLE: - dec.hlsl_semantic = argument; + case DecorationUserSemantic: + dec.user_semantic = argument; break; case DecorationUserTypeGOOGLE: @@ -692,8 +693,8 @@ const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) cons switch (decoration) { - case DecorationHlslSemanticGOOGLE: - return dec.hlsl_semantic; + case DecorationUserSemantic: + return dec.user_semantic; case DecorationUserTypeGOOGLE: return dec.user_type; @@ -757,8 +758,8 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration) dec.spec_id = 0; break; - case DecorationHlslSemanticGOOGLE: - dec.hlsl_semantic.clear(); + case DecorationUserSemantic: + dec.user_semantic.clear(); break; case DecorationFPRoundingMode: @@ -853,8 +854,8 @@ void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoratio switch (decoration) { - case DecorationHlslSemanticGOOGLE: - dec.hlsl_semantic = argument; + case DecorationUserSemantic: + dec.user_semantic = argument; break; default: @@ -874,8 +875,8 @@ const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, switch (decoration) { - case DecorationHlslSemanticGOOGLE: - return dec.hlsl_semantic; + case DecorationUserSemantic: + return dec.user_semantic; default: return empty_string; @@ -928,8 +929,8 @@ void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration dec dec.spec_id = 0; break; - case DecorationHlslSemanticGOOGLE: - dec.hlsl_semantic.clear(); + case DecorationUserSemantic: + dec.user_semantic.clear(); break; default: diff --git a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp index 0e825b4f..b1e76f20 100644 --- a/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp +++ b/3rdparty/spirv-cross/spirv_cross_parsed_ir.hpp @@ -118,10 +118,25 @@ class ParsedIR bool known = false; bool hlsl = false; + ID file_id = 0; // string + ID define_id = 0; // only non-zero for DebugSource + std::string source; + + struct Marker + { + ID line; // in source + ID col; // in source + ID offset; // in spirv stream + ID function_id; + ID block_id; + }; + + SmallVector line_markers; // sorted by line + Source() = default; }; - Source source; + std::vector sources; AddressingModel addressing_model = AddressingModelMax; MemoryModel memory_model = MemoryModelMax; @@ -233,7 +248,6 @@ class ParsedIR uint32_t get_spirv_version() const; -private: template T &get(uint32_t id) { @@ -246,6 +260,7 @@ class ParsedIR return variant_get(ids[id]); } +private: mutable uint32_t loop_iteration_depth_hard = 0; mutable uint32_t loop_iteration_depth_soft = 0; std::string empty_string; diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 21f82263..c76f2f16 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -206,10 +206,10 @@ static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard void CompilerGLSL::init() { - if (ir.source.known) + if (!ir.sources.empty() && ir.sources.front().known) { - options.es = ir.source.es; - options.version = ir.source.version; + options.es = ir.sources.front().es; + options.version = ir.sources.front().version; } // Query the locale to see what the decimal point is. @@ -1335,9 +1335,6 @@ void CompilerGLSL::emit_struct(SPIRType &type) emitted = true; } - if (has_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget)) - emit_struct_padding_target(type); - end_scope_decl(); if (emitted) @@ -1755,10 +1752,32 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f { uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing); - // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size, - // so that it is possible to pack other vectors into the last element. - if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct) - packed_size -= (4 - type.vecsize) * (type.width / 8); + if (packing_is_hlsl(packing)) + { + // For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size, + // so that it is possible to pack other vectors into the last element. + if (type.basetype != SPIRType::Struct) + { + if (flags.get(DecorationRowMajor) && type.columns > 1) + packed_size -= (4 - type.columns) * (type.width / 8); + else + packed_size -= (4 - type.vecsize) * (type.width / 8); + } + else + { + const auto *base_type = &type; + while (is_array(*base_type)) + { + auto &new_type = get(base_type->parent_type); + if (!is_array(new_type)) + break; + base_type = &new_type; + } + + packed_size -= type_to_packed_array_stride(*base_type, flags, packing); + packed_size += type_to_packed_size(get(base_type->parent_type), flags, packing); + } + } return packed_size; } @@ -1777,15 +1796,27 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing); uint32_t alignment = max(packed_alignment, pad_alignment); - // The next member following a struct member is aligned to the base alignment of the struct that came before. - // GL 4.5 spec, 7.6.2.2. - if (member_type.basetype == SPIRType::Struct) - pad_alignment = packed_alignment; + uint32_t element_size = type_to_packed_size(member_type, member_flags, packing); + pad_alignment = 1; + + if (packing_is_hlsl(packing)) + { + // HLSL is primarily a "cannot-straddle-vec4" language. + uint32_t begin_word = size / 16; + uint32_t end_word = (size + element_size - 1) / 16; + if (begin_word != end_word) + alignment = max(alignment, 16u); + } else - pad_alignment = 1; + { + // The next member following a struct member is aligned to the base alignment of the struct that came before. + // GL 4.5 spec, 7.6.2.2. + if (member_type.basetype == SPIRType::Struct) + pad_alignment = packed_alignment; + } size = (size + alignment - 1) & ~(alignment - 1); - size += type_to_packed_size(member_type, member_flags, packing); + size += element_size; } } else @@ -1803,9 +1834,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f if (flags.get(DecorationColMajor) && type.columns > 1) { - if (packing_is_vec4_padded(packing)) - size = type.columns * 4 * base_alignment; - else if (type.vecsize == 3) + if (packing_is_vec4_padded(packing) || type.vecsize == 3) size = type.columns * 4 * base_alignment; else size = type.columns * type.vecsize * base_alignment; @@ -1813,9 +1842,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f if (flags.get(DecorationRowMajor) && type.vecsize > 1) { - if (packing_is_vec4_padded(packing)) - size = type.vecsize * 4 * base_alignment; - else if (type.columns == 3) + if (packing_is_vec4_padded(packing) || type.columns == 3) size = type.vecsize * 4 * base_alignment; else size = type.vecsize * type.columns * base_alignment; @@ -1824,7 +1851,12 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f // For matrices in HLSL, the last element has a size which depends on its vector size, // so that it is possible to pack other vectors into the last element. if (packing_is_hlsl(packing) && type.columns > 1) - size -= (4 - type.vecsize) * (type.width / 8); + { + if (flags.get(DecorationRowMajor)) + size -= (4 - type.columns) * (type.width / 8); + else + size -= (4 - type.vecsize) * (type.width / 8); + } } } @@ -1915,7 +1947,7 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin // The next member following a struct member is aligned to the base alignment of the struct that came before. // GL 4.5 spec, 7.6.2.2. - if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer) + if (!packing_is_hlsl(packing) && memb_type.basetype == SPIRType::Struct && !memb_type.pointer) pad_alignment = packed_alignment; else pad_alignment = 1; @@ -1943,13 +1975,16 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin } // Verify array stride rules. - if (is_array(memb_type) && - type_to_packed_array_stride(memb_type, member_flags, packing) != - type_struct_member_array_stride(type, i)) + if (is_array(memb_type)) { - if (failed_validation_index) - *failed_validation_index = i; - return false; + auto packed_array_stride = type_to_packed_array_stride(memb_type, member_flags, packing); + auto member_array_stride = type_struct_member_array_stride(type, i); + if (packed_array_stride != member_array_stride) + { + if (failed_validation_index) + *failed_validation_index = i; + return false; + } } // Verify that sub-structs also follow packing rules. @@ -10837,6 +10872,15 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice access_meshlet_position_y = true; } + if (get(type->parent_type).op == OpTypeStruct && + has_decoration(type->parent_type, DecorationArrayStride)) + { + uint32_t native_stride = get_decoration(type->parent_type, DecorationArrayStride); + uint32_t array_stride = get_decoration(type_id, DecorationArrayStride); + if (native_stride != array_stride) + expr += ".data"; + } + type_id = type->parent_type; type = &get(type_id); @@ -10924,6 +10968,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice physical_type = 0; row_major_matrix_needs_conversion = member_is_non_native_row_major_matrix(*type, index); + type_id = type->member_types[index]; type = &get(type->member_types[index]); } // Matrix -> Vector @@ -11135,9 +11180,9 @@ string CompilerGLSL::to_flattened_struct_member(const string &basename, const SP return ret; } -uint32_t CompilerGLSL::get_physical_type_stride(const SPIRType &) const +uint32_t CompilerGLSL::get_physical_type_id_stride(TypeID) const { - SPIRV_CROSS_THROW("Invalid to call get_physical_type_stride on a backend without native pointer support."); + SPIRV_CROSS_THROW("Invalid to call get_physical_type_id_stride on a backend without native pointer support."); } string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, @@ -11198,13 +11243,13 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32 // If there is a mismatch we have to go via 64-bit pointer arithmetic :'( // Using packed hacks only gets us so far, and is not designed to deal with pointer to // random values. It works for structs though. - auto &pointee_type = get_pointee_type(get(type_id)); - uint32_t physical_stride = get_physical_type_stride(pointee_type); + TypeID pointee_type_id = get_pointee_type_id(type_id); + uint32_t physical_stride = get_physical_type_id_stride(pointee_type_id); uint32_t requested_stride = get_decoration(type_id, DecorationArrayStride); if (physical_stride != requested_stride) { flags |= ACCESS_CHAIN_PTR_CHAIN_POINTER_ARITH_BIT; - if (is_vector(pointee_type)) + if (is_vector(get(pointee_type_id))) flags |= ACCESS_CHAIN_PTR_CHAIN_CAST_TO_SCALAR_BIT; } } @@ -16305,10 +16350,6 @@ void CompilerGLSL::emit_struct_member(const SPIRType &type, uint32_t member_type variable_decl(membertype, to_member_name(type, index)), ";"); } -void CompilerGLSL::emit_struct_padding_target(const SPIRType &) -{ -} - string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, uint32_t id, const Bitset &flags) { // GL_EXT_buffer_reference variables can be marked as restrict. diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index 2e2a3fce..5566b49b 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -459,7 +459,6 @@ class CompilerGLSL : public Compiler virtual std::string builtin_to_glsl(BuiltIn builtin, StorageClass storage); virtual void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier = "", uint32_t base_offset = 0); - virtual void emit_struct_padding_target(const SPIRType &type); virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0, bool member = false); std::string constant_expression(const SPIRConstant &c, bool inside_block_like_struct_scope = false, @@ -785,7 +784,7 @@ class CompilerGLSL : public Compiler // Only meaningful on backends with physical pointer support ala MSL. // Relevant for PtrAccessChain / BDA. - virtual uint32_t get_physical_type_stride(const SPIRType &type) const; + virtual uint32_t get_physical_type_id_stride(TypeID type_id) const; StorageClass get_expression_effective_storage_class(uint32_t ptr); virtual bool access_chain_needs_stage_io_builtin_translation(uint32_t base); diff --git a/3rdparty/spirv-cross/spirv_hlsl.cpp b/3rdparty/spirv-cross/spirv_hlsl.cpp index 307388bd..81bea2a8 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.cpp +++ b/3rdparty/spirv-cross/spirv_hlsl.cpp @@ -1021,7 +1021,13 @@ void CompilerHLSL::emit_interface_block_member_in_struct(const SPIRVariable &var { auto &execution = get_entry_point(); auto type = get(var.basetype); - auto semantic = to_semantic(location, execution.model, var.storage); + + std::string semantic; + if (hlsl_options.user_semantic && has_member_decoration(var.self, member_index, DecorationUserSemantic)) + semantic = get_member_decoration_string(var.self, member_index, DecorationUserSemantic); + else + semantic = to_semantic(location, execution.model, var.storage); + auto mbr_name = join(to_name(type.self), "_", to_member_name(type, member_index)); auto &mbr_type = get(type.member_types[member_index]); @@ -1080,17 +1086,28 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord auto name = to_name(var.self); if (use_location_number) { - uint32_t location_number; + uint32_t location_number = UINT32_MAX; - // If an explicit location exists, use it with TEXCOORD[N] semantic. - // Otherwise, pick a vacant location. - if (has_decoration(var.self, DecorationLocation)) - location_number = get_decoration(var.self, DecorationLocation); + std::string semantic; + bool has_user_semantic = false; + + if (hlsl_options.user_semantic && has_decoration(var.self, DecorationUserSemantic)) + { + semantic = get_decoration_string(var.self, DecorationUserSemantic); + has_user_semantic = true; + } else - location_number = get_vacant_location(); + { + // If an explicit location exists, use it with TEXCOORD[N] semantic. + // Otherwise, pick a vacant location. + if (has_decoration(var.self, DecorationLocation)) + location_number = get_decoration(var.self, DecorationLocation); + else + location_number = get_vacant_location(); - // Allow semantic remap if specified. - auto semantic = to_semantic(location_number, execution.model, var.storage); + // Allow semantic remap if specified. + semantic = to_semantic(location_number, execution.model, var.storage); + } if (need_matrix_unroll && type.columns > 1) { @@ -1104,14 +1121,15 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord newtype.columns = 1; string effective_semantic; - if (hlsl_options.flatten_matrix_vertex_input_semantics) + if (hlsl_options.flatten_matrix_vertex_input_semantics && !has_user_semantic) effective_semantic = to_semantic(location_number, execution.model, var.storage); else effective_semantic = join(semantic, "_", i); statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)), variable_decl(newtype, join(name, "_", i)), " : ", effective_semantic, ";"); - active_locations.insert(location_number++); + if (location_number != UINT32_MAX) + active_locations.insert(location_number++); } } else @@ -1127,10 +1145,13 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)), variable_decl(decl_type, name), " : ", semantic, ";"); - // Structs and arrays should consume more locations. - uint32_t consumed_locations = type_to_consumed_locations(decl_type); - for (uint32_t i = 0; i < consumed_locations; i++) - active_locations.insert(location_number + i); + if (location_number != UINT32_MAX) + { + // Structs and arrays should consume more locations. + uint32_t consumed_locations = type_to_consumed_locations(decl_type); + for (uint32_t i = 0; i < consumed_locations; i++) + active_locations.insert(location_number + i); + } } } else diff --git a/3rdparty/spirv-cross/spirv_hlsl.hpp b/3rdparty/spirv-cross/spirv_hlsl.hpp index c7de6af0..059036f0 100644 --- a/3rdparty/spirv-cross/spirv_hlsl.hpp +++ b/3rdparty/spirv-cross/spirv_hlsl.hpp @@ -151,6 +151,9 @@ class CompilerHLSL : public CompilerGLSL // This relies on UserTypeGOOGLE to encode the buffer type either as "structuredbuffer" or "rwstructuredbuffer" // whereas the type can be extended with an optional subtype, e.g. "structuredbuffer:int". bool preserve_structured_buffers = false; + + // Use UserSemantic decoration info (if specified), otherwise use default mechanism (such as add_vertex_attribute_remap or TEXCOORD#). + bool user_semantic = false; }; explicit CompilerHLSL(std::vector spirv_) diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index 2525df38..1291d5d2 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -5048,23 +5048,16 @@ void CompilerMSL::mark_scalar_layout_structs(const SPIRType &type) if (struct_needs_explicit_padding) { - msl_size = get_declared_struct_size_msl(*struct_type, true, true); - if (array_stride < msl_size) - { - SPIRV_CROSS_THROW("Cannot express an array stride smaller than size of struct type."); - } - else + msl_size = get_declared_struct_size_msl(*struct_type); + + if (array_stride > msl_size) { - if (has_extended_decoration(struct_type->self, SPIRVCrossDecorationPaddingTarget)) - { - if (array_stride != - get_extended_decoration(struct_type->self, SPIRVCrossDecorationPaddingTarget)) - SPIRV_CROSS_THROW( - "A struct is used with different array strides. Cannot express this in MSL."); - } - else - set_extended_decoration(struct_type->self, SPIRVCrossDecorationPaddingTarget, array_stride); + set_decoration(struct_type->self, DecorationArrayStride, msl_size); + add_spv_func_and_recompile(SPVFuncImplPaddedArrayElement); } + + if (array_stride < msl_size) + SPIRV_CROSS_THROW("Cannot express an array stride smaller than size of struct type."); } } } @@ -5170,8 +5163,10 @@ bool CompilerMSL::validate_member_packing_rules_msl(const SPIRType &type, uint32 // If app tries to be cheeky and access the member out of bounds, this will not work, but this is the best we can do. // In OpAccessChain with logical memory models, access chains must be in-bounds in SPIR-V specification. bool relax_array_stride = mbr_type.array.back() == 1 && mbr_type.array_size_literal.back(); + bool is_plain_struct = !mbr_type.pointer && mbr_type.basetype == SPIRType::Struct; - if (!relax_array_stride) + // Array of struct is padded on-demand. + if (!relax_array_stride && !is_plain_struct) { uint32_t spirv_array_stride = type_struct_member_array_stride(type, index); uint32_t msl_array_stride = get_declared_struct_member_array_stride_msl(type, index); @@ -6170,14 +6165,31 @@ void CompilerMSL::emit_custom_functions() "device", "device", "device", "device", "thread", "threadgroup", }; + static const bool src_is_physical_with_mismatch[] = { + true, true, false, + false, false, false, + false, false, false, + false, true, true, + }; + + static const bool dst_is_physical_with_mismatch[] = { + false, false, false, + false, false, false, + false, false, true, + true, false, false, + }; + for (uint32_t variant = 0; variant < 12; variant++) { + assert(!src_is_physical_with_mismatch[variant] || !dst_is_physical_with_mismatch[variant]); bool is_multidim = spv_func == SPVFuncImplArrayCopyMultidim; - const char* dim = is_multidim ? "[N][M]" : "[N]"; + const char *dim = is_multidim ? "[N][M]" : "[N]"; + + // Simple base case. statement("template" : ">"); statement("inline void spvArrayCopy", function_name_tags[variant], "(", - dst_address_space[variant], " T (&dst)", dim, ", ", - src_address_space[variant], " T (&src)", dim, ")"); + dst_address_space[variant], " T (&dst)", dim, ", ", + src_address_space[variant], " T (&src)", dim, ")"); begin_scope(); statement("for (uint i = 0; i < N; i++)"); begin_scope(); @@ -6187,6 +6199,81 @@ void CompilerMSL::emit_custom_functions() statement("dst[i] = src[i];"); end_scope(); end_scope(); + + if (spv_function_implementations.count(SPVFuncImplArrayCopyExtendedSrc) && + src_is_physical_with_mismatch[variant]) + { + // 1st overload, src can be magic vector where dst is a scalar. + // Need reinterpret casts to be memory model correct. LLVM vectors are broken otherwise. + statement("template" : ">"); + statement("inline void spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " T (&dst)", dim, ", ", + src_address_space[variant], " vec (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("dst[i] = reinterpret_cast<", src_address_space[variant], " T &>(src[i]);"); + end_scope(); + end_scope(); + + statement(""); + + // 2nd overload, both are vectors, but need SFINAE magic to avoid ambiguous case. + statement("template" : ">"); + statement("inline enable_if_t spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " vec (&dst)", dim, ", ", + src_address_space[variant], " vec (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("dst[i] = reinterpret_cast<", src_address_space[variant], " vec &>(src[i]);"); + end_scope(); + end_scope(); + } + + if (spv_function_implementations.count(SPVFuncImplArrayCopyExtendedDst) && + dst_is_physical_with_mismatch[variant]) + { + // 1st overload, src can be magic vector where dst is a scalar. + // Need reinterpret casts to be memory model correct. LLVM vectors are broken otherwise. + statement("template" : ">"); + statement("inline void spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " vec (&dst)", dim, ", ", + src_address_space[variant], " T (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("reinterpret_cast<", dst_address_space[variant], " T &>(dst[i]) = src[i];"); + end_scope(); + end_scope(); + + statement(""); + + // 2nd overload, both are vectors, but need SFINAE magic to avoid ambiguous case. + statement("template" : ">"); + statement("inline enable_if_t spvArrayCopy", function_name_tags[variant], "(", + dst_address_space[variant], " vec (&dst)", dim, ", ", + src_address_space[variant], " vec (&src)", dim, ")"); + begin_scope(); + statement("for (uint i = 0; i < N; i++)"); + begin_scope(); + if (is_multidim) + statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);"); + else + statement("reinterpret_cast<", dst_address_space[variant], " vec &>(dst[i]) = src[i];"); + end_scope(); + end_scope(); + } + statement(""); } break; @@ -8121,6 +8208,13 @@ void CompilerMSL::emit_custom_functions() statement(""); break; + case SPVFuncImplPaddedArrayElement: + // .data is used in access chain. + statement("template "); + statement("struct spvPaddedArrayElement { T data; char padding[stride - sizeof(T)]; };"); + statement(""); + break; + case SPVFuncImplReduceAdd: // Metal doesn't support __builtin_reduce_add or simd_reduce_add, so we need this. // Metal also doesn't support the other vector builtins, which would have been useful to make this a single template. @@ -10905,6 +10999,12 @@ bool CompilerMSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rh else SPIRV_CROSS_THROW("Unknown storage class used for copying arrays."); + // Should be very rare, but mark if we need extra magic template overloads. + if (has_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID)) + add_spv_func_and_recompile(SPVFuncImplArrayCopyExtendedDst); + if (has_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID)) + add_spv_func_and_recompile(SPVFuncImplArrayCopyExtendedSrc); + // Pass internal array of spvUnsafeArray<> into wrapper functions if (lhs_is_array_template && rhs_is_array_template && !msl_options.force_native_arrays) statement("spvArrayCopy", tag, "(", lhs, ".elements, ", to_expression(rhs_id), ".elements);"); @@ -13377,6 +13477,24 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ else decl_type = type_to_glsl(*declared_type, orig_id, true); + if (physical_type.basetype == SPIRType::Struct && + has_decoration(physical_type.self, DecorationArrayStride) && + is_array(physical_type)) + { + uint32_t native_stride = get_decoration(physical_type.self, DecorationArrayStride); + uint32_t array_stride = get_decoration(type.member_types[index], DecorationArrayStride); + auto *struct_array_type = &physical_type; + + while (struct_array_type->parent_type && is_array(get(struct_array_type->parent_type))) + { + array_stride = get_decoration(struct_array_type->parent_type, DecorationArrayStride); + struct_array_type = &get(struct_array_type->parent_type); + } + + if (array_stride != native_stride) + decl_type = join("spvPaddedArrayElement<", decl_type, ", ", array_stride, ">"); + } + const char *overlapping_binding_tag = has_extended_member_decoration(type.self, index, SPIRVCrossDecorationOverlappingBinding) ? "// Overlapping binding: " : ""; @@ -13415,16 +13533,6 @@ void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_ builtin_declaration = false; } -void CompilerMSL::emit_struct_padding_target(const SPIRType &type) -{ - uint32_t struct_size = get_declared_struct_size_msl(type, true, true); - uint32_t target_size = get_extended_decoration(type.self, SPIRVCrossDecorationPaddingTarget); - if (target_size < struct_size) - SPIRV_CROSS_THROW("Cannot pad with negative bytes."); - else if (target_size > struct_size) - statement("char _m0_final_padding[", target_size - struct_size, "];"); -} - // Return a MSL qualifier for the specified function attribute member string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t index) { @@ -14172,6 +14280,10 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo addr_space = "threadgroup"; } + // BlockIO is passed as thread and lowered on return from main. + if (get_execution_model() == ExecutionModelVertex && has_decoration(type.self, DecorationBlock)) + addr_space = "thread"; + if (!addr_space) addr_space = "device"; } @@ -18171,17 +18283,17 @@ string CompilerMSL::built_in_func_arg(BuiltIn builtin, bool prefix_comma) return bi_arg; } -const SPIRType &CompilerMSL::get_physical_member_type(const SPIRType &type, uint32_t index) const +TypeID CompilerMSL::get_physical_member_type_id(const SPIRType &type, uint32_t index) const { if (member_is_remapped_physical_type(type, index)) - return get(get_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID)); + return get_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID); else - return get(type.member_types[index]); + return type.member_types[index]; } SPIRType CompilerMSL::get_presumed_input_type(const SPIRType &ib_type, uint32_t index) const { - SPIRType type = get_physical_member_type(ib_type, index); + SPIRType type = get(get_physical_member_type_id(ib_type, index)); uint32_t loc = get_member_decoration(ib_type.self, index, DecorationLocation); uint32_t cmp = get_member_decoration(ib_type.self, index, DecorationComponent); auto p_va = inputs_by_location.find({loc, cmp}); @@ -18191,7 +18303,7 @@ SPIRType CompilerMSL::get_presumed_input_type(const SPIRType &ib_type, uint32_t return type; } -uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type, bool is_packed, bool row_major) const +uint32_t CompilerMSL::get_declared_type_array_stride_msl(TypeID type_id, const SPIRType *special_type, bool is_packed, bool row_major) const { // Array stride in MSL is always size * array_size. sizeof(float3) == 16, // unlike GLSL and HLSL where array stride would be 16 and size 12. @@ -18200,11 +18312,42 @@ uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type, b // far more complicated. We'd rather just create the final type, and ignore having to create the entire type // hierarchy in order to compute this value, so make a temporary type on the stack. - auto basic_type = type; - basic_type.array.clear(); - basic_type.array_size_literal.clear(); - uint32_t value_size = get_declared_type_size_msl(basic_type, is_packed, row_major); + uint32_t value_size; + + // We don't always use proper type hierarchy for synthesized types, so be robust. + if (type_id && get(type_id).parent_type) + { + bool uses_declared_array_stride = false; + + uint32_t array_stride = 0; + TypeID basic_type_id = type_id; + while (is_array(get(basic_type_id))) + { + array_stride = get_decoration(basic_type_id, DecorationArrayStride); + auto parent_type_id = get(basic_type_id).parent_type; + // If the base struct itself has ArrayStride decoration, it will be padded on-demand. + uses_declared_array_stride = has_decoration(parent_type_id, DecorationArrayStride); + if (parent_type_id) + basic_type_id = parent_type_id; + else + break; + } + + if (array_stride && uses_declared_array_stride) + value_size = array_stride; + else + value_size = get_declared_type_size_msl(basic_type_id, nullptr, is_packed, row_major); + } + else + { + // Old, broken path. + auto basic_type = type_id ? get(type_id) : *special_type; + basic_type.array.clear(); + basic_type.array_size_literal.clear(); + value_size = get_declared_type_size_msl(0, &basic_type, is_packed, row_major); + } + auto &type = type_id ? get(type_id) : *special_type; uint32_t dimensions = uint32_t(type.array.size()); assert(dimensions > 0); dimensions--; @@ -18221,47 +18364,47 @@ uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type, b uint32_t CompilerMSL::get_declared_struct_member_array_stride_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_array_stride_msl(get_physical_member_type(type, index), + return get_declared_type_array_stride_msl(get_physical_member_type_id(type, index), nullptr, member_is_packed_physical_type(type, index), has_member_decoration(type.self, index, DecorationRowMajor)); } uint32_t CompilerMSL::get_declared_input_array_stride_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_array_stride_msl(get_presumed_input_type(type, index), false, + auto presumed_type = get_presumed_input_type(type, index); + return get_declared_type_array_stride_msl(0, &presumed_type, false, has_member_decoration(type.self, index, DecorationRowMajor)); } -uint32_t CompilerMSL::get_declared_type_matrix_stride_msl(const SPIRType &type, bool packed, bool row_major) const +uint32_t CompilerMSL::get_declared_type_matrix_stride_msl(TypeID type_id, const SPIRType *special_type, + bool packed, bool row_major) const { + auto &type = type_id ? get(type_id) : *special_type; + // For packed matrices, we just use the size of the vector type. // Otherwise, MatrixStride == alignment, which is the size of the underlying vector type. if (packed) return (type.width / 8) * ((row_major && type.columns > 1) ? type.columns : type.vecsize); else - return get_declared_type_alignment_msl(type, false, row_major); + return get_declared_type_alignment_msl(type_id, special_type, false, row_major); } uint32_t CompilerMSL::get_declared_struct_member_matrix_stride_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_matrix_stride_msl(get_physical_member_type(type, index), + return get_declared_type_matrix_stride_msl(get_physical_member_type_id(type, index), nullptr, member_is_packed_physical_type(type, index), has_member_decoration(type.self, index, DecorationRowMajor)); } uint32_t CompilerMSL::get_declared_input_matrix_stride_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_matrix_stride_msl(get_presumed_input_type(type, index), false, + auto presumed_type = get_presumed_input_type(type, index); + return get_declared_type_matrix_stride_msl(0, &presumed_type, false, has_member_decoration(type.self, index, DecorationRowMajor)); } -uint32_t CompilerMSL::get_declared_struct_size_msl(const SPIRType &struct_type, bool ignore_alignment, - bool ignore_padding) const +uint32_t CompilerMSL::get_declared_struct_size_msl(const SPIRType &struct_type) const { - // If we have a target size, that is the declared size as well. - if (!ignore_padding && has_extended_decoration(struct_type.self, SPIRVCrossDecorationPaddingTarget)) - return get_extended_decoration(struct_type.self, SPIRVCrossDecorationPaddingTarget); - if (struct_type.member_types.empty()) return 0; @@ -18270,13 +18413,10 @@ uint32_t CompilerMSL::get_declared_struct_size_msl(const SPIRType &struct_type, // In MSL, a struct's alignment is equal to the maximum alignment of any of its members. uint32_t alignment = 1; - if (!ignore_alignment) + for (uint32_t i = 0; i < mbr_cnt; i++) { - for (uint32_t i = 0; i < mbr_cnt; i++) - { - uint32_t mbr_alignment = get_declared_struct_member_alignment_msl(struct_type, i); - alignment = max(alignment, mbr_alignment); - } + uint32_t mbr_alignment = get_declared_struct_member_alignment_msl(struct_type, i); + alignment = max(alignment, mbr_alignment); } // Last member will always be matched to the final Offset decoration, but size of struct in MSL now depends @@ -18287,16 +18427,19 @@ uint32_t CompilerMSL::get_declared_struct_size_msl(const SPIRType &struct_type, return msl_size; } -uint32_t CompilerMSL::get_physical_type_stride(const SPIRType &type) const +uint32_t CompilerMSL::get_physical_type_id_stride(TypeID type_id) const { // This should only be relevant for plain types such as scalars and vectors? // If we're pointing to a struct, it will recursively pick up packed/row-major state. - return get_declared_type_size_msl(type, false, false); + return get_declared_type_size_msl(type_id, nullptr, false, false); } // Returns the byte size of a struct member. -uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_packed, bool row_major) const +uint32_t CompilerMSL::get_declared_type_size_msl(TypeID type_id, const SPIRType *special_type, + bool is_packed, bool row_major) const { + auto &type = type_id ? get(type_id) : *special_type; + // Pointers take 8 bytes each // Match both pointer and array-of-pointer here. if (type.pointer && type.storage == StorageClassPhysicalStorageBuffer) @@ -18329,10 +18472,27 @@ uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_p default: { - if (!type.array.empty()) + if ((!type.parent_type || special_type) && !type.array.empty()) { + // Special case where the type hierarchy is not set up properly. + // Don't want to have to allocate a bunch of dummy type IDs just to make it work. uint32_t array_size = to_array_size_literal(type); - return get_declared_type_array_stride_msl(type, is_packed, row_major) * max(array_size, 1u); + return get_declared_type_array_stride_msl(type_id, special_type, is_packed, row_major) * max(array_size, 1u); + } + else if (is_array(type) && type.parent_type) + { + // For the proper case. Ideally all code paths should go through here, but + // would need a lot of cleanup to make that work ... + auto &parent_type = get(type.parent_type); + uint32_t effective_stride; + + if (parent_type.op == OpTypeStruct && has_decoration(parent_type.self, DecorationArrayStride)) + effective_stride = get_decoration(type_id, DecorationArrayStride); + else + effective_stride = get_declared_type_array_stride_msl(type_id, special_type, is_packed, row_major); + + uint32_t array_size = to_array_size_literal(type); + return effective_stride * max(array_size, 1u); } if (type.basetype == SPIRType::Struct) @@ -18362,20 +18522,24 @@ uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_p uint32_t CompilerMSL::get_declared_struct_member_size_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_size_msl(get_physical_member_type(type, index), + return get_declared_type_size_msl(get_physical_member_type_id(type, index), nullptr, member_is_packed_physical_type(type, index), has_member_decoration(type.self, index, DecorationRowMajor)); } uint32_t CompilerMSL::get_declared_input_size_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_size_msl(get_presumed_input_type(type, index), false, + auto presumed_type = get_presumed_input_type(type, index); + return get_declared_type_size_msl(0, &presumed_type, false, has_member_decoration(type.self, index, DecorationRowMajor)); } // Returns the byte alignment of a type. -uint32_t CompilerMSL::get_declared_type_alignment_msl(const SPIRType &type, bool is_packed, bool row_major) const +uint32_t CompilerMSL::get_declared_type_alignment_msl(TypeID type_id, const SPIRType *special_type, + bool is_packed, bool row_major) const { + auto &type = type_id ? get(type_id) : *special_type; + // Pointers align on multiples of 8 bytes. // Deliberately ignore array-ness here. It's not relevant for alignment. if (type.pointer && type.storage == StorageClassPhysicalStorageBuffer) @@ -18429,14 +18593,15 @@ uint32_t CompilerMSL::get_declared_type_alignment_msl(const SPIRType &type, bool uint32_t CompilerMSL::get_declared_struct_member_alignment_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_alignment_msl(get_physical_member_type(type, index), + return get_declared_type_alignment_msl(get_physical_member_type_id(type, index), nullptr, member_is_packed_physical_type(type, index), has_member_decoration(type.self, index, DecorationRowMajor)); } uint32_t CompilerMSL::get_declared_input_alignment_msl(const SPIRType &type, uint32_t index) const { - return get_declared_type_alignment_msl(get_presumed_input_type(type, index), false, + auto presumed_type = get_presumed_input_type(type, index); + return get_declared_type_alignment_msl(0, &presumed_type, false, has_member_decoration(type.self, index, DecorationRowMajor)); } diff --git a/3rdparty/spirv-cross/spirv_msl.hpp b/3rdparty/spirv-cross/spirv_msl.hpp index f63f5a23..d6bd8faa 100644 --- a/3rdparty/spirv-cross/spirv_msl.hpp +++ b/3rdparty/spirv-cross/spirv_msl.hpp @@ -796,6 +796,8 @@ class CompilerMSL : public CompilerGLSL SPVFuncImplSSign, SPVFuncImplArrayCopy, SPVFuncImplArrayCopyMultidim, + SPVFuncImplArrayCopyExtendedSrc, + SPVFuncImplArrayCopyExtendedDst, SPVFuncImplTexelBufferCoords, SPVFuncImplImage2DAtomicCoords, // Emulate texture2D atomic operations SPVFuncImplGradientCube, @@ -884,6 +886,7 @@ class CompilerMSL : public CompilerGLSL SPVFuncImplVariableSizedDescriptor, SPVFuncImplVariableDescriptorArray, SPVFuncImplPaddedStd140, + SPVFuncImplPaddedArrayElement, SPVFuncImplReduceAdd, SPVFuncImplImageFence, SPVFuncImplTextureCast, @@ -919,7 +922,6 @@ class CompilerMSL : public CompilerGLSL const std::string &qualifier = ""); void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier = "", uint32_t base_offset = 0) override; - void emit_struct_padding_target(const SPIRType &type) override; std::string type_to_glsl(const SPIRType &type, uint32_t id, bool member); std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; void emit_block_hints(const SPIRBlock &block) override; @@ -1094,15 +1096,15 @@ class CompilerMSL : public CompilerGLSL uint32_t get_physical_tess_level_array_size(BuiltIn builtin) const; - uint32_t get_physical_type_stride(const SPIRType &type) const override; + uint32_t get_physical_type_id_stride(TypeID type_id) const override; // MSL packing rules. These compute the effective packing rules as observed by the MSL compiler in the MSL output. // These values can change depending on various extended decorations which control packing rules. // We need to make these rules match up with SPIR-V declared rules. - uint32_t get_declared_type_size_msl(const SPIRType &type, bool packed, bool row_major) const; - uint32_t get_declared_type_array_stride_msl(const SPIRType &type, bool packed, bool row_major) const; - uint32_t get_declared_type_matrix_stride_msl(const SPIRType &type, bool packed, bool row_major) const; - uint32_t get_declared_type_alignment_msl(const SPIRType &type, bool packed, bool row_major) const; + uint32_t get_declared_type_size_msl(TypeID type_id, const SPIRType *special_type, bool packed, bool row_major) const; + uint32_t get_declared_type_array_stride_msl(TypeID type_id, const SPIRType *special_type, bool packed, bool row_major) const; + uint32_t get_declared_type_matrix_stride_msl(TypeID type_id, const SPIRType *special_type, bool packed, bool row_major) const; + uint32_t get_declared_type_alignment_msl(TypeID type_id, const SPIRType *special_type, bool packed, bool row_major) const; uint32_t get_declared_struct_member_size_msl(const SPIRType &struct_type, uint32_t index) const; uint32_t get_declared_struct_member_array_stride_msl(const SPIRType &struct_type, uint32_t index) const; @@ -1114,11 +1116,10 @@ class CompilerMSL : public CompilerGLSL uint32_t get_declared_input_matrix_stride_msl(const SPIRType &struct_type, uint32_t index) const; uint32_t get_declared_input_alignment_msl(const SPIRType &struct_type, uint32_t index) const; - const SPIRType &get_physical_member_type(const SPIRType &struct_type, uint32_t index) const; + TypeID get_physical_member_type_id(const SPIRType &struct_type, uint32_t index) const; SPIRType get_presumed_input_type(const SPIRType &struct_type, uint32_t index) const; - uint32_t get_declared_struct_size_msl(const SPIRType &struct_type, bool ignore_alignment = false, - bool ignore_padding = false) const; + uint32_t get_declared_struct_size_msl(const SPIRType &struct_type) const; std::string to_component_argument(uint32_t id); void align_struct(SPIRType &ib_type, std::unordered_set &aligned_structs); diff --git a/3rdparty/spirv-cross/spirv_parser.cpp b/3rdparty/spirv-cross/spirv_parser.cpp index 63431294..d2e7dfa5 100644 --- a/3rdparty/spirv-cross/spirv_parser.cpp +++ b/3rdparty/spirv-cross/spirv_parser.cpp @@ -22,6 +22,7 @@ */ #include "spirv_parser.hpp" +#include "NonSemanticShaderDebugInfo100.h" #include using namespace std; @@ -43,7 +44,7 @@ static bool decoration_is_string(Decoration decoration) { switch (decoration) { - case DecorationHlslSemanticGOOGLE: + case DecorationUserSemantic: return true; default: @@ -137,6 +138,15 @@ void Parser::parse() } forward_pointer_fixups.clear(); + for (auto &source : ir.sources) + { + auto cmp = [](const ParsedIR::Source::Marker &a, const ParsedIR::Source::Marker &b) { + return a.line < b.line; + }; + + std::sort(source.line_markers.begin(), source.line_markers.end(), cmp); + } + if (current_function) SPIRV_CROSS_THROW("Function was not terminated."); if (current_block) @@ -194,7 +204,6 @@ void Parser::parse(const Instruction &instruction) switch (op) { - case OpSourceContinued: case OpSourceExtension: case OpNop: case OpModuleProcessed: @@ -213,38 +222,53 @@ void Parser::parse(const Instruction &instruction) case OpSource: { - ir.source.lang = static_cast(ops[0]); - switch (ir.source.lang) + ir.sources.emplace_back(); + auto &source = ir.sources.back(); + source.lang = static_cast(ops[0]); + + switch (source.lang) { case SourceLanguageESSL: - ir.source.es = true; - ir.source.version = ops[1]; - ir.source.known = true; - ir.source.hlsl = false; + source.es = true; + source.version = ops[1]; + source.known = true; + source.hlsl = false; break; case SourceLanguageGLSL: - ir.source.es = false; - ir.source.version = ops[1]; - ir.source.known = true; - ir.source.hlsl = false; + source.es = false; + source.version = ops[1]; + source.known = true; + source.hlsl = false; break; case SourceLanguageHLSL: // For purposes of cross-compiling, this is GLSL 450. - ir.source.es = false; - ir.source.version = 450; - ir.source.known = true; - ir.source.hlsl = true; + source.es = false; + source.version = 450; + source.known = true; + source.hlsl = true; break; default: - ir.source.known = false; + source.known = false; break; } + + if (length >= 3) + source.file_id = ops[2]; + + if (length >= 4) + source.source = extract_string(ir.spirv, instruction.offset + 3); + break; } + case OpSourceContinued: + if (!ir.sources.empty()) + ir.sources.back().source += extract_string(ir.spirv, instruction.offset); + break; + case OpUndef: { uint32_t result_type = ops[0]; @@ -318,17 +342,70 @@ void Parser::parse(const Instruction &instruction) ir.load_type_width.insert({ ops[1], type->width }); } } - else if (op == OpExtInst) + + if (op == OpExtInst && length > 4) { // Don't want to deal with ForwardRefs here. - auto &ext = get(ops[2]); if (ext.ext == SPIRExtension::NonSemanticShaderDebugInfo) { - // Parse global ShaderDebugInfo we care about. - // Just forward the string information. - if (ops[3] == SPIRExtension::DebugSource) + const auto instr = ops[3]; + if (instr == NonSemanticShaderDebugInfo100DebugSource) + { set(ops[1], get(ops[4]).str); + + ir.sources.emplace_back(); + auto &source = ir.sources.back(); + source.file_id = ops[4]; + source.define_id = ops[1]; + if (length >= 6) + source.source = ir.get(ops[5]).str; + } + else if (instr == NonSemanticShaderDebugInfo100DebugSourceContinued) + { + if (length < 5) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugSourceContinued"); + if (!ir.sources.empty()) + ir.sources.back().source += ir.get(ops[4]).str; + } + else if (instr == NonSemanticShaderDebugInfo100DebugLine) + { + if (length < 9) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugLine"); + auto source_id = ops[4]; + auto line_start = ir.get(ops[5]).scalar_i32(); + auto col_start = ir.get(ops[7]).scalar_i32(); + + for (auto &source : ir.sources) + { + if (source.define_id != source_id) + continue; + + source.line_markers.emplace_back(); + auto &marker = source.line_markers.back(); + marker.line = line_start; + marker.col = col_start; + marker.offset = instruction.offset - 1; + marker.function_id = current_function ? current_function->self : ID(0); + marker.block_id = current_block ? current_block->self : ID(0); + break; + } + } + else if (instr == NonSemanticShaderDebugInfo100DebugLocalVariable) + { + if (length < 11) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugLocalVariable"); + auto &lvar = set(ops[1]); + lvar.name_id = ops[4]; + } + else if (instr == NonSemanticShaderDebugInfo100DebugDeclare) + { + if (length < 7) + SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugDeclare"); + auto &lvar = get(ops[4]); + auto &var = get(ops[5]); + var.debug_local_variables.push_back(lvar.self); + } } } break; @@ -1378,6 +1455,24 @@ void Parser::parse(const Instruction &instruction) current_function->entry_line.line_literal = ops[1]; } } + + uint32_t file = ops[0]; + uint32_t line = ops[1]; + + for (auto &source : ir.sources) + { + if (source.file_id == file) + { + source.line_markers.emplace_back(); + auto &marker = source.line_markers.back(); + marker.line = line; + marker.offset = instruction.offset - 1; + marker.function_id = current_function ? current_function->self : ID(0); + marker.block_id = current_block ? current_block->self : ID(0); + break; + } + } + break; } diff --git a/CMakeLists.txt b/CMakeLists.txt index 4213dc02..5a2d25ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ if (NOT (IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang")) message(STATUS "Downloading glslang ...") find_program(GIT_COMMAND NAMES git REQUIRED) execute_process(COMMAND ${GIT_COMMAND} clone "https://github.com/KhronosGroup/glslang.git" "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang") - execute_process(COMMAND ${GIT_COMMAND} -C "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang" checkout "dffbc79733f63435ae24e73f64384f1374e0dda2") + execute_process(COMMAND ${GIT_COMMAND} -C "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang" checkout "16.2.0") find_program(PYTHON_COMMAND NAMES python3 python REQUIRED) execute_process(COMMAND ${PYTHON_COMMAND} "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang/update_glslang_sources.py" WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang") @@ -82,6 +82,14 @@ if (NOT (IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang")) message(STATUS "Apply ${GLSLANG_PATCH_FILE} to ${GLSLANG_SOURCE_DIR} ...") execute_process(COMMAND ${GIT_COMMAND} -C "${GLSLANG_SOURCE_DIR}" apply --verbose --ignore-whitespace "${GLSLANG_PATCH_FILE}") endif() + +set(GLSLANG_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang") + set(GLSLANG_PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/glslang.patch") + file(TO_CMAKE_PATH "${GLSLANG_SOURCE_DIR}" GLSLANG_SOURCE_DIR) + file(TO_CMAKE_PATH "${GLSLANG_PATCH_FILE}" GLSLANG_PATCH_FILE) + message(STATUS "Apply ${GLSLANG_PATCH_FILE} to ${GLSLANG_SOURCE_DIR} ...") + execute_process(COMMAND ${GIT_COMMAND} -C "${GLSLANG_SOURCE_DIR}" apply --verbose --ignore-whitespace "${GLSLANG_PATCH_FILE}") + add_subdirectory(3rdparty/glslang) add_subdirectory(3rdparty/spirv-cross) add_subdirectory(3rdparty/sx) diff --git a/README.md b/README.md index d069d2df..1a80ba27 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ It uses [glslang](https://github.com/KhronosGroup/glslang) for parsing GLSL and ### 3.5.0 - Add support for running on linux-arm64 +- Update spirv-cross: bf6bb5c(4178) (Until Feb 13, 2026) +- Update glslang to 16.2.0 ### 3.4.0 @@ -29,7 +31,7 @@ It uses [glslang](https://github.com/KhronosGroup/glslang) for parsing GLSL and ### 3.2.0 - Unify and re-enumerate vertex input & uniform variable types (Break changes) -- Update spirv-cross: b8bd9d5(5153) (Until Dec 2, 2025) +- Update spirv-cross: b8bd9d5(4153) (Until Dec 2, 2025) - Update glslang: 0036567(5381) (Until Dec 10, 2025) ### 3.1.1 @@ -48,7 +50,7 @@ It uses [glslang](https://github.com/KhronosGroup/glslang) for parsing GLSL and ### 1.14.0 - Update glslang: dffbc79(5382) (Until Dec 12, 2025) -- Update spirv-cross: b8bd9d5(5153) (Until Dec 2, 2025) +- Update spirv-cross: b8bd9d5(4153) (Until Dec 2, 2025) - Fix spirv code output truncation when --sgs set - Add --profile version support for SPIRV (default: 100) - Remove SPVRemapper linkage diff --git a/glslang.patch b/glslang.patch index e9b99a60..67d5a173 100644 --- a/glslang.patch +++ b/glslang.patch @@ -1,8 +1,8 @@ diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp -index 1a5c40c5..6a09804c 100644 +index ff9c8b04..8a4700fb 100644 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp -@@ -10831,6 +10831,14 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol +@@ -11148,6 +11148,14 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol // default to 0 builder.addDecoration(id, spv::Decoration::Binding, 0); } @@ -30,31 +30,22 @@ index 9fb4f3ff..e12dcc26 100644 GLSLANG_EXPORT void GetSpirvVersion(std::string&); diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp -index dcc9b4e1..724bc141 100644 +index f81faefa..cb81b170 100644 --- a/SPIRV/doc.cpp +++ b/SPIRV/doc.cpp -@@ -350,6 +350,7 @@ const char* DecorationString(int decoration) - case (int)Decoration::HitObjectShaderRecordBufferEXT: return "DecorationHitObjectShaderRecordBufferEXT"; +@@ -356,6 +356,7 @@ const char* DecorationString(int decoration) - case (int)Decoration::SaturatedToLargestFloat8NormalConversionEXT: return "DecorationSaturatedToLargestFloat8NormalConversionEXT"; -+ case 7000: return "SamplerSlot"; // axslcc spec + case (int)Decoration::ArrayStrideIdEXT: return "DecorationArrayStrideIdEXT"; + case (int)Decoration::OffsetIdEXT: return "DecorationOffsetIdEXT"; ++ case (int)Decoration::SamplerSlot: return "SamplerSlot"; // axslcc spec } } diff --git a/SPIRV/spirv.hpp11 b/SPIRV/spirv.hpp11 -index 6f3021e9..57dfe1a1 100644 +index 36a82e7a..95a64e12 100644 --- a/SPIRV/spirv.hpp11 +++ b/SPIRV/spirv.hpp11 -@@ -206,7 +206,7 @@ enum class ExecutionMode : unsigned { - SampleInterlockOrderedEXT = 5368, - SampleInterlockUnorderedEXT = 5369, - ShadingRateInterlockOrderedEXT = 5370, -- ShadingRateInterlockUnorderedEXT = 5371, -+ ShadingRateInterlockUnorderedEXT = 5371, - Shader64BitIndexingEXT = 5427, - SharedLocalMemorySizeINTEL = 5618, - RoundingModeRTPINTEL = 5620, -@@ -653,6 +653,7 @@ enum class Decoration : unsigned { +@@ -657,6 +657,7 @@ enum class Decoration : unsigned { ImplementInRegisterMapINTEL = 6191, CacheControlLoadINTEL = 6442, CacheControlStoreINTEL = 6443, @@ -62,38 +53,11 @@ index 6f3021e9..57dfe1a1 100644 Max = 0x7fffffff, }; -@@ -1199,7 +1200,7 @@ enum class Capability : unsigned { - RayTracingDisplacementMicromapNV = 5409, - RawAccessChainsNV = 5414, - RayTracingSpheresGeometryNV = 5418, -- RayTracingLinearSweptSpheresGeometryNV = 5419, -+ RayTracingLinearSweptSpheresGeometryNV = 5419, - Shader64BitIndexingEXT = 5426, - CooperativeMatrixReductionsNV = 5430, - CooperativeMatrixConversionsNV = 5431, -@@ -3426,7 +3427,7 @@ inline const char* ExecutionModeToString(ExecutionMode value) { - case ExecutionMode::SampleInterlockOrderedEXT: return "SampleInterlockOrderedEXT"; - case ExecutionMode::SampleInterlockUnorderedEXT: return "SampleInterlockUnorderedEXT"; - case ExecutionMode::ShadingRateInterlockOrderedEXT: return "ShadingRateInterlockOrderedEXT"; -- case ExecutionMode::ShadingRateInterlockUnorderedEXT: return "ShadingRateInterlockUnorderedEXT"; -+ case ExecutionMode::ShadingRateInterlockUnorderedEXT: return "ShadingRateInterlockUnorderedEXT"; - case ExecutionMode::Shader64BitIndexingEXT: return "Shader64BitIndexingEXT"; - case ExecutionMode::SharedLocalMemorySizeINTEL: return "SharedLocalMemorySizeINTEL"; - case ExecutionMode::RoundingModeRTPINTEL: return "RoundingModeRTPINTEL"; -@@ -4157,7 +4158,7 @@ inline const char* CapabilityToString(Capability value) { - case Capability::RayTracingDisplacementMicromapNV: return "RayTracingDisplacementMicromapNV"; - case Capability::RawAccessChainsNV: return "RawAccessChainsNV"; - case Capability::RayTracingSpheresGeometryNV: return "RayTracingSpheresGeometryNV"; -- case Capability::RayTracingLinearSweptSpheresGeometryNV: return "RayTracingLinearSweptSpheresGeometryNV"; -+ case Capability::RayTracingLinearSweptSpheresGeometryNV: return "RayTracingLinearSweptSpheresGeometryNV"; - case Capability::Shader64BitIndexingEXT: return "Shader64BitIndexingEXT"; - case Capability::CooperativeMatrixReductionsNV: return "CooperativeMatrixReductionsNV"; - case Capability::CooperativeMatrixConversionsNV: return "CooperativeMatrixConversionsNV"; diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h -index d3124ac8..5580ef25 100644 +index 3fb0c55b..6b6ef437 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h -@@ -929,6 +929,9 @@ public: +@@ -940,6 +940,9 @@ public: unsigned int layoutBinding : 16; static const unsigned int layoutBindingEnd = 0xFFFF; @@ -103,7 +67,7 @@ index d3124ac8..5580ef25 100644 unsigned int layoutIndex : 8; static const unsigned int layoutIndexEnd = 0xFF; -@@ -994,6 +997,7 @@ public: +@@ -1015,6 +1018,7 @@ public: layoutSet = layoutSetEnd; layoutBinding = layoutBindingEnd; @@ -111,7 +75,7 @@ index d3124ac8..5580ef25 100644 layoutAttachment = layoutAttachmentEnd; } -@@ -1027,6 +1031,10 @@ public: +@@ -1048,6 +1052,10 @@ public: { return layoutBinding != layoutBindingEnd; } @@ -135,10 +99,10 @@ index 4eec55b5..caa880fd 100644 #ifdef __cplusplus diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp -index 38ce7bd6..90f1816d 100644 +index 658ca42d..9090ad73 100644 --- a/glslang/MachineIndependent/ParseHelper.cpp +++ b/glslang/MachineIndependent/ParseHelper.cpp -@@ -7075,6 +7075,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi +@@ -7121,6 +7121,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi error(loc, "needs a literal integer", "binding", ""); return; } @@ -149,7 +113,7 @@ index 38ce7bd6..90f1816d 100644 if (id == "constant_id") { requireSpv(loc, "constant_id"); if (value >= (int)TQualifier::layoutSpecConstantIdEnd) { -@@ -7413,6 +7417,8 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie +@@ -7498,6 +7502,8 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie dst.layoutSet = src.layoutSet; if (src.layoutBinding != TQualifier::layoutBindingEnd) dst.layoutBinding = src.layoutBinding; diff --git a/spirv-cross.patch b/spirv-cross.patch index d0373f07..0942ec06 100644 --- a/spirv-cross.patch +++ b/spirv-cross.patch @@ -1,12 +1,12 @@ diff --git a/spirv.h b/spirv.h -index 26bc6d9d..7bb01b3e 100644 +index 26bc6d9d..9f067765 100644 --- a/spirv.h +++ b/spirv.h @@ -645,6 +645,7 @@ typedef enum SpvDecoration_ { SpvDecorationConditionalINTEL = 6247, SpvDecorationCacheControlLoadINTEL = 6442, SpvDecorationCacheControlStoreINTEL = 6443, -+ SpvDecorationSamplerSlot = 7000, // axslcc spec ++ SpvDecorationSamplerSlot = 7000, // axslcc spec SpvDecorationMax = 0x7fffffff, } SpvDecoration; @@ -14,19 +14,19 @@ index 26bc6d9d..7bb01b3e 100644 case SpvDecorationIndex: return "Index"; case SpvDecorationBinding: return "Binding"; case SpvDecorationDescriptorSet: return "DescriptorSet"; -+ case SpvDecorationSamplerSlot: return "SamplerSlot"; // axslcc spec ++ case SpvDecorationSamplerSlot: return "SamplerSlot"; // axslcc spec case SpvDecorationOffset: return "Offset"; case SpvDecorationXfbBuffer: return "XfbBuffer"; case SpvDecorationXfbStride: return "XfbStride"; diff --git a/spirv.hpp b/spirv.hpp -index 086fcc48..1c0a6735 100644 +index 086fcc48..c3ce94c9 100644 --- a/spirv.hpp +++ b/spirv.hpp @@ -641,6 +641,7 @@ enum Decoration { DecorationConditionalINTEL = 6247, DecorationCacheControlLoadINTEL = 6442, DecorationCacheControlStoreINTEL = 6443, -+ DecorationSamplerSlot = 7000, // axslcc spec ++ DecorationSamplerSlot = 7000, // axslcc spec DecorationMax = 0x7fffffff, }; @@ -39,10 +39,10 @@ index 086fcc48..1c0a6735 100644 case DecorationXfbBuffer: return "XfbBuffer"; case DecorationXfbStride: return "XfbStride"; diff --git a/spirv_common.hpp b/spirv_common.hpp -index 02d84230..5e81d9a4 100644 +index cd06f754..1d20d762 100644 --- a/spirv_common.hpp +++ b/spirv_common.hpp -@@ -1798,6 +1798,7 @@ struct Meta +@@ -1814,6 +1814,7 @@ struct Meta uint32_t component = 0; uint32_t set = 0; uint32_t binding = 0; @@ -51,10 +51,10 @@ index 02d84230..5e81d9a4 100644 uint32_t xfb_buffer = 0; uint32_t xfb_stride = 0; diff --git a/spirv_cross_parsed_ir.cpp b/spirv_cross_parsed_ir.cpp -index 1c23ece1..449c6655 100644 +index bb9a5f58..5e1f58a3 100644 --- a/spirv_cross_parsed_ir.cpp +++ b/spirv_cross_parsed_ir.cpp -@@ -431,6 +431,10 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument) +@@ -432,6 +432,10 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument) dec.set = argument; break; @@ -65,7 +65,7 @@ index 1c23ece1..449c6655 100644 case DecorationInputAttachmentIndex: dec.input_attachment = argument; break; -@@ -652,6 +656,8 @@ uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const +@@ -653,6 +657,8 @@ uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const return dec.stream; case DecorationBinding: return dec.binding; @@ -74,7 +74,7 @@ index 1c23ece1..449c6655 100644 case DecorationDescriptorSet: return dec.set; case DecorationInputAttachmentIndex: -@@ -739,6 +745,10 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration) +@@ -740,6 +746,10 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration) dec.set = 0; break; @@ -104,10 +104,10 @@ index f30706f5..e8099602 100644 } } // namespace spirv_cross_util diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp -index f9ce6cb0..21f82263 100644 +index 92363605..c76f2f16 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp -@@ -2387,7 +2387,10 @@ void CompilerGLSL::emit_buffer_block(const SPIRVariable &var) +@@ -2422,7 +2422,10 @@ void CompilerGLSL::emit_buffer_block(const SPIRVariable &var) emit_buffer_block_flattened(var); else if (is_legacy() || (!options.es && options.version == 130) || (ubo_block && options.emit_uniform_buffer_as_plain_uniforms)) @@ -119,7 +119,7 @@ index f9ce6cb0..21f82263 100644 else emit_buffer_block_native(var); } -@@ -10894,6 +10897,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice +@@ -10938,6 +10941,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice string qual_mbr_name = get_member_qualified_name(type_id, index); if (!qual_mbr_name.empty()) expr = qual_mbr_name; @@ -128,7 +128,7 @@ index f9ce6cb0..21f82263 100644 else if (flatten_member_reference) expr += join("_", to_member_name(*type, index)); else -@@ -20290,3 +20295,37 @@ bool CompilerGLSL::has_legacy_nocontract(uint32_t result_type, uint32_t id) cons +@@ -20331,3 +20336,37 @@ bool CompilerGLSL::has_legacy_nocontract(uint32_t result_type, uint32_t id) cons FPFastMathModeAllowReassocMask; return (get_fp_fast_math_flags_for_op(result_type, id) & fp_flags) != fp_flags; } @@ -167,7 +167,7 @@ index f9ce6cb0..21f82263 100644 + +// === axslcc spec diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp -index 98e93ee9..2e2a3fce 100644 +index 709b3ea2..5566b49b 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -156,6 +156,18 @@ public: @@ -189,7 +189,7 @@ index 98e93ee9..2e2a3fce 100644 // If non-zero, controls layout(num_views = N) in; in GL_OVR_multiview2. uint32_t ovr_multiview_view_count = 0; -@@ -1087,6 +1099,11 @@ protected: +@@ -1086,6 +1098,11 @@ protected: uint32_t get_fp_fast_math_flags_for_op(uint32_t result_type, uint32_t id) const; bool has_legacy_nocontract(uint32_t result_type, uint32_t id) const; @@ -202,10 +202,10 @@ index 98e93ee9..2e2a3fce 100644 void init(); diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp -index 098beca5..307388bd 100644 +index a18fa3c6..81bea2a8 100644 --- a/spirv_hlsl.cpp +++ b/spirv_hlsl.cpp -@@ -1434,6 +1434,30 @@ bool CompilerHLSL::is_hlsl_aux_buffer_binding_used(HLSLAuxBinding binding) const +@@ -1455,6 +1455,30 @@ bool CompilerHLSL::is_hlsl_aux_buffer_binding_used(HLSLAuxBinding binding) const return false; } @@ -236,7 +236,7 @@ index 098beca5..307388bd 100644 void CompilerHLSL::emit_composite_constants() { // HLSL cannot declare structs or arrays inline, so we must move them out to -@@ -3970,7 +3994,21 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse) +@@ -3991,7 +4015,21 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse) if (combined_image) sampler_expr = to_non_uniform_aware_expression(combined_image->sampler); else @@ -259,7 +259,7 @@ index 098beca5..307388bd 100644 expr += sampler_expr; } -@@ -4342,13 +4380,16 @@ void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var) +@@ -4363,13 +4401,16 @@ void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var) if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer) { @@ -284,10 +284,10 @@ index 098beca5..307388bd 100644 break; } diff --git a/spirv_hlsl.hpp b/spirv_hlsl.hpp -index 5f9c3139..c7de6af0 100644 +index 0d5181b9..059036f0 100644 --- a/spirv_hlsl.hpp +++ b/spirv_hlsl.hpp -@@ -227,6 +227,11 @@ public: +@@ -230,6 +230,11 @@ public: void unset_hlsl_aux_buffer_binding(HLSLAuxBinding binding); bool is_hlsl_aux_buffer_binding_used(HLSLAuxBinding binding) const; @@ -299,7 +299,7 @@ index 5f9c3139..c7de6af0 100644 private: std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; std::string image_type_hlsl(const SPIRType &type, uint32_t id); -@@ -320,6 +325,8 @@ private: +@@ -323,6 +328,8 @@ private: bool requires_scalar_refract = false; bool requires_scalar_faceforward = false; From 45d8d90151ea7627f916816f7a9a83bfa6857d79 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 25 Feb 2026 22:34:30 +0800 Subject: [PATCH 3/4] Update glslang.patch --- CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a2d25ff..6c936125 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,13 +82,6 @@ if (NOT (IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang")) message(STATUS "Apply ${GLSLANG_PATCH_FILE} to ${GLSLANG_SOURCE_DIR} ...") execute_process(COMMAND ${GIT_COMMAND} -C "${GLSLANG_SOURCE_DIR}" apply --verbose --ignore-whitespace "${GLSLANG_PATCH_FILE}") endif() - -set(GLSLANG_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/3rdparty/glslang") - set(GLSLANG_PATCH_FILE "${CMAKE_CURRENT_LIST_DIR}/glslang.patch") - file(TO_CMAKE_PATH "${GLSLANG_SOURCE_DIR}" GLSLANG_SOURCE_DIR) - file(TO_CMAKE_PATH "${GLSLANG_PATCH_FILE}" GLSLANG_PATCH_FILE) - message(STATUS "Apply ${GLSLANG_PATCH_FILE} to ${GLSLANG_SOURCE_DIR} ...") - execute_process(COMMAND ${GIT_COMMAND} -C "${GLSLANG_SOURCE_DIR}" apply --verbose --ignore-whitespace "${GLSLANG_PATCH_FILE}") add_subdirectory(3rdparty/glslang) add_subdirectory(3rdparty/spirv-cross) From 222ac6e8ed13081e74bdee4d1e2a1c30a433aa65 Mon Sep 17 00:00:00 2001 From: halx99 Date: Wed, 25 Feb 2026 22:39:13 +0800 Subject: [PATCH 4/4] Add missing header --- .../NonSemanticShaderDebugInfo100.h | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h diff --git a/3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h b/3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h new file mode 100644 index 00000000..b276b560 --- /dev/null +++ b/3rdparty/spirv-cross/NonSemanticShaderDebugInfo100.h @@ -0,0 +1,171 @@ +// Copyright (c) 2018-2024 The Khronos Group Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and/or associated documentation files (the "Materials"), +// to deal in the Materials without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Materials, and to permit persons to whom the +// Materials are furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Materials. +// +// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// +// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +// IN THE MATERIALS. + +#ifndef SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ +#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + NonSemanticShaderDebugInfo100Version = 100, + NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff +}; +enum { + NonSemanticShaderDebugInfo100Revision = 6, + NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100Instructions { + NonSemanticShaderDebugInfo100DebugInfoNone = 0, + NonSemanticShaderDebugInfo100DebugCompilationUnit = 1, + NonSemanticShaderDebugInfo100DebugTypeBasic = 2, + NonSemanticShaderDebugInfo100DebugTypePointer = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifier = 4, + NonSemanticShaderDebugInfo100DebugTypeArray = 5, + NonSemanticShaderDebugInfo100DebugTypeVector = 6, + NonSemanticShaderDebugInfo100DebugTypedef = 7, + NonSemanticShaderDebugInfo100DebugTypeFunction = 8, + NonSemanticShaderDebugInfo100DebugTypeEnum = 9, + NonSemanticShaderDebugInfo100DebugTypeComposite = 10, + NonSemanticShaderDebugInfo100DebugTypeMember = 11, + NonSemanticShaderDebugInfo100DebugTypeInheritance = 12, + NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13, + NonSemanticShaderDebugInfo100DebugTypeTemplate = 14, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15, + NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17, + NonSemanticShaderDebugInfo100DebugGlobalVariable = 18, + NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19, + NonSemanticShaderDebugInfo100DebugFunction = 20, + NonSemanticShaderDebugInfo100DebugLexicalBlock = 21, + NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22, + NonSemanticShaderDebugInfo100DebugScope = 23, + NonSemanticShaderDebugInfo100DebugNoScope = 24, + NonSemanticShaderDebugInfo100DebugInlinedAt = 25, + NonSemanticShaderDebugInfo100DebugLocalVariable = 26, + NonSemanticShaderDebugInfo100DebugInlinedVariable = 27, + NonSemanticShaderDebugInfo100DebugDeclare = 28, + NonSemanticShaderDebugInfo100DebugValue = 29, + NonSemanticShaderDebugInfo100DebugOperation = 30, + NonSemanticShaderDebugInfo100DebugExpression = 31, + NonSemanticShaderDebugInfo100DebugMacroDef = 32, + NonSemanticShaderDebugInfo100DebugMacroUndef = 33, + NonSemanticShaderDebugInfo100DebugImportedEntity = 34, + NonSemanticShaderDebugInfo100DebugSource = 35, + NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101, + NonSemanticShaderDebugInfo100DebugSourceContinued = 102, + NonSemanticShaderDebugInfo100DebugLine = 103, + NonSemanticShaderDebugInfo100DebugNoLine = 104, + NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105, + NonSemanticShaderDebugInfo100DebugStoragePath = 106, + NonSemanticShaderDebugInfo100DebugEntryPoint = 107, + NonSemanticShaderDebugInfo100DebugTypeMatrix = 108, + NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff +}; + + +enum NonSemanticShaderDebugInfo100DebugInfoFlags { + NonSemanticShaderDebugInfo100None = 0x0000, + NonSemanticShaderDebugInfo100FlagIsProtected = 0x01, + NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02, + NonSemanticShaderDebugInfo100FlagIsPublic = 0x03, + NonSemanticShaderDebugInfo100FlagIsLocal = 0x04, + NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08, + NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10, + NonSemanticShaderDebugInfo100FlagArtificial = 0x20, + NonSemanticShaderDebugInfo100FlagExplicit = 0x40, + NonSemanticShaderDebugInfo100FlagPrototyped = 0x80, + NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100, + NonSemanticShaderDebugInfo100FlagStaticMember = 0x200, + NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400, + NonSemanticShaderDebugInfo100FlagLValueReference = 0x800, + NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000, + NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000, + NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000, + NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000, + NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000, + NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000, + NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100BuildIdentifierFlags { + NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01, + NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding { + NonSemanticShaderDebugInfo100Unspecified = 0, + NonSemanticShaderDebugInfo100Address = 1, + NonSemanticShaderDebugInfo100Boolean = 2, + NonSemanticShaderDebugInfo100Float = 3, + NonSemanticShaderDebugInfo100Signed = 4, + NonSemanticShaderDebugInfo100SignedChar = 5, + NonSemanticShaderDebugInfo100Unsigned = 6, + NonSemanticShaderDebugInfo100UnsignedChar = 7, + NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugCompositeType { + NonSemanticShaderDebugInfo100Class = 0, + NonSemanticShaderDebugInfo100Structure = 1, + NonSemanticShaderDebugInfo100Union = 2, + NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugTypeQualifier { + NonSemanticShaderDebugInfo100ConstType = 0, + NonSemanticShaderDebugInfo100VolatileType = 1, + NonSemanticShaderDebugInfo100RestrictType = 2, + NonSemanticShaderDebugInfo100AtomicType = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugOperation { + NonSemanticShaderDebugInfo100Deref = 0, + NonSemanticShaderDebugInfo100Plus = 1, + NonSemanticShaderDebugInfo100Minus = 2, + NonSemanticShaderDebugInfo100PlusUconst = 3, + NonSemanticShaderDebugInfo100BitPiece = 4, + NonSemanticShaderDebugInfo100Swap = 5, + NonSemanticShaderDebugInfo100Xderef = 6, + NonSemanticShaderDebugInfo100StackValue = 7, + NonSemanticShaderDebugInfo100Constu = 8, + NonSemanticShaderDebugInfo100Fragment = 9, + NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugImportedEntity { + NonSemanticShaderDebugInfo100ImportedModule = 0, + NonSemanticShaderDebugInfo100ImportedDeclaration = 1, + NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff +}; + + +#ifdef __cplusplus +} +#endif + +#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_