diff --git a/.gitmodules b/.gitmodules
index 696e6e3d7e..01e2ced8b6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -18,3 +18,8 @@
url = https://github.com/libusb/libusb.git
branch = master
shallow = true
+[submodule "Externals/spirv_cross/SPIRV-Cross"]
+ path = Externals/spirv_cross/SPIRV-Cross
+ url = https://github.com/KhronosGroup/SPIRV-Cross.git
+ branch = master
+ shallow = true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bf47e74185..ae835b0f39 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -660,6 +660,7 @@ else()
endif()
add_subdirectory(Externals/imgui)
add_subdirectory(Externals/glslang)
+add_subdirectory(Externals/spirv_cross)
if(ENABLE_VULKAN)
add_definitions(-DHAS_VULKAN)
diff --git a/Externals/ExternalsReferenceAll.props b/Externals/ExternalsReferenceAll.props
index b74dc4d421..f3a19282e4 100644
--- a/Externals/ExternalsReferenceAll.props
+++ b/Externals/ExternalsReferenceAll.props
@@ -82,6 +82,9 @@
{ec082900-b4d8-42e9-9663-77f02f6936ae}
+
+ {3d780617-ec8c-4721-b9fd-dfc9bb658c7c}
+
{677ea016-1182-440c-9345-dc88d1e98c0c}
diff --git a/Externals/spirv_cross/CMakeLists.txt b/Externals/spirv_cross/CMakeLists.txt
new file mode 100644
index 0000000000..522f8b5073
--- /dev/null
+++ b/Externals/spirv_cross/CMakeLists.txt
@@ -0,0 +1,52 @@
+set(SRCS
+ SPIRV-Cross/GLSL.std.450.h
+ SPIRV-Cross/spirv.h
+ SPIRV-Cross/spirv.hpp
+ SPIRV-Cross/spirv_cfg.cpp
+ SPIRV-Cross/spirv_cfg.hpp
+ SPIRV-Cross/spirv_common.hpp
+ SPIRV-Cross/spirv_cpp.cpp
+ SPIRV-Cross/spirv_cpp.hpp
+ SPIRV-Cross/spirv_cross.cpp
+ SPIRV-Cross/spirv_cross.hpp
+ SPIRV-Cross/spirv_cross_c.cpp
+ SPIRV-Cross/spirv_cross_c.h
+ SPIRV-Cross/spirv_cross_containers.hpp
+ SPIRV-Cross/spirv_cross_error_handling.hpp
+ SPIRV-Cross/spirv_cross_parsed_ir.cpp
+ SPIRV-Cross/spirv_cross_parsed_ir.hpp
+ SPIRV-Cross/spirv_cross_util.cpp
+ SPIRV-Cross/spirv_cross_util.hpp
+ SPIRV-Cross/spirv_glsl.cpp
+ SPIRV-Cross/spirv_glsl.hpp
+ SPIRV-Cross/spirv_hlsl.cpp
+ SPIRV-Cross/spirv_hlsl.hpp
+ SPIRV-Cross/spirv_msl.cpp
+ SPIRV-Cross/spirv_msl.hpp
+ SPIRV-Cross/spirv_parser.cpp
+ SPIRV-Cross/spirv_parser.hpp
+ SPIRV-Cross/spirv_reflect.cpp
+ SPIRV-Cross/spirv_reflect.hpp
+)
+
+if(NOT MSVC)
+# spirv_cross requires C++11 at a minimum to compile.
+add_compile_options(-std=c++11)
+
+# Silence some warnings that occur frequently to reduce noise in build logs.
+add_compile_options(-Wno-shadow)
+add_compile_options(-Wno-reorder)
+add_compile_options(-Wno-sign-compare)
+add_compile_options(-Wno-parentheses)
+add_compile_options(-Wno-unused-variable)
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ add_compile_options(-Wno-unused-but-set-variable)
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ add_compile_options(-Wno-missing-variable-declarations)
+endif()
+endif()
+
+add_library(spirv_cross STATIC ${SRCS})
+
+target_compile_definitions(spirv_cross PUBLIC SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS)
+target_include_directories(spirv_cross PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Cross/include ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Cross)
diff --git a/Externals/spirv_cross/SPIRV-Cross b/Externals/spirv_cross/SPIRV-Cross
new file mode 160000
index 0000000000..50b4d5389b
--- /dev/null
+++ b/Externals/spirv_cross/SPIRV-Cross
@@ -0,0 +1 @@
+Subproject commit 50b4d5389b6a06f86fb63a2848e1a7da6d9755ca
diff --git a/Externals/spirv_cross/spirv_cross.vcxproj b/Externals/spirv_cross/spirv_cross.vcxproj
new file mode 100644
index 0000000000..de93abda1b
--- /dev/null
+++ b/Externals/spirv_cross/spirv_cross.vcxproj
@@ -0,0 +1,53 @@
+
+
+
+
+
+ {3d780617-ec8c-4721-b9fd-dfc9bb658c7c}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/VSProps/Base.props b/Source/VSProps/Base.props
index aadace92ee..49f546d39f 100644
--- a/Source/VSProps/Base.props
+++ b/Source/VSProps/Base.props
@@ -38,6 +38,7 @@
$(ExternalsDir)fmt\include;%(AdditionalIncludeDirectories)
$(ExternalsDir)GL;%(AdditionalIncludeDirectories)
$(ExternalsDir)glslang;$(ExternalsDir)glslang\StandAlone;$(ExternalsDir)glslang\glslang\Public;$(ExternalsDir)glslang\SPIRV;%(AdditionalIncludeDirectories)
+ $(ExternalsDir)spirv_cross\SPIRV-Cross;%(AdditionalIncludeDirectories)
$(ExternalsDir)imgui;%(AdditionalIncludeDirectories)
$(ExternalsDir)liblzma\api;%(AdditionalIncludeDirectories)
$(ExternalsDir)libpng;%(AdditionalIncludeDirectories)
@@ -89,6 +90,7 @@
HAS_VULKAN;%(PreprocessorDefinitions)
HAS_LIBMGBA;%(PreprocessorDefinitions)
AUTOUPDATE=1;%(PreprocessorDefinitions)
+ SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS;%(PreprocessorDefinitions)
diff --git a/Source/dolphin-emu.sln b/Source/dolphin-emu.sln
index 853465535f..89df520d9b 100644
--- a/Source/dolphin-emu.sln
+++ b/Source/dolphin-emu.sln
@@ -79,6 +79,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mgba", "..\Externals\mGBA\m
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\Externals\fmt\fmt.vcxproj", "{4BC5A148-0AB3-440F-A980-A29B4B999190}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spirv_cross", "..\Externals\spirv_cross\spirv_cross.vcxproj", "{3d780617-ec8c-4721-b9fd-dfc9bb658c7c}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -379,6 +381,14 @@ Global
{4BC5A148-0AB3-440F-A980-A29B4B999190}.Release|ARM64.Build.0 = Release|ARM64
{4BC5A148-0AB3-440F-A980-A29B4B999190}.Release|x64.ActiveCfg = Release|x64
{4BC5A148-0AB3-440F-A980-A29B4B999190}.Release|x64.Build.0 = Release|x64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|ARM64.Build.0 = Debug|ARM64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|x64.ActiveCfg = Debug|x64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Debug|x64.Build.0 = Debug|x64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|ARM64.ActiveCfg = Release|ARM64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|ARM64.Build.0 = Release|ARM64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|x64.ActiveCfg = Release|x64
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -411,6 +421,7 @@ Global
{1BEA10F3-80CE-4BC4-9331-5769372CDF99} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{864C4C8E-296D-3DBC-AD83-F1D5CB6E8EC6} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
{4BC5A148-0AB3-440F-A980-A29B4B999190} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
+ {3D780617-EC8C-4721-B9FD-DFC9BB658C7C} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {64B0A343-3B94-4522-9C24-6937FE5EFB22}