diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index be7aac2..986e7e1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,6 +14,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
+ with:
+ submodules: recursive
- name: Set up MSVC environment
uses: microsoft/setup-msbuild@v2
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..d7451d5
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,12 @@
+[submodule "Dependencies/volk"]
+ path = Dependencies/volk
+ url = https://github.com/zeux/volk
+[submodule "Dependencies/dxvk"]
+ path = Dependencies/dxvk
+ url = https://github.com/doitsujin/dxvk
+[submodule "Dependencies/Vulkan-Headers"]
+ path = Dependencies/Vulkan-Headers
+ url = https://github.com/KhronosGroup/Vulkan-Headers
+[submodule "Dependencies/FFmpeg/include/FFmpeg"]
+ path = Dependencies/FFmpeg/include/FFmpeg
+ url = https://git.ffmpeg.org/ffmpeg.git
diff --git a/Dependencies/FFmpeg/include/FFmpeg b/Dependencies/FFmpeg/include/FFmpeg
new file mode 160000
index 0000000..ff63d48
--- /dev/null
+++ b/Dependencies/FFmpeg/include/FFmpeg
@@ -0,0 +1 @@
+Subproject commit ff63d4865bc553ca58b923d77df566b6979d2f2d
diff --git a/Dependencies/FFmpeg/include/libavcodec/version.h b/Dependencies/FFmpeg/include/libavcodec/version.h
new file mode 100644
index 0000000..9d910cf
--- /dev/null
+++ b/Dependencies/FFmpeg/include/libavcodec/version.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_VERSION_H
+#define AVCODEC_VERSION_H
+
+/**
+ * @file
+ * @ingroup libavc
+ * Libavcodec version macros.
+ */
+
+#include "libavutil/version.h"
+
+#include "version_major.h"
+
+#define LIBAVCODEC_VERSION_MINOR 23
+#define LIBAVCODEC_VERSION_MICRO 102
+
+#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
+ LIBAVCODEC_VERSION_MINOR, \
+ LIBAVCODEC_VERSION_MICRO)
+#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \
+ LIBAVCODEC_VERSION_MINOR, \
+ LIBAVCODEC_VERSION_MICRO)
+#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT
+
+#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION)
+
+#endif /* AVCODEC_VERSION_H */
diff --git a/Dependencies/FFmpeg/include/libavcodec/version_major.h b/Dependencies/FFmpeg/include/libavcodec/version_major.h
new file mode 100644
index 0000000..5eed53e
--- /dev/null
+++ b/Dependencies/FFmpeg/include/libavcodec/version_major.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_VERSION_MAJOR_H
+#define AVCODEC_VERSION_MAJOR_H
+
+/**
+ * @file
+ * @ingroup libavc
+ * Libavcodec version macros.
+ */
+
+#define LIBAVCODEC_VERSION_MAJOR 62
+
+/**
+ * FF_API_* defines may be placed below to indicate public API that will be
+ * dropped at a future version bump. The defines themselves are not part of
+ * the public API and may change, break or disappear at any time.
+ *
+ * @note, when bumping the major version it is recommended to manually
+ * disable each FF_API_* in its own commit instead of disabling them all
+ * at once through the bump. This improves the git bisect-ability of the change.
+ */
+
+#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 63)
+
+#define FF_API_V408_CODECID (LIBAVCODEC_VERSION_MAJOR < 63)
+#define FF_API_CODEC_PROPS (LIBAVCODEC_VERSION_MAJOR < 63)
+#define FF_API_EXR_GAMMA (LIBAVCODEC_VERSION_MAJOR < 63)
+
+#define FF_API_NVDEC_OLD_PIX_FMTS (LIBAVCODEC_VERSION_MAJOR < 63)
+
+#define FF_API_PARSER_PRIVATE (LIBAVCODEC_VERSION_MAJOR < 63)
+#define FF_API_PARSER_CODECID (LIBAVCODEC_VERSION_MAJOR < 63)
+
+// reminder to remove the OMX encoder on next major bump
+#define FF_CODEC_OMX (LIBAVCODEC_VERSION_MAJOR < 63)
+// reminder to remove Sonic Lossy/Lossless encoders on next major bump
+#define FF_CODEC_SONIC_ENC (LIBAVCODEC_VERSION_MAJOR < 63)
+// reminder to remove Sonic decoder on next-next major bump
+#define FF_CODEC_SONIC_DEC (LIBAVCODEC_VERSION_MAJOR < 63)
+
+#endif /* AVCODEC_VERSION_MAJOR_H */
diff --git a/Dependencies/FFmpeg/include/libavformat/version.h b/Dependencies/FFmpeg/include/libavformat/version.h
new file mode 100644
index 0000000..1d3a538
--- /dev/null
+++ b/Dependencies/FFmpeg/include/libavformat/version.h
@@ -0,0 +1,47 @@
+/*
+ * Version macros.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_VERSION_H
+#define AVFORMAT_VERSION_H
+
+/**
+ * @file
+ * @ingroup libavf
+ * Libavformat version macros
+ */
+
+#include "libavutil/version.h"
+
+#include "version_major.h"
+
+#define LIBAVFORMAT_VERSION_MINOR 8
+#define LIBAVFORMAT_VERSION_MICRO 102
+
+#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
+ LIBAVFORMAT_VERSION_MINOR, \
+ LIBAVFORMAT_VERSION_MICRO)
+#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \
+ LIBAVFORMAT_VERSION_MINOR, \
+ LIBAVFORMAT_VERSION_MICRO)
+#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT
+
+#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION)
+
+#endif /* AVFORMAT_VERSION_H */
diff --git a/Dependencies/FFmpeg/include/libavformat/version_major.h b/Dependencies/FFmpeg/include/libavformat/version_major.h
new file mode 100644
index 0000000..c2f6e16
--- /dev/null
+++ b/Dependencies/FFmpeg/include/libavformat/version_major.h
@@ -0,0 +1,52 @@
+/*
+ * Version macros.
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFORMAT_VERSION_MAJOR_H
+#define AVFORMAT_VERSION_MAJOR_H
+
+/**
+ * @file
+ * @ingroup libavf
+ * Libavformat version macros
+ */
+
+// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
+// Also please add any ticket numbers that you believe might be affected here
+#define LIBAVFORMAT_VERSION_MAJOR 62
+
+/**
+ * FF_API_* defines may be placed below to indicate public API that will be
+ * dropped at a future version bump. The defines themselves are not part of
+ * the public API and may change, break or disappear at any time.
+ *
+ * @note, when bumping the major version it is recommended to manually
+ * disable each FF_API_* in its own commit instead of disabling them all
+ * at once through the bump. This improves the git bisect-ability of the change.
+ *
+ */
+#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 63)
+
+#define FF_API_INTERNAL_TIMING (LIBAVFORMAT_VERSION_MAJOR < 63)
+
+#define FF_API_NO_DEFAULT_TLS_VERIFY (LIBAVFORMAT_VERSION_MAJOR < 63)
+
+#define FF_API_R_FRAME_RATE 1
+
+#endif /* AVFORMAT_VERSION_MAJOR_H */
diff --git a/Dependencies/FFmpeg/include/libavutil/avconfig.h b/Dependencies/FFmpeg/include/libavutil/avconfig.h
new file mode 100644
index 0000000..c289fbb
--- /dev/null
+++ b/Dependencies/FFmpeg/include/libavutil/avconfig.h
@@ -0,0 +1,6 @@
+/* Generated by ffmpeg configure */
+#ifndef AVUTIL_AVCONFIG_H
+#define AVUTIL_AVCONFIG_H
+#define AV_HAVE_BIGENDIAN 0
+#define AV_HAVE_FAST_UNALIGNED 1
+#endif /* AVUTIL_AVCONFIG_H */
diff --git a/Dependencies/FFmpeg/include/libavutil/version.h b/Dependencies/FFmpeg/include/libavutil/version.h
new file mode 100644
index 0000000..9ed3879
--- /dev/null
+++ b/Dependencies/FFmpeg/include/libavutil/version.h
@@ -0,0 +1,121 @@
+/*
+ * copyright (c) 2003 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * @ingroup lavu
+ * Libavutil version macros
+ */
+
+#ifndef AVUTIL_VERSION_H
+#define AVUTIL_VERSION_H
+
+#include "macros.h"
+
+/**
+ * @addtogroup version_utils
+ *
+ * Useful to check and match library version in order to maintain
+ * backward compatibility.
+ *
+ * The FFmpeg libraries follow a versioning scheme very similar to
+ * Semantic Versioning (http://semver.org/)
+ * The difference is that the component called PATCH is called MICRO in FFmpeg
+ * and its value is reset to 100 instead of 0 to keep it above or equal to 100.
+ * Also we do not increase MICRO for every bugfix or change in git master.
+ *
+ * Prior to FFmpeg 3.2 point releases did not change any lib version number to
+ * avoid aliassing different git master checkouts.
+ * Starting with FFmpeg 3.2, the released library versions will occupy
+ * a separate MAJOR.MINOR that is not used on the master development branch.
+ * That is if we branch a release of master 55.10.123 we will bump to 55.11.100
+ * for the release and master will continue at 55.12.100 after it. Each new
+ * point release will then bump the MICRO improving the usefulness of the lib
+ * versions.
+ *
+ * @{
+ */
+
+#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c))
+#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c
+#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c)
+
+/**
+ * Extract version components from the full ::AV_VERSION_INT int as returned
+ * by functions like ::avformat_version() and ::avcodec_version()
+ */
+#define AV_VERSION_MAJOR(a) ((a) >> 16)
+#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8)
+#define AV_VERSION_MICRO(a) ((a) & 0xFF)
+
+/**
+ * @}
+ */
+
+/**
+ * @defgroup lavu_ver Version and Build diagnostics
+ *
+ * Macros and function useful to check at compile time and at runtime
+ * which version of libavutil is in use.
+ *
+ * @{
+ */
+
+#define LIBAVUTIL_VERSION_MAJOR 60
+#define LIBAVUTIL_VERSION_MINOR 23
+#define LIBAVUTIL_VERSION_MICRO 100
+
+#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
+ LIBAVUTIL_VERSION_MINOR, \
+ LIBAVUTIL_VERSION_MICRO)
+#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \
+ LIBAVUTIL_VERSION_MINOR, \
+ LIBAVUTIL_VERSION_MICRO)
+#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT
+
+#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION)
+
+/**
+ * @defgroup lavu_depr_guards Deprecation Guards
+ * FF_API_* defines may be placed below to indicate public API that will be
+ * dropped at a future version bump. The defines themselves are not part of
+ * the public API and may change, break or disappear at any time.
+ *
+ * @note, when bumping the major version it is recommended to manually
+ * disable each FF_API_* in its own commit instead of disabling them all
+ * at once through the bump. This improves the git bisect-ability of the change.
+ *
+ * @{
+ */
+
+#define FF_API_MOD_UINTP2 (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_RISCV_FD_ZBA (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_VULKAN_FIXED_QUEUES (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_OPT_INT_LIST (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_OPT_PTR (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_CPU_FLAG_FORCE (LIBAVUTIL_VERSION_MAJOR < 61)
+#define FF_API_DOVI_L11_INVALID_PROPS (LIBAVUTIL_VERSION_MAJOR < 61)
+
+/**
+ * @}
+ * @}
+ */
+
+#endif /* AVUTIL_VERSION_H */
diff --git a/Dependencies/FFmpeg/lib/avcodec.lib b/Dependencies/FFmpeg/lib/avcodec.lib
new file mode 100644
index 0000000..16b0be4
Binary files /dev/null and b/Dependencies/FFmpeg/lib/avcodec.lib differ
diff --git a/Dependencies/FFmpeg/lib/avformat.lib b/Dependencies/FFmpeg/lib/avformat.lib
new file mode 100644
index 0000000..27fa8c5
Binary files /dev/null and b/Dependencies/FFmpeg/lib/avformat.lib differ
diff --git a/Dependencies/FFmpeg/lib/avutil.lib b/Dependencies/FFmpeg/lib/avutil.lib
new file mode 100644
index 0000000..37c4b42
Binary files /dev/null and b/Dependencies/FFmpeg/lib/avutil.lib differ
diff --git a/Dependencies/Vulkan-Headers b/Dependencies/Vulkan-Headers
new file mode 160000
index 0000000..b5c8f99
--- /dev/null
+++ b/Dependencies/Vulkan-Headers
@@ -0,0 +1 @@
+Subproject commit b5c8f996196ba4aa6d8f97e52b5d3b6e70f7e4e2
diff --git a/Dependencies/dxvk b/Dependencies/dxvk
new file mode 160000
index 0000000..c27ef1c
--- /dev/null
+++ b/Dependencies/dxvk
@@ -0,0 +1 @@
+Subproject commit c27ef1c43a93741ec1e8d1dc55b6bcf2444a471f
diff --git a/Dependencies/volk b/Dependencies/volk
new file mode 160000
index 0000000..d979819
--- /dev/null
+++ b/Dependencies/volk
@@ -0,0 +1 @@
+Subproject commit d979819fd03de3a7606d6e23d6ff4968942599da
diff --git a/Source/DivaModLoader/CodeLoader.cpp b/Source/DivaModLoader/CodeLoader.cpp
index 2bb1ee9..201950c 100644
--- a/Source/DivaModLoader/CodeLoader.cpp
+++ b/Source/DivaModLoader/CodeLoader.cpp
@@ -3,6 +3,7 @@
#include "Context.h"
#include "SigScan.h"
#include "Utilities.h"
+#include "MoviePlayer.h"
// Stores the current directory, and reverts it back to the original when it exits the current scope.
struct CurrentDirectoryGuard
@@ -95,9 +96,10 @@ HOOK(HRESULT, WINAPI, D3D11CreateDeviceAndSwapChain, /* address set in init due
if (FAILED(result))
return result;
- if (!CodeLoader::d3dInitEvents.empty() && ppSwapChain && *ppSwapChain &&
+ if (ppSwapChain && *ppSwapChain &&
ppDevice && *ppDevice && ppImmediateContext && *ppImmediateContext)
{
+ MoviePlayer::d3dInit(*ppSwapChain, *ppDevice, *ppImmediateContext);
CurrentDirectoryGuard guard;
for (auto& event : CodeLoader::d3dInitEvents)
@@ -201,14 +203,11 @@ void CodeLoader::init()
}
}
- if (!d3dInitEvents.empty() || !onFrameEvents.empty() || !onResizeEvents.empty())
- {
- // load import address manually for RenderDoc compatibility
- originalD3D11CreateDeviceAndSwapChain =
- *(D3D11CreateDeviceAndSwapChainDelegate**)readInstrPtr(sigD3D11CreateDeviceAndSwapChain(), 0, 0x6);
+ // load import address manually for RenderDoc compatibility
+ originalD3D11CreateDeviceAndSwapChain =
+ *(D3D11CreateDeviceAndSwapChainDelegate**)readInstrPtr(sigD3D11CreateDeviceAndSwapChain(), 0, 0x6);
- INSTALL_HOOK(D3D11CreateDeviceAndSwapChain);
- }
+ INSTALL_HOOK(D3D11CreateDeviceAndSwapChain);
}
// Gets called during WinMain.
diff --git a/Source/DivaModLoader/Context.cpp b/Source/DivaModLoader/Context.cpp
index 1adbfa1..20574f7 100644
--- a/Source/DivaModLoader/Context.cpp
+++ b/Source/DivaModLoader/Context.cpp
@@ -12,6 +12,7 @@
#include "Utilities.h"
#include "PvLoader.h"
#include "ThumbnailLoader.h"
+#include "MoviePlayer.h"
HRESULT(*originalDirectInput8Create)(HINSTANCE, DWORD, REFIID, LPVOID*, LPUNKNOWN);
extern "C" __declspec(dllexport) HRESULT DirectInput8Create(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter)
@@ -70,6 +71,7 @@ void Context::preInit()
}
INSTALL_HOOK(CrtMain);
+ MoviePlayer::preInit();
}
void Context::init()
@@ -108,4 +110,5 @@ void Context::postInit()
CodeLoader::postInit();
PvLoader::init();
ThumbnailLoader::init();
+ MoviePlayer::init();
}
diff --git a/Source/DivaModLoader/DivaModLoader.vcxproj b/Source/DivaModLoader/DivaModLoader.vcxproj
index 8658c65..b76d090 100644
--- a/Source/DivaModLoader/DivaModLoader.vcxproj
+++ b/Source/DivaModLoader/DivaModLoader.vcxproj
@@ -58,7 +58,7 @@
Disabled
true
true
- ..\..\Dependencies\Detours\include;..\..\Dependencies;%(AdditionalIncludeDirectories)
+ ..\..\Dependencies\Detours\include;..\..\Dependencies\FFmpeg\include;..\..\Dependencies\FFmpeg\include\FFmpeg;..\..\Dependencies\volk;..\..\Dependencies\dxvk\include\spirv\include;..\..\Dependencies\Vulkan-Headers\include;..\..\Dependencies;%(AdditionalIncludeDirectories)
Use
Pch.h
Pch.h
@@ -68,8 +68,8 @@
Console
- detours.lib;syelog.lib;%(AdditionalDependencies)
- ..\..\Dependencies\Detours\lib
+ detours.lib;syelog.lib;avcodec.lib;avformat.lib;avutil.lib;bcrypt.lib;%(AdditionalDependencies)
+ ..\..\Dependencies\Detours\lib;..\..\Dependencies\FFmpeg\lib
@@ -80,7 +80,7 @@
true
true
true
- ..\..\Dependencies\Detours\include;..\..\Dependencies;%(AdditionalIncludeDirectories)
+ ..\..\Dependencies\Detours\include;..\..\Dependencies\FFmpeg\include;..\..\Dependencies\FFmpeg\include\FFmpeg;..\..\Dependencies\volk;..\..\Dependencies\dxvk\include\spirv\include;..\..\Dependencies\Vulkan-Headers\include;..\..\Dependencies;%(AdditionalIncludeDirectories)
Use
Pch.h
Pch.h
@@ -95,8 +95,8 @@
Console
true
true
- detours.lib;syelog.lib;%(AdditionalDependencies)
- ..\..\Dependencies\Detours\lib
+ detours.lib;syelog.lib;avcodec.lib;avformat.lib;avutil.lib;bcrypt.lib;%(AdditionalDependencies)
+ ..\..\Dependencies\Detours\lib;..\..\Dependencies\FFmpeg\lib
@@ -107,6 +107,7 @@
+
@@ -126,6 +127,9 @@
+
+ $(IntDir);%(AdditionalIncludeDirectories)
+
Create
@@ -146,6 +150,19 @@
Document
+
+
+ false
+ fxc /T vs_5_0 /E vs /Fh $(IntDir)%(Filename)_vs.fxh /Vn vs_bytecode /D BT709 /DFULL %(Identity)
+fxc /T ps_5_0 /E ps /Fh $(IntDir)%(Filename)_bt601_full.fxh /Vn bt601_full_bytecode /D BT601 /DFULL %(Identity)
+fxc /T ps_5_0 /E ps /Fh $(IntDir)%(Filename)_bt601_limited.fxh /Vn bt601_limited_bytecode /D BT601 /DLIMITED %(Identity)
+fxc /T ps_5_0 /E ps /Fh $(IntDir)%(Filename)_bt709_full.fxh /Vn bt709_full_bytecode /D BT709 /DFULL %(Identity)
+fxc /T ps_5_0 /E ps /Fh $(IntDir)%(Filename)_bt709_limited.fxh /Vn bt709_limited_bytecode /D BT709 /DLIMITED %(Identity)
+fxc /T ps_5_0 /E ps /Fh $(IntDir)%(Filename)_bt2020_full.fxh /Vn bt2020_full_bytecode /D BT2020 /DFULL %(Identity)
+fxc /T ps_5_0 /E ps /Fh $(IntDir)%(Filename)_bt2020_limited.fxh /Vn bt2020_limited_bytecode /D BT2020 /DLIMITED %(Identity)
+ $(IntDir)%(Filename)_vs.fxh;$(IntDir)%(Filename)_bt601_full.fxh;$(IntDir)%(Filename)_bt601_limited.fxh;$(IntDir)%(Filename)_bt709_full.fxh;$(IntDir)%(Filename)_bt709_limited.fxh;$(IntDir)%(Filename)_bt2020_full.fxh;$(IntDir)%(Filename)_bt2020_limited.fxh
+
+
diff --git a/Source/DivaModLoader/DivaModLoader.vcxproj.filters b/Source/DivaModLoader/DivaModLoader.vcxproj.filters
index bedc235..82a8ce2 100644
--- a/Source/DivaModLoader/DivaModLoader.vcxproj.filters
+++ b/Source/DivaModLoader/DivaModLoader.vcxproj.filters
@@ -18,6 +18,7 @@
+
@@ -35,6 +36,7 @@
+
@@ -42,4 +44,7 @@
+
+
+
\ No newline at end of file
diff --git a/Source/DivaModLoader/MoviePlayer.cpp b/Source/DivaModLoader/MoviePlayer.cpp
new file mode 100644
index 0000000..2da4d1d
--- /dev/null
+++ b/Source/DivaModLoader/MoviePlayer.cpp
@@ -0,0 +1,2016 @@
+#include "MoviePlayer.h"
+#include "MoviePlayer_vs.fxh";
+#include "MoviePlayer_bt601_full.fxh"
+#include "MoviePlayer_bt601_limited.fxh"
+#include "MoviePlayer_bt709_full.fxh"
+#include "MoviePlayer_bt709_limited.fxh"
+#include "MoviePlayer_bt2020_full.fxh"
+#include "MoviePlayer_bt2020_limited.fxh"
+
+#include "Utilities.h"
+#include "Types.h"
+#include "Context.h"
+
+bool vulkan = false;
+
+IDXGISwapChain *d3d11SwapChain;
+ID3D11Device* d3d11Device;
+ID3D11DeviceContext* d3d11DeviceContext;
+
+ID3D11VertexShader* shader_vs;
+ID3D11PixelShader* shader_bt601_full;
+ID3D11PixelShader* shader_bt601_limited;
+ID3D11PixelShader* shader_bt709_full;
+ID3D11PixelShader* shader_bt709_limited;
+ID3D11PixelShader* shader_bt2020_full;
+ID3D11PixelShader* shader_bt2020_limited;
+
+VkInstance vkInstance;
+VkPhysicalDevice vkPhysDevice;
+VkDevice vkDevice;
+uint32_t vkVersion;
+
+std::vector vkInstanceExtensions;
+std::vector vkDeviceExtensions;
+VkPhysicalDeviceFeatures2 vkDeviceFeatures;
+std::vector vkQueueFamilies;
+
+struct Vec2 {
+ float x;
+ float y;
+};
+
+struct Vec3 {
+ float x;
+ float y;
+ float z;
+};
+
+struct Vec4 {
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+struct Mat4 {
+ Vec4 x;
+ Vec4 y;
+ Vec4 z;
+ Vec4 w;
+};
+
+struct DirectXTexture {
+ int32_t ref_count;
+ DirectXTexture* free_next;
+ ID3D11Texture2D* texture;
+ ID3D11ShaderResourceView* resource_view;
+ int32_t format;
+ int32_t internal_format;
+ int32_t flags;
+ int32_t width;
+ int32_t height;
+ int32_t mip_levels;
+};
+
+struct Texture {
+ int32_t ref_count;
+ int32_t id;
+ int32_t flags;
+ int16_t width;
+ int16_t height;
+ uint32_t target;
+ uint32_t format;
+ int32_t max_mipmap;
+ int32_t size;
+ int32_t unk_0x20;
+ DirectXTexture* dx_texture;
+};
+
+class TaskInterface {
+public:
+ virtual ~TaskInterface() {}
+ virtual bool Init() = 0;
+ virtual bool Loop() = 0;
+ virtual bool Destroy() = 0;
+ virtual bool Display() = 0;
+ virtual bool Basic() = 0;
+};
+
+struct Task : public TaskInterface {
+ int32_t priority;
+ Task* parent;
+ int32_t op;
+ int32_t state;
+ int32_t request;
+ int32_t nextOp;
+ int32_t nextState;
+ bool resetOnDestroy;
+ bool isFrameDependent;
+ char name[32];
+ uint32_t base_calc_time;
+ uint32_t calc_time;
+ uint32_t calc_time_max;
+ uint32_t disp_time;
+ uint32_t disp_time_max;
+};
+
+struct SpriteArgs {
+ uint32_t kind;
+ int32_t id;
+ uint8_t color[4];
+ int32_t attr;
+ int32_t blend;
+ int32_t index;
+ int32_t layer;
+ int32_t priority;
+ int32_t resolution_mode_screen;
+ int32_t resolution_mode_sprite;
+ Vec3 center;
+ Vec3 trans;
+ Vec3 scale;
+ Vec3 rot;
+ Vec2 skew_angle;
+ Mat4 mat;
+ Texture* texture;
+ int32_t shader;
+ int32_t field_AC;
+ Mat4 transform;
+ bool field_F0;
+ void* vertex_array;
+ size_t num_vertex;
+ int32_t field_108;
+ void* field_110;
+ bool set_viewport;
+ Vec4 viewport;
+ uint32_t flags;
+ Vec2 sprite_size;
+ int32_t field_138;
+ Vec2 texture_pos;
+ Vec2 texture_size;
+ SpriteArgs* next;
+ DirectXTexture* dx_texture;
+};
+
+FUNCTION_PTR(Texture*, __fastcall, TextureLoadTex2D, 0x1405F0720, uint32_t id, int32_t format, uint32_t width, uint32_t, int32_t mip_levels, void** data, int32_t, bool generate_mips);
+FUNCTION_PTR(void, __fastcall, TextureRelease, 0x1405F0950, Texture*);
+FUNCTION_PTR(void, __fastcall, DefaultSpriteArgs, 0x1405B78D0, SpriteArgs* args);
+FUNCTION_PTR(SpriteArgs*, __fastcall, put_sprite, 0x1405B49C0, SpriteArgs* args);
+FUNCTION_PTR(bool, __fastcall, DelTask, 0x1529F3780, Task* task);
+FUNCTION_PTR(bool, __fastcall, ResolveFilePath, 0x1402A5330, prj::string* in, prj::string* out);
+
+struct FFmpegPlayer {
+ enum class Status {
+ NotInitialized = 0,
+ Playing,
+ Shutdown,
+ };
+
+ enum class Shader {
+ BT601_FULL,
+ BT601_LIMITED,
+ BT709_FULL,
+ BT709_LIMITED,
+ BT2020_FULL,
+ BT2020_LIMITED,
+ };
+
+ AVFormatContext* input_ctx;
+ AVCodecContext* decoder_ctx;
+ AVStream* video;
+ AVFrame* frame;
+ int32_t stream_index;
+ double position;
+ double next_frame;
+ Status status;
+ Shader shader;
+ bool frame_updated;
+
+ ID3D11SamplerState* sampler;
+
+ ID3D11Texture2D* nv12_texture;
+ ID3D11ShaderResourceView* luminance_view;
+ ID3D11ShaderResourceView* chrominance_view;
+
+ ID3D11Texture2D* staging_nv12_texture;
+ ID3D11ShaderResourceView* staging_luminance_view;
+ ID3D11ShaderResourceView* staging_chrominance_view;
+
+ Texture* game_texture;
+ ID3D11RenderTargetView* render_target;
+
+ FFmpegPlayer() {
+ this->input_ctx = nullptr;
+ this->decoder_ctx = nullptr;
+ this->video = nullptr;
+ this->frame = nullptr;
+ this->sampler = nullptr;
+ this->nv12_texture = nullptr;
+ this->luminance_view = nullptr;
+ this->chrominance_view = nullptr;
+ this->staging_nv12_texture = nullptr;
+ this->staging_luminance_view = nullptr;
+ this->staging_chrominance_view = nullptr;
+ this->game_texture = nullptr;
+ this->render_target = nullptr;
+
+ this->stream_index = 0;
+ this->position = 0.0;
+ this->next_frame = 0.0;
+ this->status = Status::NotInitialized;
+ this->shader = Shader::BT709_FULL;
+ this->frame_updated = false;
+ }
+
+ void Reset() {
+ if (vulkan && this->decoder_ctx != nullptr && this->decoder_ctx->hw_device_ctx != nullptr) {
+ AVHWDeviceContext* hw_device_ctx = (AVHWDeviceContext*)this->decoder_ctx->hw_device_ctx->data;
+ AVVulkanDeviceContext* vk_device_ctx = (AVVulkanDeviceContext*)hw_device_ctx->hwctx;
+
+ vk_device_ctx->inst = VK_NULL_HANDLE;
+ vk_device_ctx->phys_dev = VK_NULL_HANDLE;
+ vk_device_ctx->act_dev = VK_NULL_HANDLE;
+ }
+
+ if (this->input_ctx != nullptr) {
+ avformat_close_input(&this->input_ctx);
+ this->input_ctx = nullptr;
+ this->video = nullptr;
+ }
+ if (this->decoder_ctx != nullptr) {
+ avcodec_free_context(&this->decoder_ctx);
+ this->decoder_ctx = nullptr;
+ }
+ if (this->frame != nullptr) {
+ av_frame_free(&this->frame);
+ this->frame = nullptr;
+ }
+ if (this->game_texture != nullptr) {
+ TextureRelease(this->game_texture);
+ this->game_texture = nullptr;
+ }
+ if (this->sampler != nullptr) {
+ this->sampler->Release();
+ this->sampler = nullptr;
+ }
+ if (this->nv12_texture != nullptr) {
+ this->nv12_texture->Release();
+ this->nv12_texture = nullptr;
+ }
+ if (this->luminance_view != nullptr) {
+ this->luminance_view->Release();
+ this->luminance_view = nullptr;
+ }
+ if (this->chrominance_view != nullptr) {
+ this->chrominance_view->Release();
+ this->chrominance_view = nullptr;
+ }
+ if (this->staging_nv12_texture != nullptr) {
+ this->staging_nv12_texture->Release();
+ this->staging_nv12_texture = nullptr;
+ }
+ if (this->staging_luminance_view != nullptr) {
+ this->staging_luminance_view->Release();
+ this->staging_luminance_view = nullptr;
+ }
+ if (this->staging_chrominance_view != nullptr) {
+ this->staging_chrominance_view->Release();
+ this->staging_chrominance_view = nullptr;
+ }
+ if (this->render_target != nullptr) {
+ this->render_target->Release();
+ this->render_target = nullptr;
+ }
+
+ this->stream_index = 0;
+ this->status = FFmpegPlayer::Status::NotInitialized;
+ this->position = 0.0;
+ this->next_frame = 0.0;
+ this->shader = FFmpegPlayer::Shader::BT709_FULL;
+ this->frame_updated = false;
+ }
+};
+
+struct TaskMovie : Task {
+ enum class State : int32_t {
+ Wait = 0,
+ Init = 1,
+ Disp = 2,
+ Stop = 3,
+ Shutdown = 4,
+ };
+
+ enum class DispType : int32_t {
+ None = 0,
+ Sprite = 1,
+ Texture = 2,
+ };
+
+ struct SprParams {
+ Vec4 rect;
+ uint32_t resolution_mode;
+ float scale;
+ uint32_t unk_18;
+ uint32_t index;
+ uint32_t priority;
+ uint32_t unk_24;
+ };
+
+ struct TextureInfo {
+ Texture* g_texture_y;
+ Texture* g_texture_uv;
+ void* unk_10;
+ int32_t width;
+ int32_t height;
+ };
+
+ prj::string path;
+ DispType disp_type;
+ SprParams params;
+ void* unk_B8;
+ State state;
+ void* player;
+ bool paused;
+ bool wait_play;
+ bool is_ffmpeg; // Added in padding
+ int64_t unk_D8;
+ int32_t unk_E0;
+ int64_t time;
+ int64_t offset;
+ int32_t index;
+};
+
+FFmpegPlayer ffmpeg_players[2];
+
+AVPixelFormat
+get_format(AVCodecContext* decoder_ctx, const AVPixelFormat* pixel_formats) {
+ const std::set known_formats = { vulkan ? AV_PIX_FMT_VULKAN : AV_PIX_FMT_D3D11, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10LE };
+ std::set formats = {};
+ while (*pixel_formats != AV_PIX_FMT_NONE) {
+ if (known_formats.find(*pixel_formats) != known_formats.end()) formats.insert(*pixel_formats);
+ pixel_formats++;
+ }
+
+ if (decoder_ctx->hw_device_ctx != nullptr && formats.find(AV_PIX_FMT_VULKAN) != formats.end()) return AV_PIX_FMT_VULKAN;
+ else if (decoder_ctx->hw_device_ctx != nullptr && formats.find(AV_PIX_FMT_D3D11) != formats.end()) return AV_PIX_FMT_D3D11;
+ else if (formats.find(AV_PIX_FMT_YUV420P) != formats.end()) return AV_PIX_FMT_YUV420P;
+ else if (formats.find(AV_PIX_FMT_YUV420P10LE) != formats.end()) return AV_PIX_FMT_YUV420P10LE;
+ else return AV_PIX_FMT_NONE;
+}
+
+HOOK(TaskMovie*, __fastcall, TaskMovieInit, 0x140454660, TaskMovie* movie) {
+ movie->is_ffmpeg = false;
+ return originalTaskMovieInit(movie);
+}
+
+HOOK(bool, __fastcall, TaskMovieCheckDisp, 0x1569B1520, TaskMovie* movie) {
+ if (!movie->is_ffmpeg) return originalTaskMovieCheckDisp(movie);
+ if (!movie->wait_play) return false;
+ auto player = &ffmpeg_players[movie->index];
+
+ return player->status == FFmpegPlayer::Status::Playing || player->status == FFmpegPlayer::Status::Shutdown;
+}
+
+HOOK(bool, __fastcall, TaskMovieCtrl, 0x140454890, TaskMovie* movie) {
+ if (!movie->is_ffmpeg) return originalTaskMovieCtrl(movie);
+
+ auto player = &ffmpeg_players[movie->index];
+ switch (player->status) {
+ case FFmpegPlayer::Status::NotInitialized: {
+ int32_t res = 0;
+ player->Reset();
+
+ player->input_ctx = avformat_alloc_context();
+ res = avformat_open_input(&player->input_ctx, movie->path.c_str(), nullptr, nullptr);
+ if (res < 0 || player->input_ctx == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ res = avformat_find_stream_info(player->input_ctx, nullptr);
+ if (res < 0) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ const AVCodec* decoder;
+ res = av_find_best_stream(player->input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
+ if (res < 0 || decoder == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ player->stream_index = res;
+ player->video = player->input_ctx->streams[player->stream_index];
+
+ int32_t i = 0;
+ const AVCodecHWConfig* config = avcodec_get_hw_config(decoder, i);
+ while (config != nullptr) {
+ if (config->device_type == (vulkan ? AV_HWDEVICE_TYPE_VULKAN : AV_HWDEVICE_TYPE_D3D11VA)) break;
+ config = avcodec_get_hw_config(decoder, i);
+ i++;
+ }
+
+ player->decoder_ctx = avcodec_alloc_context3(decoder);
+ if (player->decoder_ctx == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ res = avcodec_parameters_to_context(player->decoder_ctx, player->video->codecpar);
+ if (res < 0) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ player->decoder_ctx->get_format = get_format;
+
+ if (config == nullptr) {
+ }
+ else if (vulkan) {
+ AVBufferRef* hw_device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VULKAN);
+ AVHWDeviceContext* device_ctx = (AVHWDeviceContext*)(hw_device_ctx->data);
+ if (device_ctx == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ AVVulkanDeviceContext* vulkan_device_ctx = (AVVulkanDeviceContext*)(device_ctx->hwctx);
+ if (vulkan_device_ctx == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ vulkan_device_ctx->get_proc_addr = vkGetInstanceProcAddr;
+ vulkan_device_ctx->inst = vkInstance;
+ vulkan_device_ctx->phys_dev = vkPhysDevice;
+ vulkan_device_ctx->act_dev = vkDevice;
+ vulkan_device_ctx->device_features = vkDeviceFeatures;
+ vulkan_device_ctx->enabled_inst_extensions = vkInstanceExtensions.data();
+ vulkan_device_ctx->nb_enabled_inst_extensions = vkInstanceExtensions.size();
+ vulkan_device_ctx->enabled_dev_extensions = vkDeviceExtensions.data();
+ vulkan_device_ctx->nb_enabled_dev_extensions = vkDeviceExtensions.size();
+ memcpy(&vulkan_device_ctx->qf, vkQueueFamilies.data(), sizeof(AVVulkanDeviceQueueFamily) * vkQueueFamilies.size());
+ vulkan_device_ctx->nb_qf = vkQueueFamilies.size();
+
+ res = av_hwdevice_ctx_init(hw_device_ctx);
+ if (res < 0) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ player->decoder_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
+ }
+ else {
+ AVBufferRef* hw_device_ctx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA);
+ AVHWDeviceContext* device_ctx = (AVHWDeviceContext*)(hw_device_ctx->data);
+ if (device_ctx == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ AVD3D11VADeviceContext* d3d11va_device_ctx = (AVD3D11VADeviceContext*)(device_ctx->hwctx);
+ if (d3d11va_device_ctx == nullptr) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ d3d11va_device_ctx->device = d3d11Device;
+ d3d11va_device_ctx->device_context = d3d11DeviceContext;
+ res = av_hwdevice_ctx_init(hw_device_ctx);
+ if (res < 0) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ player->decoder_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
+ }
+
+ res = avcodec_open2(player->decoder_ctx, decoder, nullptr);
+ if (res < 0) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ res = av_seek_frame(player->input_ctx, player->stream_index, 0, 0);
+ if (res < 0) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ if (player->decoder_ctx->color_primaries == AVCOL_PRI_BT470M || player->decoder_ctx->color_primaries == AVCOL_PRI_BT470BG ||
+ player->decoder_ctx->color_primaries == AVCOL_PRI_SMPTE170M || player->decoder_ctx->color_primaries == AVCOL_PRI_SMPTE240M) {
+ if (player->decoder_ctx->color_range == AVCOL_RANGE_MPEG) player->shader = FFmpegPlayer::Shader::BT601_LIMITED;
+ else if (player->decoder_ctx->color_range == AVCOL_RANGE_JPEG) player->shader = FFmpegPlayer::Shader::BT601_FULL;
+ else player->shader = FFmpegPlayer::Shader::BT601_LIMITED;
+ }
+ else if (player->decoder_ctx->color_primaries == AVCOL_PRI_BT709) {
+ if (player->decoder_ctx->color_range == AVCOL_RANGE_MPEG) player->shader = FFmpegPlayer::Shader::BT709_LIMITED;
+ else if (player->decoder_ctx->color_range == AVCOL_RANGE_JPEG) player->shader = FFmpegPlayer::Shader::BT709_FULL;
+ else player->shader = FFmpegPlayer::Shader::BT709_FULL;
+ }
+ else if (player->decoder_ctx->color_primaries == AVCOL_PRI_BT2020) {
+ if (player->decoder_ctx->color_range == AVCOL_RANGE_MPEG) player->shader = FFmpegPlayer::Shader::BT2020_LIMITED;
+ else if (player->decoder_ctx->color_range == AVCOL_RANGE_JPEG) player->shader = FFmpegPlayer::Shader::BT2020_FULL;
+ else player->shader = FFmpegPlayer::Shader::BT2020_FULL;
+ }
+ else if (player->decoder_ctx->height < 720) {
+ if (player->decoder_ctx->color_range == AVCOL_RANGE_MPEG) player->shader = FFmpegPlayer::Shader::BT601_LIMITED;
+ else if (player->decoder_ctx->color_range == AVCOL_RANGE_JPEG) player->shader = FFmpegPlayer::Shader::BT601_FULL;
+ else player->shader = FFmpegPlayer::Shader::BT601_LIMITED;
+ }
+ else {
+ if (player->decoder_ctx->color_range == AVCOL_RANGE_MPEG) player->shader = FFmpegPlayer::Shader::BT709_LIMITED;
+ else if (player->decoder_ctx->color_range == AVCOL_RANGE_JPEG) player->shader = FFmpegPlayer::Shader::BT709_FULL;
+ else player->shader = FFmpegPlayer::Shader::BT709_FULL;
+ }
+
+ HRESULT hr;
+
+ D3D11_SAMPLER_DESC sampler_desc = {};
+ sampler_desc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
+ sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ sampler_desc.MipLODBias = 0.0;
+ sampler_desc.MaxAnisotropy = 1;
+ sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+ sampler_desc.BorderColor[0] = 0.0;
+ sampler_desc.BorderColor[1] = 0.5;
+ sampler_desc.BorderColor[2] = 0.5;
+ sampler_desc.BorderColor[3] = 0.0;
+ sampler_desc.MinLOD = 0.0;
+ sampler_desc.MaxLOD = 1.0;
+
+ hr = d3d11Device->CreateSamplerState(&sampler_desc, &player->sampler);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ if (player->decoder_ctx->pix_fmt == AV_PIX_FMT_YUV420P) {
+ D3D11_TEXTURE2D_DESC desc = {};
+ desc.Width = player->decoder_ctx->width;
+ desc.Height = player->decoder_ctx->height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_NV12;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ hr = d3d11Device->CreateTexture2D(&desc, nullptr, &player->nv12_texture);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ hr = d3d11Device->CreateTexture2D(&desc, nullptr, &player->staging_nv12_texture);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+ srv_desc.Format = DXGI_FORMAT_R8_UNORM;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = -1;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+
+ hr = d3d11Device->CreateShaderResourceView(player->nv12_texture, &srv_desc, &player->luminance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ hr = d3d11Device->CreateShaderResourceView(player->staging_nv12_texture, &srv_desc, &player->staging_luminance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ srv_desc.Format = DXGI_FORMAT_R8G8_UNORM;
+
+ hr = d3d11Device->CreateShaderResourceView(player->nv12_texture, &srv_desc, &player->chrominance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ hr = d3d11Device->CreateShaderResourceView(player->staging_nv12_texture, &srv_desc, &player->staging_chrominance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+ }
+ else if (player->decoder_ctx->pix_fmt == AV_PIX_FMT_YUV420P10LE) {
+ D3D11_TEXTURE2D_DESC desc = {};
+ desc.Width = player->decoder_ctx->width;
+ desc.Height = player->decoder_ctx->height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_P010;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ hr = d3d11Device->CreateTexture2D(&desc, nullptr, &player->nv12_texture);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ hr = d3d11Device->CreateTexture2D(&desc, nullptr, &player->staging_nv12_texture);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+ srv_desc.Format = DXGI_FORMAT_R16_UNORM;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = -1;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+
+ hr = d3d11Device->CreateShaderResourceView(player->nv12_texture, &srv_desc, &player->luminance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ hr = d3d11Device->CreateShaderResourceView(player->staging_nv12_texture, &srv_desc, &player->staging_luminance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ srv_desc.Format = DXGI_FORMAT_R16G16_UNORM;
+
+ hr = d3d11Device->CreateShaderResourceView(player->nv12_texture, &srv_desc, &player->chrominance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ hr = d3d11Device->CreateShaderResourceView(player->staging_nv12_texture, &srv_desc, &player->staging_chrominance_view);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+ }
+
+ player->game_texture = TextureLoadTex2D(0x393939 + movie->index, 6, player->decoder_ctx->width, player->decoder_ctx->height, 0, nullptr, 0, false);
+
+ hr = d3d11Device->CreateRenderTargetView(player->game_texture->dx_texture->texture, nullptr, &player->render_target);
+ if (FAILED(hr)) {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+
+ player->position = 0.0;
+ player->next_frame = 0.0;
+
+ movie->state = TaskMovie::State::Disp;
+ player->status = FFmpegPlayer::Status::Playing;
+ }; break;
+ case FFmpegPlayer::Status::Playing: {
+ if (movie->time == -1) break;
+
+ player->position = ((double)movie->time - (double)movie->offset) / 1000.0 / 1000.0;
+ while (player->position >= player->next_frame && player->next_frame < (double)player->input_ctx->duration * av_q2d(AV_TIME_BASE_Q) && !movie->paused && !movie->wait_play) {
+ int32_t res;
+
+ AVPacket* packet = av_packet_alloc();
+ res = av_read_frame(player->input_ctx, packet);
+ if (res < 0) {
+ av_packet_free(&packet);
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+ if (packet->stream_index != player->stream_index) {
+ av_packet_free(&packet);
+ continue;
+ }
+
+ res = avcodec_send_packet(player->decoder_ctx, packet);
+ if (res < 0) {
+ av_packet_free(&packet);
+ if (res == AVERROR(EAGAIN)) {
+ continue;
+ }
+ else {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+ }
+
+ player->frame_updated = false;
+
+ if (player->frame != nullptr) av_frame_free(&player->frame);
+ player->frame = av_frame_alloc();
+ res = avcodec_receive_frame(player->decoder_ctx, player->frame);
+ if (res < 0) {
+ av_frame_free(&player->frame);
+ av_packet_free(&packet);
+ if (res == AVERROR(EAGAIN)) {
+ continue;
+ }
+ else {
+ movie->state = TaskMovie::State::Shutdown;
+ player->status = FFmpegPlayer::Status::Shutdown;
+ break;
+ }
+ }
+
+ player->frame_updated = true;
+ player->next_frame = ((double)packet->duration + (double)player->frame->pts) * av_q2d(player->video->time_base);
+
+ av_packet_free(&packet);
+ }
+ }; break;
+ case FFmpegPlayer::Status::Shutdown: {
+ }; break;
+ }
+
+ return false;
+}
+
+HOOK(void, __fastcall, TaskMovieCtrlPlayer, 0x1404551B0, TaskMovie* movie) {
+ if (!movie->is_ffmpeg) return originalTaskMovieCtrlPlayer(movie);
+
+ auto player = &ffmpeg_players[movie->index];
+ if (player->input_ctx == nullptr) return;
+
+ double position = ((double)movie->time - (double)movie->offset) / 1000.0 / 1000.0;
+ if (position < 0.0) position = 0.0;
+
+ avformat_seek_file(player->input_ctx, player->stream_index, 0, (int64_t)(position / av_q2d(player->video->time_base)), (int64_t)(position / av_q2d(player->video->time_base)), 0);
+ player->position = position;
+ player->next_frame = 0.0;
+}
+
+HOOK(void, __fastcall, TaskMovieDisp, 0x1404549D0, TaskMovie* movie) {
+ if (!movie->is_ffmpeg) return originalTaskMovieDisp(movie);
+
+ auto player = &ffmpeg_players[movie->index];
+ if (movie->state != TaskMovie::State::Disp || movie->disp_type != TaskMovie::DispType::Sprite) return;
+ if (player->status != FFmpegPlayer::Status::Playing || player->game_texture == nullptr || player->frame == nullptr) return;
+
+ if (player->frame_updated) {
+ d3d11DeviceContext->VSSetShader(shader_vs, nullptr, 0);
+ switch (player->shader) {
+ case FFmpegPlayer::Shader::BT601_FULL: d3d11DeviceContext->PSSetShader(shader_bt601_full, nullptr, 0); break;
+ case FFmpegPlayer::Shader::BT601_LIMITED: d3d11DeviceContext->PSSetShader(shader_bt601_limited, nullptr, 0); break;
+ case FFmpegPlayer::Shader::BT709_FULL: d3d11DeviceContext->PSSetShader(shader_bt709_full, nullptr, 0); break;
+ case FFmpegPlayer::Shader::BT709_LIMITED: d3d11DeviceContext->PSSetShader(shader_bt709_limited, nullptr, 0); break;
+ case FFmpegPlayer::Shader::BT2020_FULL: d3d11DeviceContext->PSSetShader(shader_bt2020_full, nullptr, 0); break;
+ case FFmpegPlayer::Shader::BT2020_LIMITED: d3d11DeviceContext->PSSetShader(shader_bt2020_limited, nullptr, 0); break;
+ };
+
+ D3D11_VIEWPORT viewport = {};
+ viewport.TopLeftX = 0;
+ viewport.TopLeftY = 0;
+ viewport.Width = player->decoder_ctx->width;
+ viewport.Height = player->decoder_ctx->height;
+
+ d3d11DeviceContext->RSSetViewports(1, &viewport);
+ d3d11DeviceContext->OMSetRenderTargets(1, &player->render_target, nullptr);
+ d3d11DeviceContext->PSSetSamplers(0, 1, &player->sampler);
+
+ if (player->frame->format == AV_PIX_FMT_VULKAN) {
+ AVVkFrame* vk_frame = (AVVkFrame*)player->frame->data[0];
+ AVHWDeviceContext* hw_device_ctx = (AVHWDeviceContext*)player->decoder_ctx->hw_device_ctx->data;
+ AVHWFramesContext* hw_frames_ctx = (AVHWFramesContext*)player->decoder_ctx->hw_frames_ctx->data;
+ AVVulkanDeviceContext* vk_device_ctx = (AVVulkanDeviceContext*)hw_device_ctx->hwctx;
+ IDXGIVkInteropDevice1* vkInteropDevice = nullptr;
+ d3d11Device->QueryInterface(&vkInteropDevice);
+
+ switch (hw_frames_ctx->sw_format) {
+ case AV_PIX_FMT_NV12: {
+ ID3D11Texture2D* texture;
+ ID3D11ShaderResourceView* luminance_view;
+ ID3D11ShaderResourceView* chrominance_view;
+
+ D3D11_TEXTURE2D_DESC1 desc = {};
+ desc.Width = player->decoder_ctx->width;
+ desc.Height = player->decoder_ctx->height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_NV12;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+ desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
+
+ HRESULT hr = vkInteropDevice->CreateTexture2DFromVkImage(&desc, vk_frame->img[0], &texture);
+ if (FAILED(hr)) {
+ break;
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+ srv_desc.Format = DXGI_FORMAT_R8_UNORM;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = -1;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+
+ hr = d3d11Device->CreateShaderResourceView(texture, &srv_desc, &luminance_view);
+ if (FAILED(hr)) {
+ break;
+ }
+
+ srv_desc.Format = DXGI_FORMAT_R8G8_UNORM;
+
+ hr = d3d11Device->CreateShaderResourceView(texture, &srv_desc, &chrominance_view);
+ if (FAILED(hr)) {
+ break;
+ }
+
+ d3d11DeviceContext->PSSetShaderResources(0, 1, &luminance_view);
+ d3d11DeviceContext->PSSetShaderResources(1, 1, &chrominance_view);
+ d3d11DeviceContext->Draw(3, 0);
+
+ chrominance_view->Release();
+ luminance_view->Release();
+ texture->Release();
+ }; break;
+ case AV_PIX_FMT_P010LE: {
+ ID3D11Texture2D* texture;
+ ID3D11ShaderResourceView* luminance_view;
+ ID3D11ShaderResourceView* chrominance_view;
+
+ D3D11_TEXTURE2D_DESC1 desc = {};
+ desc.Width = player->decoder_ctx->width;
+ desc.Height = player->decoder_ctx->height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_P010;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+ desc.MiscFlags = 0;
+ desc.TextureLayout = D3D11_TEXTURE_LAYOUT_UNDEFINED;
+
+ HRESULT hr = vkInteropDevice->CreateTexture2DFromVkImage(&desc, vk_frame->img[0], &texture);
+ if (FAILED(hr)) {
+ break;
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
+ srv_desc.Format = DXGI_FORMAT_R16_UNORM;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = -1;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+
+ hr = d3d11Device->CreateShaderResourceView(texture, &srv_desc, &luminance_view);
+ if (FAILED(hr)) {
+ break;
+ }
+
+ srv_desc.Format = DXGI_FORMAT_R16G16_UNORM;
+
+ hr = d3d11Device->CreateShaderResourceView(texture, &srv_desc, &chrominance_view);
+ if (FAILED(hr)) {
+ break;
+ }
+
+ d3d11DeviceContext->PSSetShaderResources(0, 1, &luminance_view);
+ d3d11DeviceContext->PSSetShaderResources(1, 1, &chrominance_view);
+ d3d11DeviceContext->Draw(3, 0);
+
+ chrominance_view->Release();
+ luminance_view->Release();
+ texture->Release();
+ }; break;
+ default: {
+ }; break;
+ }
+ }
+ else if (player->frame->format == AV_PIX_FMT_D3D11) {
+ d3d11DeviceContext->CopySubresourceRegion(player->nv12_texture, 0, 0, 0, 0, (ID3D11Texture2D*)player->frame->data[0], (uint32_t)player->frame->data[1], nullptr);
+ d3d11DeviceContext->PSSetShaderResources(0, 1, &player->luminance_view);
+ d3d11DeviceContext->PSSetShaderResources(1, 1, &player->chrominance_view);
+ d3d11DeviceContext->Draw(3, 0);
+ }
+ else if (player->frame->format == AV_PIX_FMT_YUV420P) {
+ D3D11_MAPPED_SUBRESOURCE map;
+ HRESULT hr = d3d11DeviceContext->Map(player->staging_nv12_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
+ if (FAILED(hr)) return;
+
+ for (int i = 0; i < player->frame->height; i++)
+ memcpy((uint8_t*)map.pData + i * map.RowPitch, (uint8_t*)player->frame->data[0] + i * player->frame->linesize[0], std::min((uint32_t)player->frame->linesize[0], map.RowPitch));
+
+ const __m128i filter = _mm_set_epi8(7, 7 + 8, 6, 6 + 8, 5, 5 + 8, 4, 4 + 8, 3, 3 + 8, 2, 2 + 8, 1, 1 + 8, 0, 0 + 8);
+ for (int i = 0; i < player->frame->height / 2; i++){
+ int u_offset = i * player->frame->linesize[1];
+ int v_offset = i * player->frame->linesize[2];
+ int tex_offset = (i + player->frame->height) * map.RowPitch;
+ for (int j = 0; j < player->frame->width / 8; j++) {
+ uint64_t u = *(uint64_t*)(player->frame->data[1] + u_offset + j * 8);
+ uint64_t v = *(uint64_t*)(player->frame->data[2] + u_offset + j * 8);
+ __m128i data = _mm_set_epi64x(u, v);
+ __m128i ordered = _mm_shuffle_epi8(data, filter);
+ _mm_store_si128((__m128i*)((uint8_t*)map.pData + tex_offset + j * 16), ordered);
+ }
+ }
+ d3d11DeviceContext->Unmap(player->staging_nv12_texture, 0);
+
+ d3d11DeviceContext->PSSetShaderResources(0, 1, &player->staging_luminance_view);
+ d3d11DeviceContext->PSSetShaderResources(1, 1, &player->staging_chrominance_view);
+ d3d11DeviceContext->Draw(3, 0);
+ }
+ else if (player->frame->format == AV_PIX_FMT_YUV420P10LE) {
+ D3D11_MAPPED_SUBRESOURCE map;
+ HRESULT hr = d3d11DeviceContext->Map(player->staging_nv12_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);
+ if (FAILED(hr)) return;
+
+ for (int i = 0; i < player->frame->height; i++) {
+ int y_offset = i * player->frame->linesize[0];
+ int tex_offset = i * map.RowPitch;
+ for (int j = 0; j < player->frame->width / 8; j++) {
+ __m128i data = _mm_load_si128((__m128i*)(player->frame->data[0] + y_offset + j * 16));
+ _mm_store_si128((__m128i*)((uint8_t*)map.pData + tex_offset + j * 16), _mm_slli_epi16(data, 6));
+ }
+ }
+
+ const __m128i filter = _mm_set_epi8(7, 6, 7 + 8, 6 + 8, 5, 4, 5 + 8, 4 + 8, 3, 2, 3 + 8, 2 + 8, 1, 0, 1 + 8, 0 + 8);
+ for (int i = 0; i < player->frame->height / 2; i++) {
+ int u_offset = i * player->frame->linesize[1];
+ int v_offset = i * player->frame->linesize[2];
+ int tex_offset = (i + player->frame->height) * map.RowPitch;
+ for (int j = 0; j < player->frame->width / 8; j++) {
+ uint64_t u = *(uint64_t*)(player->frame->data[1] + u_offset + j * 8);
+ uint64_t v = *(uint64_t*)(player->frame->data[2] + u_offset + j * 8);
+ __m128i data = _mm_set_epi64x(u, v);
+ __m128i ordered = _mm_shuffle_epi8(_mm_slli_epi16(data, 6), filter);
+ _mm_store_si128((__m128i*)((uint8_t*)map.pData + tex_offset + j * 16), ordered);
+ }
+ }
+ d3d11DeviceContext->Unmap(player->staging_nv12_texture, 0);
+
+ d3d11DeviceContext->PSSetShaderResources(0, 1, &player->staging_luminance_view);
+ d3d11DeviceContext->PSSetShaderResources(1, 1, &player->staging_chrominance_view);
+ d3d11DeviceContext->Draw(3, 0);
+ }
+ player->frame_updated = false;
+ }
+
+ // Taken from rediva
+ float width = player->decoder_ctx->width;
+ float height = player->decoder_ctx->height;
+ float scale = movie->params.scale;
+
+ Vec2 sprite_size;
+ sprite_size.x = width;
+ sprite_size.x = height;
+
+ float tex_x = 0.0;
+ float tex_y = 0.0;
+ float tex_width;
+ float tex_height;
+
+ if (scale <= 0.0) {
+ scale = fmin(movie->params.rect.z / width, movie->params.rect.w / height);
+ float ar = width / height;
+ float desired_ar = movie->params.rect.z / movie->params.rect.w;
+
+ tex_width = (1.0 / scale) * (ar < desired_ar ? movie->params.rect.z / desired_ar * ar : movie->params.rect.z);
+ tex_height = (1.0 / scale) * (ar > desired_ar ? movie->params.rect.w / desired_ar * ar : movie->params.rect.w);
+
+ sprite_size.x = tex_width;
+ sprite_size.y = tex_height;
+
+ tex_x = width * 0.5 - tex_width * 0.5;
+ tex_y = height - height * 0.5 - tex_height * 0.5;
+ }
+ else {
+ tex_width = width;
+ tex_height = height;
+ }
+
+ SpriteArgs args = { 0 };
+ DefaultSpriteArgs(&args);
+
+ args.id = -1;
+ args.texture = player->game_texture;
+ args.index = movie->params.index;
+ args.priority = movie->params.priority;
+ args.resolution_mode_screen = movie->params.resolution_mode;
+ args.resolution_mode_sprite = movie->params.resolution_mode;
+ args.scale.x = scale;
+ args.scale.y = scale;
+ args.flags = 0x03;
+ args.texture_pos.x = tex_x;
+ args.texture_pos.y = tex_y;
+ args.texture_size.x = tex_width;
+ args.texture_size.y = tex_height;
+ args.sprite_size = sprite_size;
+ args.attr = 0x00420000;
+ args.trans.x = movie->params.rect.x + movie->params.rect.z * 0.5;
+ args.trans.y = movie->params.rect.y + movie->params.rect.w * 0.5;
+
+ put_sprite(&args);
+}
+
+// TODO: Convert RGBA to BT601 FULL UV12
+HOOK(void, __fastcall, TaskMovieGetTexture, 0x140455240, TaskMovie* movie, TaskMovie::TextureInfo* texture) {
+ if (!movie->is_ffmpeg) return originalTaskMovieGetTexture(movie, texture);
+
+ if (movie->state != TaskMovie::State::Disp || movie->disp_type != TaskMovie::DispType::Texture) return;
+ auto player = &ffmpeg_players[movie->index];
+ if (player->status != FFmpegPlayer::Status::Playing) return;
+
+ texture->g_texture_y = player->game_texture;
+ texture->width = player->decoder_ctx->width;
+ texture->height = player->decoder_ctx->height;
+}
+
+HOOK(bool, __fastcall, TaskMovieReset, 0x140454B60, TaskMovie* movie, TaskMovie::SprParams* params) {
+ movie->is_ffmpeg = false;
+
+ return originalTaskMovieReset(movie, params);
+}
+
+HOOK(void, __fastcall, TaskMovieStart, 0x140454CC0, TaskMovie* movie, prj::string* path) {
+ prj::string buf("");
+ if (*(uint32_t*)(path->c_str() + path->length() - 4) == *(uint32_t*)".usm") {
+ movie->is_ffmpeg = false;
+ if (ResolveFilePath(path, &buf)) return originalTaskMovieStart(movie, path);
+ else {
+ DelTask(movie);
+ return;
+ }
+ }
+
+ if (!ResolveFilePath(path, &buf)) {
+ *(uint32_t*)(path->c_str() + path->length() - 4) = *(uint32_t*)".usm";
+ movie->is_ffmpeg = false;
+ if (ResolveFilePath(path, &buf)) return originalTaskMovieStart(movie, path);
+ else {
+ DelTask(movie);
+ return;
+ }
+ }
+
+ auto player = &ffmpeg_players[movie->index];
+ movie->is_ffmpeg = true;
+ if (player->input_ctx == nullptr || strcmp(player->input_ctx->url, buf.c_str()) != 0) {
+ movie->state = TaskMovie::State::Init;
+ movie->path = buf.c_str();
+ player->status = FFmpegPlayer::Status::NotInitialized;
+ }
+ else {
+ movie->paused = false;
+ }
+ implOfTaskMovieCtrlPlayer(movie);
+}
+
+HOOK(VkResult, __fastcall, VkCreateDevice, nullptr, VkPhysicalDevice physicalDevice, VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) {
+ vkDeviceExtensions.reserve(pCreateInfo->enabledExtensionCount);
+
+ std::map DesiredExtensions = {
+ { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_DECODE_VP9_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME, false },
+ { VK_KHR_VIDEO_MAINTENANCE_2_EXTENSION_NAME, false },
+ { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, false },
+ { VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, false },
+ { VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, false },
+ { VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, false },
+ { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, false },
+ { VK_EXT_SHADER_OBJECT_EXTENSION_NAME, false },
+ { VK_KHR_SHADER_SUBGROUP_ROTATE_EXTENSION_NAME, false },
+ { VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME, false },
+ { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, false },
+ { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, false },
+ { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, false },
+ { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, false },
+ { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, false },
+ { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, false },
+ { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, false },
+ };
+
+ for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+ vkDeviceExtensions.push_back((char*)calloc(strlen(pCreateInfo->ppEnabledExtensionNames[i]) + 1, sizeof(char)));
+ strcpy(vkDeviceExtensions.at(i), pCreateInfo->ppEnabledExtensionNames[i]);
+
+ for (auto& extension : DesiredExtensions) {
+ if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], extension.first) == 0) {
+ extension.second = true;
+ break;
+ }
+ }
+ }
+
+ uint32_t extension_count = 0;
+ vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, nullptr);
+ auto extensions = (VkExtensionProperties*)malloc(sizeof(VkExtensionProperties) * extension_count);
+ vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, extensions);
+
+ for (uint32_t i = 0; i < extension_count; i++) {
+ for (auto& extension : DesiredExtensions) {
+ if (!extension.second && strcmp(extensions[i].extensionName, extension.first) == 0) {
+ vkDeviceExtensions.push_back((char*)extension.first);
+ break;
+ }
+ }
+ }
+
+ free(extensions);
+
+ std::map DesiredFeatures = {
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT, false },
+ { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR, false }
+ };
+
+ VkPhysicalDeviceFeatures2 enabledFeatures = {};
+ VkPhysicalDeviceVulkan11Features vulkan11Features = {};
+ VkPhysicalDeviceVulkan12Features vulkan12Features = {};
+ VkPhysicalDeviceVulkan13Features vulkan13Features = {};
+ VkPhysicalDeviceVulkan14Features vulkan14Features = {};
+ VkPhysicalDeviceShaderSubgroupRotateFeatures shaderSubgroupFeatures = {};
+ VkPhysicalDeviceHostImageCopyFeaturesEXT hostImageCopyFeatures = {};
+ VkPhysicalDeviceShaderExpectAssumeFeaturesKHR shaderExpectAssumeFeatures = {};
+ VkPhysicalDeviceVideoMaintenance1FeaturesKHR videoMaintenance1Features = {};
+ VkPhysicalDeviceVideoMaintenance2FeaturesKHR videoMaintenance2Features = {};
+ VkPhysicalDeviceVideoDecodeVP9FeaturesKHR vp9Features = {};
+ VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures = {};
+ VkPhysicalDeviceCooperativeMatrixFeaturesKHR cooperativeMatrixFeatures = {};
+ VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptorBufferFeatures = {};
+ VkPhysicalDeviceShaderAtomicFloatFeaturesEXT shaderAtomicFloatFeatures = {};
+ VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR shaderRelaxFeatures = {};
+
+ enabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ vulkan11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
+ vulkan12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
+ vulkan13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
+ vulkan14Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES;
+ shaderSubgroupFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR;
+ hostImageCopyFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT;
+ shaderExpectAssumeFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR;
+ videoMaintenance1Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR;
+ videoMaintenance2Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR;
+ vp9Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR;
+ shaderObjectFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT;
+ cooperativeMatrixFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR;
+ descriptorBufferFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT;
+ shaderAtomicFloatFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT;
+ shaderRelaxFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR;
+
+ enabledFeatures.pNext = &vulkan11Features;
+ vulkan11Features.pNext = &vulkan12Features;
+ vulkan12Features.pNext = &vulkan13Features;
+ vulkan13Features.pNext = &vulkan14Features;
+ vulkan14Features.pNext = &shaderSubgroupFeatures;
+ shaderSubgroupFeatures.pNext = &hostImageCopyFeatures;
+ hostImageCopyFeatures.pNext = &shaderExpectAssumeFeatures;
+ shaderExpectAssumeFeatures.pNext = &videoMaintenance1Features;
+ videoMaintenance1Features.pNext = &videoMaintenance2Features;
+ videoMaintenance2Features.pNext = &vp9Features;
+ vp9Features.pNext = &shaderObjectFeatures;
+ shaderObjectFeatures.pNext = &cooperativeMatrixFeatures;
+ cooperativeMatrixFeatures.pNext = &descriptorBufferFeatures;
+ descriptorBufferFeatures.pNext = &shaderAtomicFloatFeatures;
+ shaderAtomicFloatFeatures.pNext = &shaderRelaxFeatures;
+ shaderRelaxFeatures.pNext = nullptr;
+
+ vkGetPhysicalDeviceFeatures2(physicalDevice, &enabledFeatures);
+
+ vkDeviceFeatures = {};
+ vkDeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+
+ if (pCreateInfo->pEnabledFeatures != nullptr) {
+ memcpy(&vkDeviceFeatures.features, pCreateInfo->pEnabledFeatures, sizeof(VkPhysicalDeviceFeatures));
+
+ vkDeviceFeatures.features.shaderImageGatherExtended = enabledFeatures.features.shaderImageGatherExtended;
+ vkDeviceFeatures.features.shaderStorageImageReadWithoutFormat = enabledFeatures.features.shaderStorageImageReadWithoutFormat;
+ vkDeviceFeatures.features.shaderStorageImageWriteWithoutFormat = enabledFeatures.features.shaderStorageImageWriteWithoutFormat;
+ vkDeviceFeatures.features.fragmentStoresAndAtomics = enabledFeatures.features.fragmentStoresAndAtomics;
+ vkDeviceFeatures.features.vertexPipelineStoresAndAtomics = enabledFeatures.features.vertexPipelineStoresAndAtomics;
+ vkDeviceFeatures.features.shaderInt64 = enabledFeatures.features.shaderInt64;
+ vkDeviceFeatures.features.shaderInt16 = enabledFeatures.features.shaderInt16;
+ vkDeviceFeatures.features.shaderFloat64 = enabledFeatures.features.shaderFloat64;
+ }
+
+ const void* pNext = pCreateInfo->pNext;
+ void** ppNext = &vkDeviceFeatures.pNext;
+
+ while (pNext != nullptr) {
+ auto sType = *(VkStructureType*)pNext;
+
+ if (DesiredFeatures.find(sType) != DesiredFeatures.end()) {
+ DesiredFeatures.find(sType)->second = true;
+ }
+
+ size_t size = 0;
+ switch (sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
+ memcpy(&vkDeviceFeatures.features, (void*)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, features)), sizeof(VkPhysicalDeviceFeatures));
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+
+ vkDeviceFeatures.features.shaderImageGatherExtended = enabledFeatures.features.shaderImageGatherExtended;
+ vkDeviceFeatures.features.shaderStorageImageReadWithoutFormat = enabledFeatures.features.shaderStorageImageReadWithoutFormat;
+ vkDeviceFeatures.features.shaderStorageImageWriteWithoutFormat = enabledFeatures.features.shaderStorageImageWriteWithoutFormat;
+ vkDeviceFeatures.features.fragmentStoresAndAtomics = enabledFeatures.features.fragmentStoresAndAtomics;
+ vkDeviceFeatures.features.vertexPipelineStoresAndAtomics = enabledFeatures.features.vertexPipelineStoresAndAtomics;
+ vkDeviceFeatures.features.shaderInt64 = enabledFeatures.features.shaderInt64;
+ vkDeviceFeatures.features.shaderInt16 = enabledFeatures.features.shaderInt16;
+ vkDeviceFeatures.features.shaderFloat64 = enabledFeatures.features.shaderFloat64;
+
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: {
+ *ppNext = malloc(sizeof(VkPhysicalDeviceVulkan11Features));
+ memcpy(*ppNext, pNext, sizeof(VkPhysicalDeviceVulkan11Features));
+
+ auto features = (VkPhysicalDeviceVulkan11Features*)*ppNext;
+ features->samplerYcbcrConversion = vulkan11Features.samplerYcbcrConversion;
+ features->storagePushConstant16 = vulkan11Features.storagePushConstant16;
+ features->storageBuffer16BitAccess = vulkan11Features.storageBuffer16BitAccess;
+ features->uniformAndStorageBuffer16BitAccess = vulkan11Features.uniformAndStorageBuffer16BitAccess;
+
+ ppNext = (void**)((uint64_t)*ppNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: {
+ *ppNext = malloc(sizeof(VkPhysicalDeviceVulkan12Features));
+ memcpy(*ppNext, pNext, sizeof(VkPhysicalDeviceVulkan12Features));
+
+ auto features = (VkPhysicalDeviceVulkan12Features*)*ppNext;
+ features->timelineSemaphore = vulkan12Features.timelineSemaphore;
+ features->scalarBlockLayout = vulkan12Features.scalarBlockLayout;
+ features->bufferDeviceAddress = vulkan12Features.bufferDeviceAddress;
+ features->hostQueryReset = vulkan12Features.hostQueryReset;
+ features->storagePushConstant8 = vulkan12Features.storagePushConstant8;
+ features->shaderInt8 = vulkan12Features.shaderInt8;
+ features->storageBuffer8BitAccess = vulkan12Features.storageBuffer8BitAccess;
+ features->uniformAndStorageBuffer8BitAccess = vulkan12Features.uniformAndStorageBuffer8BitAccess;
+ features->shaderFloat16 = vulkan12Features.shaderFloat16;
+ features->shaderBufferInt64Atomics = vulkan12Features.shaderBufferInt64Atomics;
+ features->shaderSharedInt64Atomics = vulkan12Features.shaderSharedInt64Atomics;
+ features->vulkanMemoryModel = vulkan12Features.vulkanMemoryModel;
+ features->vulkanMemoryModelDeviceScope = vulkan12Features.vulkanMemoryModelDeviceScope;
+ features->uniformBufferStandardLayout = vulkan12Features.uniformBufferStandardLayout;
+
+ ppNext = (void**)((uint64_t)*ppNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: {
+ *ppNext = malloc(sizeof(VkPhysicalDeviceVulkan13Features));
+ memcpy(*ppNext, pNext, sizeof(VkPhysicalDeviceVulkan13Features));
+
+ auto features = (VkPhysicalDeviceVulkan13Features*)*ppNext;
+ features->dynamicRendering = vulkan13Features.dynamicRendering;
+ features->maintenance4 = vulkan13Features.maintenance4;
+ features->synchronization2 = vulkan13Features.synchronization2;
+ features->computeFullSubgroups = vulkan13Features.computeFullSubgroups;
+ features->subgroupSizeControl = vulkan13Features.subgroupSizeControl;
+ features->shaderZeroInitializeWorkgroupMemory = vulkan13Features.shaderZeroInitializeWorkgroupMemory;
+
+ ppNext = (void**)((uint64_t)*ppNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES: {
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES: {
+ *ppNext = malloc(sizeof(VkPhysicalDeviceVulkan14Features));
+ memcpy(*ppNext, pNext, sizeof(VkPhysicalDeviceVulkan14Features));
+
+ auto features = (VkPhysicalDeviceVulkan14Features*)*ppNext;
+ features->shaderSubgroupRotate = vulkan14Features.shaderSubgroupRotate;
+ features->hostImageCopy = vulkan14Features.hostImageCopy;
+ features->shaderExpectAssume = vulkan14Features.shaderExpectAssume;
+
+ ppNext = (void**)((uint64_t)*ppNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+
+ continue;
+ };
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceShaderSubgroupRotateFeatures);
+ auto next = (VkPhysicalDeviceShaderSubgroupRotateFeatures*)pNext;
+ next->shaderSubgroupRotate = shaderSubgroupFeatures.shaderSubgroupRotate;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT: {
+ size = sizeof(VkPhysicalDeviceHostImageCopyFeatures);
+ auto next = (VkPhysicalDeviceHostImageCopyFeatures*)pNext;
+ next->hostImageCopy = hostImageCopyFeatures.hostImageCopy;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceShaderExpectAssumeFeatures);
+ auto next = (VkPhysicalDeviceShaderExpectAssumeFeatures*)pNext;
+ next->shaderExpectAssume = shaderExpectAssumeFeatures.shaderExpectAssume;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceVideoMaintenance1FeaturesKHR);
+ auto next = (VkPhysicalDeviceVideoMaintenance1FeaturesKHR*)pNext;
+ next->videoMaintenance1 = videoMaintenance1Features.videoMaintenance1;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceVideoMaintenance2FeaturesKHR);
+ auto next = (VkPhysicalDeviceVideoMaintenance2FeaturesKHR*)pNext;
+ next->videoMaintenance2 = videoMaintenance2Features.videoMaintenance2;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceVideoDecodeVP9FeaturesKHR);
+ auto next = (VkPhysicalDeviceVideoDecodeVP9FeaturesKHR*)pNext;
+ next->videoDecodeVP9 = vp9Features.videoDecodeVP9;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT: {
+ size = sizeof(VkPhysicalDeviceShaderObjectFeaturesEXT);
+ auto next = (VkPhysicalDeviceShaderObjectFeaturesEXT*)pNext;
+ next->shaderObject = shaderObjectFeatures.shaderObject;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceCooperativeMatrixFeaturesKHR);
+ auto next = (VkPhysicalDeviceCooperativeMatrixFeaturesKHR*)pNext;
+ next->cooperativeMatrix = cooperativeMatrixFeatures.cooperativeMatrix;
+ next->cooperativeMatrixRobustBufferAccess = cooperativeMatrixFeatures.cooperativeMatrixRobustBufferAccess;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT: {
+ size = sizeof(VkPhysicalDeviceDescriptorBufferFeaturesEXT);
+ auto next = (VkPhysicalDeviceDescriptorBufferFeaturesEXT*)pNext;
+ next->descriptorBuffer = descriptorBufferFeatures.descriptorBuffer;
+ next->descriptorBufferPushDescriptors = descriptorBufferFeatures.descriptorBufferPushDescriptors;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT: {
+ size = sizeof(VkPhysicalDeviceShaderAtomicFloatFeaturesEXT);
+ auto next = (VkPhysicalDeviceShaderAtomicFloatFeaturesEXT*)pNext;
+ next->shaderBufferFloat32Atomics = shaderAtomicFloatFeatures.shaderBufferFloat32Atomics;
+ next->shaderBufferFloat32AtomicAdd = shaderAtomicFloatFeatures.shaderBufferFloat32AtomicAdd;
+ }; break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR: {
+ size = sizeof(VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR);
+ auto next = (VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR*)pNext;
+ next->shaderRelaxedExtendedInstruction = shaderRelaxFeatures.shaderRelaxedExtendedInstruction;
+ }; break;
+ case VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT: size = sizeof(VkDeviceDeviceMemoryReportCreateInfoEXT); break;
+ case VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV: size = sizeof(VkDeviceDiagnosticsConfigCreateInfoNV); break;
+ case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO: size = sizeof(VkDeviceGroupDeviceCreateInfo); break;
+ case VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD: size = sizeof(VkDeviceMemoryOverallocationCreateInfoAMD); break;
+ case VK_STRUCTURE_TYPE_DEVICE_PIPELINE_BINARY_INTERNAL_CACHE_CONTROL_KHR: size = sizeof(VkDevicePipelineBinaryInternalCacheControlKHR); break;
+ case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO: size = sizeof(VkDevicePrivateDataCreateInfo); break;
+ case VK_STRUCTURE_TYPE_DEVICE_QUEUE_SHADER_CORE_CONTROL_CREATE_INFO_ARM: size = sizeof(VkDeviceQueueShaderCoreControlCreateInfoARM); break;
+ case VK_STRUCTURE_TYPE_EXTERNAL_COMPUTE_QUEUE_DEVICE_CREATE_INFO_NV: size = sizeof(VkExternalComputeQueueDeviceCreateInfoNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT: size = sizeof(VkPhysicalDevice4444FormatsFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceASTCDecodeFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR: size = sizeof(VkPhysicalDeviceAccelerationStructureFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT: size = sizeof(VkPhysicalDeviceAddressBindingReportFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC: size = sizeof(VkPhysicalDeviceAmigoProfilingFeaturesSEC); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ANTI_LAG_FEATURES_AMD: size = sizeof(VkPhysicalDeviceAntiLagFeaturesAMD); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_DYNAMIC_STATE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT: size = sizeof(VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT: size = sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceBorderColorSwizzleFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceBufferDeviceAddressFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_FEATURES_NV: size = sizeof(VkPhysicalDeviceClusterAccelerationStructureFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_FEATURES_HUAWEI: size = sizeof(VkPhysicalDeviceClusterCullingShaderFeaturesHUAWEI); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD: size = sizeof(VkPhysicalDeviceCoherentMemoryFeaturesAMD); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceColorWriteEnableFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMMAND_BUFFER_INHERITANCE_FEATURES_NV: size = sizeof(VkPhysicalDeviceCommandBufferInheritanceFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR: size = sizeof(VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT: size = sizeof(VkPhysicalDeviceConditionalRenderingFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_FEATURES_NV: size = sizeof(VkPhysicalDeviceCooperativeMatrix2FeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV: size = sizeof(VkPhysicalDeviceCooperativeMatrixFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_FEATURES_NV: size = sizeof(VkPhysicalDeviceCooperativeVectorFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV: size = sizeof(VkPhysicalDeviceCopyMemoryIndirectFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV: size = sizeof(VkPhysicalDeviceCornerSampledImageFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV: size = sizeof(VkPhysicalDeviceCoverageReductionModeFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_CLAMP_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceCubicClampFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUBIC_WEIGHTS_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceCubicWeightsFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT: size = sizeof(VkPhysicalDeviceCustomBorderColorFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DATA_GRAPH_FEATURES_ARM: size = sizeof(VkPhysicalDeviceDataGraphFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEDICATED_ALLOCATION_IMAGE_ALIASING_FEATURES_NV: size = sizeof(VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_BIAS_CONTROL_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDepthBiasControlFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_CONTROL_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDepthClampControlFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_KHR: size = sizeof(VkPhysicalDeviceDepthClampZeroOneFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDepthClipControlFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDepthClipEnableFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_FEATURES_ARM: size = sizeof(VkPhysicalDeviceDescriptorBufferTensorFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES: size = sizeof(VkPhysicalDeviceDescriptorIndexingFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_POOL_OVERALLOCATION_FEATURES_NV: size = sizeof(VkPhysicalDeviceDescriptorPoolOverallocationFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE: size = sizeof(VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_COMPUTE_FEATURES_NV: size = sizeof(VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDeviceGeneratedCommandsFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV: size = sizeof(VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDeviceMemoryReportFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: size = sizeof(VkPhysicalDeviceDiagnosticsConfigFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES: size = sizeof(VkPhysicalDeviceDynamicRenderingLocalReadFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: size = sizeof(VkPhysicalDeviceExclusiveScissorFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT: size = sizeof(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT: size = sizeof(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceExtendedDynamicStateFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV: size = sizeof(VkPhysicalDeviceExtendedSparseAddressSpaceFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV: size = sizeof(VkPhysicalDeviceExternalMemoryRDMAFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT: size = sizeof(VkPhysicalDeviceFaultFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FORMAT_PACK_FEATURES_ARM: size = sizeof(VkPhysicalDeviceFormatPackFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT: size = sizeof(VkPhysicalDeviceFragmentDensityMap2FeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT: size = sizeof(VkPhysicalDeviceFragmentDensityMapFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_FEATURES_VALVE: size = sizeof(VkPhysicalDeviceFragmentDensityMapLayeredFeaturesVALVE); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_EXT: size = sizeof(VkPhysicalDeviceFragmentDensityMapOffsetFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR: size = sizeof(VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: size = sizeof(VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV: size = sizeof(VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR: size = sizeof(VkPhysicalDeviceFragmentShadingRateFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAME_BOUNDARY_FEATURES_EXT: size = sizeof(VkPhysicalDeviceFrameBoundaryFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES: size = sizeof(VkPhysicalDeviceGlobalPriorityQueryFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT: size = sizeof(VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HDR_VIVID_FEATURES_HUAWEI: size = sizeof(VkPhysicalDeviceHdrVividFeaturesHUAWEI); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT: size = sizeof(VkPhysicalDeviceImage2DViewOf3DFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_FEATURES_MESA: size = sizeof(VkPhysicalDeviceImageAlignmentControlFeaturesMESA); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT: size = sizeof(VkPhysicalDeviceImageCompressionControlFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT: size = sizeof(VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceImageProcessing2FeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceImageProcessingFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES: size = sizeof(VkPhysicalDeviceImageRobustnessFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_SLICED_VIEW_OF_3D_FEATURES_EXT: size = sizeof(VkPhysicalDeviceImageSlicedViewOf3DFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT: size = sizeof(VkPhysicalDeviceImageViewMinLodFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: size = sizeof(VkPhysicalDeviceImagelessFramebufferFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES: size = sizeof(VkPhysicalDeviceIndexTypeUint8Features); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV: size = sizeof(VkPhysicalDeviceInheritedViewportScissorFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES: size = sizeof(VkPhysicalDeviceInlineUniformBlockFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI: size = sizeof(VkPhysicalDeviceInvocationMaskFeaturesHUAWEI); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT: size = sizeof(VkPhysicalDeviceLegacyDitheringFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_FEATURES_EXT: size = sizeof(VkPhysicalDeviceLegacyVertexAttributesFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES: size = sizeof(VkPhysicalDeviceLineRasterizationFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV: size = sizeof(VkPhysicalDeviceLinearColorAttachmentFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES: size = sizeof(VkPhysicalDeviceMaintenance5Features); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_FEATURES: size = sizeof(VkPhysicalDeviceMaintenance6Features); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_FEATURES_KHR: size = sizeof(VkPhysicalDeviceMaintenance7FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_8_FEATURES_KHR: size = sizeof(VkPhysicalDeviceMaintenance8FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_FEATURES_KHR: size = sizeof(VkPhysicalDeviceMaintenance9FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAP_MEMORY_PLACED_FEATURES_EXT: size = sizeof(VkPhysicalDeviceMapMemoryPlacedFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV: size = sizeof(VkPhysicalDeviceMemoryDecompressionFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT: size = sizeof(VkPhysicalDeviceMemoryPriorityFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT: size = sizeof(VkPhysicalDeviceMeshShaderFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV: size = sizeof(VkPhysicalDeviceMeshShaderFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT: size = sizeof(VkPhysicalDeviceMultiDrawFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT: size = sizeof(VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: size = sizeof(VkPhysicalDeviceMultiviewFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_RENDER_AREAS_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceMultiviewPerViewRenderAreasFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_FEATURES_EXT: size = sizeof(VkPhysicalDeviceNestedCommandBufferFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT: size = sizeof(VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT: size = sizeof(VkPhysicalDeviceOpacityMicromapFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV: size = sizeof(VkPhysicalDeviceOpticalFlowFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT: size = sizeof(VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_FEATURES_NV: size = sizeof(VkPhysicalDevicePartitionedAccelerationStructureFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PER_STAGE_DESCRIPTOR_SET_FEATURES_NV: size = sizeof(VkPhysicalDevicePerStageDescriptorSetFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR: size = sizeof(VkPhysicalDevicePerformanceQueryFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_FEATURES_KHR: size = sizeof(VkPhysicalDevicePipelineBinaryFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CACHE_INCREMENTAL_MODE_FEATURES_SEC: size = sizeof(VkPhysicalDevicePipelineCacheIncrementalModeFeaturesSEC); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES: size = sizeof(VkPhysicalDevicePipelineCreationCacheControlFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_EXECUTABLE_PROPERTIES_FEATURES_KHR: size = sizeof(VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_LIBRARY_GROUP_HANDLES_FEATURES_EXT: size = sizeof(VkPhysicalDevicePipelineLibraryGroupHandlesFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_OPACITY_MICROMAP_FEATURES_ARM: size = sizeof(VkPhysicalDevicePipelineOpacityMicromapFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT: size = sizeof(VkPhysicalDevicePipelinePropertiesFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES: size = sizeof(VkPhysicalDevicePipelineProtectedAccessFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES: size = sizeof(VkPhysicalDevicePipelineRobustnessFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV: size = sizeof(VkPhysicalDevicePresentBarrierFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_2_FEATURES_KHR: size = sizeof(VkPhysicalDevicePresentId2FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR: size = sizeof(VkPhysicalDevicePresentIdFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_MODE_FIFO_LATEST_READY_FEATURES_KHR: size = sizeof(VkPhysicalDevicePresentModeFifoLatestReadyFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_2_FEATURES_KHR: size = sizeof(VkPhysicalDevicePresentWait2FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR: size = sizeof(VkPhysicalDevicePresentWaitFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT: size = sizeof(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT: size = sizeof(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES: size = sizeof(VkPhysicalDevicePrivateDataFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: size = sizeof(VkPhysicalDeviceProtectedMemoryFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT: size = sizeof(VkPhysicalDeviceProvokingVertexFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV: size = sizeof(VkPhysicalDeviceRawAccessChainsFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR: size = sizeof(VkPhysicalDeviceRayQueryFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV: size = sizeof(VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_LINEAR_SWEPT_SPHERES_FEATURES_NV: size = sizeof(VkPhysicalDeviceRayTracingLinearSweptSpheresFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR: size = sizeof(VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV: size = sizeof(VkPhysicalDeviceRayTracingMotionBlurFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR: size = sizeof(VkPhysicalDeviceRayTracingPipelineFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_POSITION_FETCH_FEATURES_KHR: size = sizeof(VkPhysicalDeviceRayTracingPositionFetchFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_VALIDATION_FEATURES_NV: size = sizeof(VkPhysicalDeviceRayTracingValidationFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RELAXED_LINE_RASTERIZATION_FEATURES_IMG: size = sizeof(VkPhysicalDeviceRelaxedLineRasterizationFeaturesIMG); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_FEATURES_ARM: size = sizeof(VkPhysicalDeviceRenderPassStripedFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV: size = sizeof(VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_KHR: size = sizeof(VkPhysicalDeviceRobustness2FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_FEATURES_ARM: size = sizeof(VkPhysicalDeviceSchedulingControlsFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES: size = sizeof(VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV: size = sizeof(VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT: size = sizeof(VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_BFLOAT16_FEATURES_KHR: size = sizeof(VkPhysicalDeviceShaderBfloat16FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CLOCK_FEATURES_KHR: size = sizeof(VkPhysicalDeviceShaderClockFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM: size = sizeof(VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES: size = sizeof(VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: size = sizeof(VkPhysicalDeviceShaderDrawParametersFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD: size = sizeof(VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT8_FEATURES_EXT: size = sizeof(VkPhysicalDeviceShaderFloat8FeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT_CONTROLS_2_FEATURES: size = sizeof(VkPhysicalDeviceShaderFloatControls2Features); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT: size = sizeof(VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV: size = sizeof(VkPhysicalDeviceShaderImageFootprintFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES: size = sizeof(VkPhysicalDeviceShaderIntegerDotProductFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: size = sizeof(VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MAXIMAL_RECONVERGENCE_FEATURES_KHR: size = sizeof(VkPhysicalDeviceShaderMaximalReconvergenceFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT: size = sizeof(VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_QUAD_CONTROL_FEATURES_KHR: size = sizeof(VkPhysicalDeviceShaderQuadControlFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_REPLICATED_COMPOSITES_FEATURES_EXT: size = sizeof(VkPhysicalDeviceShaderReplicatedCompositesFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV: size = sizeof(VkPhysicalDeviceShaderSMBuiltinsFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES: size = sizeof(VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR: size = sizeof(VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES: size = sizeof(VkPhysicalDeviceShaderTerminateInvocationFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceShaderTileImageFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_UNTYPED_POINTERS_FEATURES_KHR: size = sizeof(VkPhysicalDeviceShaderUntypedPointersFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV: size = sizeof(VkPhysicalDeviceShadingRateImageFeaturesNV); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT: size = sizeof(VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI: size = sizeof(VkPhysicalDeviceSubpassShadingFeaturesHUAWEI); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR: size = sizeof(VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_FEATURES_ARM: size = sizeof(VkPhysicalDeviceTensorFeaturesARM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: size = sizeof(VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES: size = sizeof(VkPhysicalDeviceTextureCompressionASTCHDRFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceTileMemoryHeapFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceTilePropertiesFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceTileShadingFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT: size = sizeof(VkPhysicalDeviceTransformFeedbackFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFIED_IMAGE_LAYOUTS_FEATURES_KHR: size = sizeof(VkPhysicalDeviceUnifiedImageLayoutsFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: size = sizeof(VkPhysicalDeviceVariablePointersFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES: size = sizeof(VkPhysicalDeviceVertexAttributeDivisorFeatures); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_ROBUSTNESS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceVertexAttributeRobustnessFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT: size = sizeof(VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_AV1_FEATURES_KHR: size = sizeof(VkPhysicalDeviceVideoEncodeAV1FeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_INTRA_REFRESH_FEATURES_KHR: size = sizeof(VkPhysicalDeviceVideoEncodeIntraRefreshFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_ENCODE_QUANTIZATION_MAP_FEATURES_KHR: size = sizeof(VkPhysicalDeviceVideoEncodeQuantizationMapFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR: size = sizeof(VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_DEGAMMA_FEATURES_QCOM: size = sizeof(VkPhysicalDeviceYcbcrDegammaFeaturesQCOM); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_IMAGE_ARRAYS_FEATURES_EXT: size = sizeof(VkPhysicalDeviceYcbcrImageArraysFeaturesEXT); break;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_DEVICE_MEMORY_FEATURES_EXT: size = sizeof(VkPhysicalDeviceZeroInitializeDeviceMemoryFeaturesEXT); break;
+ };
+
+ *ppNext = malloc(size);
+ memcpy(*ppNext, pNext, size);
+ ppNext = (void **)((uint64_t)*ppNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ pNext = *(const void**)((uint64_t)pNext + offsetof(VkPhysicalDeviceFeatures2, pNext));
+ }
+
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES] == false) {
+ auto next = (VkPhysicalDeviceVulkan11Features*)malloc(sizeof(VkPhysicalDeviceVulkan11Features));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
+ next->samplerYcbcrConversion = vulkan11Features.samplerYcbcrConversion;
+ next->storagePushConstant16 = vulkan11Features.storagePushConstant16;
+ next->storageBuffer16BitAccess = vulkan11Features.storageBuffer16BitAccess;
+ next->uniformAndStorageBuffer16BitAccess = vulkan11Features.uniformAndStorageBuffer16BitAccess;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES] == false) {
+ auto next = (VkPhysicalDeviceVulkan12Features*)malloc(sizeof(VkPhysicalDeviceVulkan12Features));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
+ next->timelineSemaphore = vulkan12Features.timelineSemaphore;
+ next->scalarBlockLayout = vulkan12Features.scalarBlockLayout;
+ next->bufferDeviceAddress = vulkan12Features.bufferDeviceAddress;
+ next->hostQueryReset = vulkan12Features.hostQueryReset;
+ next->storagePushConstant8 = vulkan12Features.storagePushConstant8;
+ next->shaderInt8 = vulkan12Features.shaderInt8;
+ next->storageBuffer8BitAccess = vulkan12Features.storageBuffer8BitAccess;
+ next->uniformAndStorageBuffer8BitAccess = vulkan12Features.uniformAndStorageBuffer8BitAccess;
+ next->shaderFloat16 = vulkan12Features.shaderFloat16;
+ next->shaderBufferInt64Atomics = vulkan12Features.shaderBufferInt64Atomics;
+ next->shaderSharedInt64Atomics = vulkan12Features.shaderSharedInt64Atomics;
+ next->vulkanMemoryModel = vulkan12Features.vulkanMemoryModel;
+ next->vulkanMemoryModelDeviceScope = vulkan12Features.vulkanMemoryModelDeviceScope;
+ next->uniformBufferStandardLayout = vulkan12Features.uniformBufferStandardLayout;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES] == false) {
+ auto next = (VkPhysicalDeviceVulkan13Features*)malloc(sizeof(VkPhysicalDeviceVulkan13Features));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
+ next->dynamicRendering = vulkan13Features.dynamicRendering;
+ next->maintenance4 = vulkan13Features.maintenance4;
+ next->synchronization2 = vulkan13Features.synchronization2;
+ next->computeFullSubgroups = vulkan13Features.computeFullSubgroups;
+ next->subgroupSizeControl = vulkan13Features.subgroupSizeControl;
+ next->shaderZeroInitializeWorkgroupMemory = vulkan13Features.shaderZeroInitializeWorkgroupMemory;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR] == false && DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES] == false) {
+ auto next = (VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR*)malloc(sizeof(VkPhysicalDeviceShaderSubgroupRotateFeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_ROTATE_FEATURES_KHR;
+ next->shaderSubgroupRotate = shaderSubgroupFeatures.shaderSubgroupRotate;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT] == false && DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES] == false) {
+ auto next = (VkPhysicalDeviceHostImageCopyFeaturesEXT*)malloc(sizeof(VkPhysicalDeviceHostImageCopyFeaturesEXT));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_FEATURES_EXT;
+ next->hostImageCopy = hostImageCopyFeatures.hostImageCopy;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR] == false && DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES] == false) {
+ auto next = (VkPhysicalDeviceShaderExpectAssumeFeaturesKHR*)malloc(sizeof(VkPhysicalDeviceShaderExpectAssumeFeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EXPECT_ASSUME_FEATURES_KHR;
+ next->shaderExpectAssume = shaderExpectAssumeFeatures.shaderExpectAssume;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR] == false) {
+ auto next = (VkPhysicalDeviceVideoMaintenance1FeaturesKHR*)malloc(sizeof(VkPhysicalDeviceVideoMaintenance1FeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_1_FEATURES_KHR;
+ next->videoMaintenance1 = videoMaintenance1Features.videoMaintenance1;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR] == false) {
+ auto next = (VkPhysicalDeviceVideoMaintenance2FeaturesKHR*)malloc(sizeof(VkPhysicalDeviceVideoMaintenance2FeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_MAINTENANCE_2_FEATURES_KHR;
+ next->videoMaintenance2 = videoMaintenance2Features.videoMaintenance2;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR] == false) {
+ auto next = (VkPhysicalDeviceVideoDecodeVP9FeaturesKHR*)malloc(sizeof(VkPhysicalDeviceVideoDecodeVP9FeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_DECODE_VP9_FEATURES_KHR;
+ next->videoDecodeVP9 = vp9Features.videoDecodeVP9;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT] == false) {
+ auto next = (VkPhysicalDeviceShaderObjectFeaturesEXT*)malloc(sizeof(VkPhysicalDeviceShaderObjectFeaturesEXT));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT;
+ next->shaderObject = shaderObjectFeatures.shaderObject;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR] == false) {
+ auto next = (VkPhysicalDeviceCooperativeMatrixFeaturesKHR*)malloc(sizeof(VkPhysicalDeviceCooperativeMatrixFeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR;
+ next->cooperativeMatrix = cooperativeMatrixFeatures.cooperativeMatrix;
+ next->cooperativeMatrixRobustBufferAccess = cooperativeMatrixFeatures.cooperativeMatrixRobustBufferAccess;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT] == false) {
+ auto next = (VkPhysicalDeviceDescriptorBufferFeaturesEXT*)malloc(sizeof(VkPhysicalDeviceDescriptorBufferFeaturesEXT));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT;
+ next->descriptorBuffer = descriptorBufferFeatures.descriptorBuffer;
+ next->descriptorBufferPushDescriptors = descriptorBufferFeatures.descriptorBufferPushDescriptors;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT] == false) {
+ auto next = (VkPhysicalDeviceShaderAtomicFloatFeaturesEXT*)malloc(sizeof(VkPhysicalDeviceShaderAtomicFloatFeaturesEXT));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT;
+ next->shaderBufferFloat32Atomics = shaderAtomicFloatFeatures.shaderBufferFloat32Atomics;
+ next->shaderBufferFloat32AtomicAdd = shaderAtomicFloatFeatures.shaderBufferFloat32AtomicAdd;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ if (DesiredFeatures[VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR] == false) {
+ auto next = (VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR*)malloc(sizeof(VkPhysicalDeviceShaderRelaxedExtendedInstructionFeaturesKHR));
+ *next = {};
+ next->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_RELAXED_EXTENDED_INSTRUCTION_FEATURES_KHR;
+ next->shaderRelaxedExtendedInstruction = shaderRelaxFeatures.shaderRelaxedExtendedInstruction;
+ *ppNext = next;
+ ppNext = &next->pNext;
+ }
+ *ppNext = nullptr;
+
+ uint32_t queue_family_count = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queue_family_count, nullptr);
+
+ VkQueueFamilyProperties2* queue_familes = (VkQueueFamilyProperties2*)malloc(sizeof(VkQueueFamilyProperties2) * queue_family_count);
+ VkQueueFamilyVideoPropertiesKHR* queue_video_props = (VkQueueFamilyVideoPropertiesKHR*)malloc(sizeof(VkQueueFamilyVideoPropertiesKHR) * queue_family_count);
+ for (uint32_t i = 0; i < queue_family_count; i++) {
+ queue_familes[i] = {};
+ queue_familes[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
+ queue_familes[i].pNext = &queue_video_props[i];
+ queue_video_props[i] = {};
+ queue_video_props[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR;
+ queue_video_props[i].pNext = nullptr;
+ }
+
+ vkGetPhysicalDeviceQueueFamilyProperties2(physicalDevice, &queue_family_count, queue_familes);
+
+ uint32_t graphics_queue_family = -1;
+ uint32_t graphics_queue_family_flag_count = -1;
+ uint32_t compute_queue_family = -1;
+ uint32_t compute_queue_family_flag_count = -1;
+ uint32_t transfer_queue_family = -1;
+ uint32_t transfer_queue_family_flag_count = -1;
+ uint32_t video_decode_queue_family = -1;
+ uint32_t video_decode_queue_family_flag_count = -1;
+
+ for (uint32_t i = 0; i < queue_family_count; i++) {
+ uint32_t flag_count = 0;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_TRANSFER_BIT || queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT || queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_PROTECTED_BIT) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_ENCODE_BIT_KHR) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_OPTICAL_FLOW_BIT_NV) flag_count++;
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_DATA_GRAPH_BIT_ARM) flag_count++;
+
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT && flag_count < graphics_queue_family_flag_count) {
+ graphics_queue_family = i;
+ graphics_queue_family_flag_count = flag_count;
+ }
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT && flag_count < compute_queue_family_flag_count) {
+ compute_queue_family = i;
+ graphics_queue_family_flag_count = flag_count;
+ }
+ if ((queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_TRANSFER_BIT || queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT || queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT) && flag_count < transfer_queue_family_flag_count) {
+ transfer_queue_family = i;
+ transfer_queue_family_flag_count = flag_count;
+ }
+ if (queue_familes[i].queueFamilyProperties.queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR && flag_count < video_decode_queue_family_flag_count) {
+ video_decode_queue_family = i;
+ video_decode_queue_family_flag_count = flag_count;
+ }
+ }
+
+ std::set unique_queues = { graphics_queue_family, compute_queue_family, transfer_queue_family, video_decode_queue_family };
+
+ for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
+ unique_queues.insert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex);
+ }
+
+ auto queueCreateInfos = (VkDeviceQueueCreateInfo*)malloc(sizeof(VkDeviceQueueCreateInfo) * unique_queues.size());
+ vkQueueFamilies.reserve(unique_queues.size());
+ uint32_t i = 0;
+ for (auto& queue : unique_queues) {
+ queueCreateInfos[i] = {};
+ queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queueCreateInfos[i].pNext = nullptr;
+ queueCreateInfos[i].queueFamilyIndex = queue;
+ queueCreateInfos[i].queueCount = queue_familes[queue].queueFamilyProperties.queueCount;
+
+ auto priorities = (float*)malloc(sizeof(float) * queue_familes[queue].queueFamilyProperties.queueCount);
+ for (uint32_t j = 0; j < queue_familes[queue].queueFamilyProperties.queueCount; j++) {
+ priorities[j] = 1.0;
+ }
+ queueCreateInfos[i].pQueuePriorities = priorities;
+
+ AVVulkanDeviceQueueFamily qf = {};
+ qf.idx = queue;
+ qf.num = queue_familes[queue].queueFamilyProperties.queueCount;
+ qf.flags = (VkQueueFlagBits)queue_familes[queue].queueFamilyProperties.queueFlags;
+ qf.video_caps = (VkVideoCodecOperationFlagBitsKHR)queue_video_props[queue].videoCodecOperations;
+ vkQueueFamilies.push_back(qf);
+
+ i++;
+ }
+
+ free(queue_familes);
+ free(queue_video_props);
+
+ const char* const* ppEnabledExtensionNames = pCreateInfo->ppEnabledExtensionNames;
+ uint32_t enabledExtensionCount = pCreateInfo->enabledExtensionCount;
+ pNext = pCreateInfo->pNext;
+ const VkPhysicalDeviceFeatures* pEnabledFeatures = pCreateInfo->pEnabledFeatures;
+ const VkDeviceQueueCreateInfo* pQueueCreateInfos = pCreateInfo->pQueueCreateInfos;
+ uint32_t queueCreateInfoCount = pCreateInfo->queueCreateInfoCount;
+ pCreateInfo->ppEnabledExtensionNames = vkDeviceExtensions.data();
+ pCreateInfo->enabledExtensionCount = vkDeviceExtensions.size();
+ pCreateInfo->pNext = &vkDeviceFeatures;
+ pCreateInfo->pEnabledFeatures = nullptr;
+ pCreateInfo->pQueueCreateInfos = queueCreateInfos;
+ pCreateInfo->queueCreateInfoCount = unique_queues.size();
+
+ VkResult res = originalVkCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
+
+ pCreateInfo->ppEnabledExtensionNames = ppEnabledExtensionNames;
+ pCreateInfo->enabledExtensionCount = enabledExtensionCount;
+ pCreateInfo->pNext = pNext;
+ pCreateInfo->pEnabledFeatures = pEnabledFeatures;
+ pCreateInfo->pQueueCreateInfos = pQueueCreateInfos;
+ pCreateInfo->queueCreateInfoCount = queueCreateInfoCount;
+
+ for (uint32_t i = 0; i < unique_queues.size(); i++) {
+ free((float*)queueCreateInfos[i].pQueuePriorities);
+ }
+ free(queueCreateInfos);
+
+ if (res == VK_SUCCESS) {
+ volkLoadDevice(vkDevice);
+ }
+ return res;
+}
+
+HOOK(VkResult, __fastcall, VkCreateInstance, nullptr, VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) {
+ vkInstanceExtensions.reserve(pCreateInfo->enabledExtensionCount);
+ for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
+ vkInstanceExtensions.push_back((char*)calloc(strlen(pCreateInfo->ppEnabledExtensionNames[i]) + 1, sizeof(char)));
+ strcpy(vkInstanceExtensions.at(i), pCreateInfo->ppEnabledExtensionNames[i]);
+ }
+ vkVersion = pCreateInfo->pApplicationInfo->apiVersion;
+
+ VkResult res = originalVkCreateInstance(pCreateInfo, pAllocator, pInstance);
+
+ if (res == VK_SUCCESS && VK_VERSION_MAJOR(vkVersion) >= 1 && VK_VERSION_MINOR(vkVersion) >= 3) {
+ volkLoadInstance(*pInstance);
+ originalVkCreateDevice = (VkCreateDeviceDelegate*)vkCreateDevice;
+ INSTALL_HOOK(VkCreateDevice);
+ }
+ return res;
+}
+
+void MoviePlayer::preInit() {
+ INSTALL_HOOK(TaskMovieInit);
+}
+
+void MoviePlayer::init() {
+ INSTALL_HOOK(TaskMovieCheckDisp);
+ INSTALL_HOOK(TaskMovieCtrl);
+ INSTALL_HOOK(TaskMovieCtrlPlayer);
+ INSTALL_HOOK(TaskMovieDisp);
+ INSTALL_HOOK(TaskMovieGetTexture);
+ INSTALL_HOOK(TaskMovieReset);
+ INSTALL_HOOK(TaskMovieStart);
+
+ // Remove ResolveFilePath before TaskMovie::Start
+ WRITE_NOP(0x14025AF89, 9);
+ WRITE_NOP(0x14024ADF0, 9);
+ // Skip replacing extension with .usm
+ WRITE_MEMORY(0x14025AEC7, uint8_t, 0x90, 0xE9);
+
+ HMODULE dllHandle = GetModuleHandle("ntdll.dll");
+ if (dllHandle != nullptr && GetProcAddress(dllHandle, "wine_get_version") != nullptr) {
+ VkResult res = volkInitialize();
+ if (res != VK_SUCCESS) {
+ MessageBoxA(nullptr, "Failed to init vulkan", "MoviePlayer::d3dInit", MB_OK | MB_ICONERROR);
+ return;
+ }
+
+ vulkan = true;
+ originalVkCreateInstance = (VkCreateInstanceDelegate*)vkCreateInstance;
+ INSTALL_HOOK(VkCreateInstance);
+ }
+}
+
+void MoviePlayer::d3dInit(IDXGISwapChain* swapChain, ID3D11Device* device, ID3D11DeviceContext* deviceContext) {
+ d3d11SwapChain = swapChain;
+ d3d11Device = device;
+ d3d11DeviceContext = deviceContext;
+
+ device->CreateVertexShader(vs_bytecode, sizeof(vs_bytecode), nullptr, &shader_vs);
+ device->CreatePixelShader(bt601_full_bytecode, sizeof(bt601_full_bytecode), nullptr, &shader_bt601_full);
+ device->CreatePixelShader(bt601_limited_bytecode, sizeof(bt601_limited_bytecode), nullptr, &shader_bt601_limited);
+ device->CreatePixelShader(bt709_full_bytecode, sizeof(bt709_full_bytecode), nullptr, &shader_bt709_full);
+ device->CreatePixelShader(bt709_limited_bytecode, sizeof(bt709_limited_bytecode), nullptr, &shader_bt709_limited);
+ device->CreatePixelShader(bt2020_full_bytecode, sizeof(bt2020_full_bytecode), nullptr, &shader_bt2020_full);
+ device->CreatePixelShader(bt2020_limited_bytecode, sizeof(bt2020_limited_bytecode), nullptr, &shader_bt2020_limited);
+
+ IDXGIVkInteropDevice1* vkInteropDevice = nullptr;
+ d3d11Device->QueryInterface(&vkInteropDevice);
+ if (vulkan && vkInteropDevice != nullptr && VK_VERSION_MAJOR(vkVersion) >= 1 && VK_VERSION_MINOR(vkVersion) >= 3) {
+ vkInteropDevice->GetVulkanHandles(&vkInstance, &vkPhysDevice, &vkDevice);
+ }
+ else {
+ vulkan = false;
+ }
+}
\ No newline at end of file
diff --git a/Source/DivaModLoader/MoviePlayer.h b/Source/DivaModLoader/MoviePlayer.h
new file mode 100644
index 0000000..80784a2
--- /dev/null
+++ b/Source/DivaModLoader/MoviePlayer.h
@@ -0,0 +1,7 @@
+#pragma once
+
+struct MoviePlayer {
+ static void preInit();
+ static void init();
+ static void d3dInit(IDXGISwapChain *swapChain, ID3D11Device* device, ID3D11DeviceContext* deviceContext);
+};
\ No newline at end of file
diff --git a/Source/DivaModLoader/MoviePlayer.hlsl b/Source/DivaModLoader/MoviePlayer.hlsl
new file mode 100644
index 0000000..cd44d99
--- /dev/null
+++ b/Source/DivaModLoader/MoviePlayer.hlsl
@@ -0,0 +1,51 @@
+#if defined (__INTELLISENSE__)
+#define BT709
+#define FULL
+#endif
+
+Texture2D luminance : register(t0);
+Texture2D chrominance : register(t1);
+SamplerState Sampler : register(s0);
+
+#if defined(BT601)
+static const float Kb = 0.114;
+static const float Kr = 0.299;
+static const float Kg = 1 - Kb - Kr;
+#elif defined(BT709)
+static const float Kb = 0.0722;
+static const float Kr = 0.2126;
+static const float Kg = 1 - Kb - Kr;
+#elif defined(BT2020)
+static const float Kb = 0.0593;
+static const float Kr = 0.2627;
+static const float Kg = 1 - Kb - Kr;
+#endif
+
+static const float3x3 YCbCrRgbMatrix =
+{
+ 1, 0, 2 - 2 * Kr,
+ 1, -(Kb / Kg) * (2 - 2 * Kb), -(Kr / Kg) * (2 - 2 * Kr),
+ 1, 2 - 2 * Kb, 0
+};
+
+void vs(in uint vertexId : SV_VertexID, out float4 position : SV_Position, out float2 texCoord : TEXCOORD)
+{
+ texCoord = float2((vertexId << 1) & 2, vertexId & 2);
+ position = float4(texCoord * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
+}
+
+void ps(in float4 position : SV_Position, in float2 texCoord : TEXCOORD, out float4 color : SV_TARGET)
+{
+ float Y = luminance.SampleLevel(Sampler, texCoord, 0);
+ float2 CbCr = chrominance.SampleLevel(Sampler, texCoord, 0);
+
+#if defined(FULL)
+ CbCr = CbCr - (128.0 / 255.0);
+#elif defined (LIMITED)
+ Y = Y * (255.0 / 219.0) - (16.0 / 219.0);
+ CbCr = CbCr * (255.0 / 224.0) - (128.0 / 224.0);
+#endif
+
+ float3 RGB = mul(YCbCrRgbMatrix, float3(Y, CbCr));
+ color = float4(RGB, 1.0);
+}
\ No newline at end of file
diff --git a/Source/DivaModLoader/Pch.cpp b/Source/DivaModLoader/Pch.cpp
index 33274ba..360da61 100644
--- a/Source/DivaModLoader/Pch.cpp
+++ b/Source/DivaModLoader/Pch.cpp
@@ -1 +1,4 @@
#include "Pch.h"
+
+#define VOLK_IMPLEMENTATION
+#include
diff --git a/Source/DivaModLoader/Pch.h b/Source/DivaModLoader/Pch.h
index dddfe9d..51dc7c2 100644
--- a/Source/DivaModLoader/Pch.h
+++ b/Source/DivaModLoader/Pch.h
@@ -5,10 +5,14 @@
#undef _ITERATOR_DEBUG_LEVEL
#define _ITERATOR_DEBUG_LEVEL 0
+#define VK_USE_PLATFORM_WIN32_KHR
+#define VK_NO_PROTOTYPES
+
#include
#include
#include
+#include
#include
#include
@@ -25,5 +29,16 @@
#include
#include
+extern "C" {
+#include
+#include
+#include
+#include
+}
+
+#include
+
+#include
+
#undef _ITERATOR_DEBUG_LEVEL
#pragma pop_macro("_ITERATOR_DEBUG_LEVEL")
\ No newline at end of file