Lazy initialization for DLL library

This commit is contained in:
2025-09-28 19:41:58 +09:00
parent 3ab4ab14c6
commit 5d70d9d3d2
12 changed files with 181 additions and 58 deletions

View File

@@ -6,7 +6,11 @@
<ItemGroup>
<Page Include="MainWindow.xaml" />
<Page Include="VideoPlayerControl.xaml" />
<Page Include="MultiVideoTestWindow.xaml" />
<Page Include="MainVideoPage.xaml" />
<Page Include="MultiVideoPage.xaml" />
<Page Include="LayeredVideoPage.xaml" />
<Page Include="LogMessagePage.xaml" />
<Page Include="SettingsPage.xaml" />
</ItemGroup>
<ItemGroup>
<Midl Include="MainWindow.idl" />
@@ -14,12 +18,24 @@
<ItemGroup>
<ClCompile Include="pch.cpp" />
<ClCompile Include="$(GeneratedFilesDir)module.g.cpp" />
<ClCompile Include="src\Rendering\D3D12VideoRenderer.cpp" />
<ClCompile Include="src\Rendering\GlobalD3D12SyncManager.cpp" />
<ClCompile Include="src\Rendering\SimpleGPURenderer.cpp" />
<ClCompile Include="src\Logger\LogManager.cpp" />
<ClCompile Include="src\Logger\LogOutputs.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="src\Rendering\D3D12VideoRenderer.h" />
<ClInclude Include="src\Rendering\SimpleGPURenderer.h" />
<ClInclude Include="src\Rendering\GlobalD3D12SyncManager.h" />
<ClInclude Include="src\Rendering\d3dx12.h" />
<ClInclude Include="src\Rendering\IVideoRenderer.h" />
<ClInclude Include="src\Logger\SimpleLogger.h" />
<ClInclude Include="src\Logger\ILogManager.h" />
<ClInclude Include="src\Logger\ILogOutput.h" />
<ClInclude Include="src\Logger\LogManager.h" />
<ClInclude Include="src\Logger\LogOutputs.h" />
</ItemGroup>
<ItemGroup>
<Image Include="Assets\Wide310x150Logo.scale-200.png">

View File

@@ -45,8 +45,6 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)lib\</OutDir>
<IntDir>$(ProjectDir)obj\$(Configuration)\</IntDir>
<TargetName>VavCore-debug</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -77,6 +75,11 @@
<AdditionalDependencies>webm-debug.lib;dav1d-debug.lib;amf-debug.lib;vpld.lib;mfplat.lib;mf.lib;mfuuid.lib;nvcuvid.lib;cuda.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\..\lib\libwebm;$(ProjectDir)..\..\..\..\lib\dav1d;$(ProjectDir)..\..\..\..\lib\amf;$(ProjectDir)..\..\..\..\lib\libvpl;$(ProjectDir)..\..\..\..\oss\nvidia-video-codec\Lib\x64;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Lib>
<PostBuildEvent>
<Command>echo Copying VavCore Debug DLL...
copy "$(TargetPath)" "$(ProjectDir)lib\$(TargetFileName)"
echo DLL copy completed.</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@@ -90,6 +93,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)..\..\..\..\include\libwebm;$(ProjectDir)..\..\..\..\include\dav1d;$(ProjectDir)..\..\..\..\include\amf;$(ProjectDir)..\..\..\..\include\libvpl;$(ProjectDir)..\..\..\..\oss\nvidia-video-codec\Interface;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
<StringPooling>true</StringPooling>
</ClCompile>
<Link>
<SubSystem>
@@ -99,6 +103,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>webm.lib;dav1d.lib;amf.lib;vpl.lib;mfplat.lib;mf.lib;mfuuid.lib;nvcuvid.lib;cuda.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\..\lib\libwebm;$(ProjectDir)..\..\..\..\lib\dav1d;$(ProjectDir)..\..\..\..\lib\amf;$(ProjectDir)..\..\..\..\lib\libvpl;$(ProjectDir)..\..\..\..\oss\nvidia-video-codec\Lib\x64;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>/OPT:REF /OPT:ICF=5 /OPT:LBR %(AdditionalOptions)</AdditionalOptions>
</Link>
<Lib>
<AdditionalDependencies>webm.lib;dav1d.lib;amf.lib;vpl.lib;mfplat.lib;mf.lib;mfuuid.lib;nvcuvid.lib;cuda.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
@@ -109,8 +114,8 @@
echo "Copying VavCore DLL to Godot extension directory..."
if not exist "$(ProjectDir)..\godot-plugin\libs\windows-x86_64\" mkdir "$(ProjectDir)..\godot-plugin\libs\windows-x86_64\"
copy "$(TargetPath)" "$(ProjectDir)..\godot-plugin\libs\windows-x86_64\"
echo "VavCore DLL copied successfully"
</Command>
copy "$(TargetPath)" "$(ProjectDir)lib\$(TargetFileName)"
echo "VavCore DLL copied successfully"</Command>
<Message>Installing VavCore DLL to Godot extension</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
@@ -137,6 +142,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="src\VavCore.cpp" />
<ClCompile Include="src\DllMain.cpp" />
<ClCompile Include="src\Decoder\AV1Decoder.cpp" />
<ClCompile Include="src\Decoder\AdaptiveAV1Decoder.cpp" />
<ClCompile Include="src\Decoder\AdaptiveNVDECDecoder.cpp" />

View File

@@ -1,4 +1,4 @@
#include "pch.h"
#include "pch.h"
#include <sstream>
// MUST follow header include order to avoid build error
@@ -869,14 +869,5 @@ void RegisterAMFDecoders() {
});
}
// Static initialization for registration
namespace {
struct AMFDecoderRegistration {
AMFDecoderRegistration() {
RegisterAMFDecoders();
}
};
static AMFDecoderRegistration s_amfRegistration;
}
} // namespace VavCore

View File

@@ -293,7 +293,5 @@ void RegisterAV1Decoders() {
});
}
// Static initialization for auto-registration
static bool s_av1_registered = (RegisterAV1Decoders(), true);
} // namespace VavCore

View File

@@ -952,8 +952,6 @@ void RegisterAndroidMediaCodecDecoders() {
});
}
// Static initialization for auto-registration (Android only)
static bool s_mediacodec_registered = (RegisterAndroidMediaCodecDecoders(), true);
} // namespace VavCore

View File

@@ -1,4 +1,4 @@
#include "pch.h"
#include "pch.h"
#include "MediaFoundationAV1Decoder.h"
#include <sstream>
#include <iomanip>

View File

@@ -689,7 +689,5 @@ void RegisterNVDECDecoders() {
});
}
// Static initialization for auto-registration
static bool s_nvdec_registered = (RegisterNVDECDecoders(), true);
} // namespace VavCore

View File

@@ -1,4 +1,4 @@
#include "pch.h"
#include "pch.h"
#include "VPLAV1Decoder.h"
#include "VideoDecoderFactory.h"
#include <iostream>
@@ -1019,7 +1019,5 @@ void RegisterVPLDecoders() {
});
}
// Static initialization for auto-registration
static bool s_vpl_registered = (RegisterVPLDecoders(), true);
} // namespace VavCore

View File

@@ -5,9 +5,6 @@
namespace VavCore {
// Static member initialization
std::vector<DecoderRegistration> VideoDecoderFactory::s_av1_decoders;
std::vector<DecoderRegistration> VideoDecoderFactory::s_vp9_decoders;
std::unique_ptr<IVideoDecoder> VideoDecoderFactory::CreateDecoder(VideoCodecType codec_type, DecoderType decoder_type) {
auto& decoders = GetDecoderList(codec_type);
@@ -163,10 +160,11 @@ std::vector<std::string> VideoDecoderFactory::GetAvailableDecoders(VideoCodecTyp
}
void VideoDecoderFactory::RegisterAV1Decoder(const DecoderRegistration& registration) {
s_av1_decoders.push_back(registration);
auto& decoders = GetDecoderList(VideoCodecType::AV1);
decoders.push_back(registration);
// Sort by priority (lower numbers = higher priority)
std::sort(s_av1_decoders.begin(), s_av1_decoders.end(), [](const auto& a, const auto& b) {
std::sort(decoders.begin(), decoders.end(), [](const auto& a, const auto& b) {
return a.priority < b.priority;
});
@@ -175,10 +173,11 @@ void VideoDecoderFactory::RegisterAV1Decoder(const DecoderRegistration& registra
}
void VideoDecoderFactory::RegisterVP9Decoder(const DecoderRegistration& registration) {
s_vp9_decoders.push_back(registration);
auto& decoders = GetDecoderList(VideoCodecType::VP9);
decoders.push_back(registration);
// Sort by priority (lower numbers = higher priority)
std::sort(s_vp9_decoders.begin(), s_vp9_decoders.end(), [](const auto& a, const auto& b) {
std::sort(decoders.begin(), decoders.end(), [](const auto& a, const auto& b) {
return a.priority < b.priority;
});
@@ -236,8 +235,8 @@ void VideoDecoderFactory::InitializeFactory() {
void VideoDecoderFactory::CleanupFactory() {
// Clear all registrations
s_av1_decoders.clear();
s_vp9_decoders.clear();
GetDecoderList(VideoCodecType::AV1).clear();
GetDecoderList(VideoCodecType::VP9).clear();
std::cout << "[VideoDecoderFactory] Factory cleanup completed" << std::endl;
}
@@ -252,13 +251,17 @@ VideoCodecType VideoDecoderFactory::DetectCodecTypeFromId(const std::string& cod
}
std::vector<DecoderRegistration>& VideoDecoderFactory::GetDecoderList(VideoCodecType codec_type) {
// Lazy initialization to avoid DLL loading issues
static std::vector<DecoderRegistration> s_av1_decoders_local;
static std::vector<DecoderRegistration> s_vp9_decoders_local;
switch (codec_type) {
case VideoCodecType::AV1:
return s_av1_decoders;
return s_av1_decoders_local;
case VideoCodecType::VP9:
return s_vp9_decoders;
return s_vp9_decoders_local;
default:
return s_av1_decoders; // Default to AV1
return s_av1_decoders_local; // Default to AV1
}
}

View File

@@ -67,9 +67,6 @@ private:
VideoDecoderFactory(const VideoDecoderFactory&) = delete;
VideoDecoderFactory& operator=(const VideoDecoderFactory&) = delete;
// Codec-specific registered decoder arrays
static std::vector<DecoderRegistration> s_av1_decoders;
static std::vector<DecoderRegistration> s_vp9_decoders;
// Helper functions
static std::vector<DecoderRegistration>& GetDecoderList(VideoCodecType codec_type);

View File

@@ -0,0 +1,120 @@
#include "pch.h"
#include <windows.h>
#include <iostream>
// Forward declarations for decoder registration functions
namespace VavCore {
extern void RegisterAV1Decoders();
extern void RegisterNVDECDecoders();
extern void RegisterVPLDecoders();
extern void RegisterAMFDecoders();
}
// Global state for DLL-level initialization
static bool g_dll_initialized = false;
static CRITICAL_SECTION g_dll_cs;
// Safe initialization flag - only allow initialization once per process
static bool g_safe_to_initialize = false;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
// Initialize critical section for thread safety
InitializeCriticalSection(&g_dll_cs);
// Mark that we're ready for safe initialization
g_safe_to_initialize = true;
std::cout << "[DllMain] VavCore.dll loaded - Process Attach" << std::endl;
std::cout << "[DllMain] Safe to initialize: Ready for vavcore_initialize() call" << std::endl;
}
break;
case DLL_THREAD_ATTACH:
// Thread-specific initialization if needed
break;
case DLL_THREAD_DETACH:
// Thread-specific cleanup if needed
break;
case DLL_PROCESS_DETACH:
{
EnterCriticalSection(&g_dll_cs);
if (g_dll_initialized) {
std::cout << "[DllMain] VavCore.dll unloading - cleaning up decoders" << std::endl;
// Cleanup all decoder registrations
// Note: We don't call VideoDecoderFactory::CleanupFactory() here
// because it might cause issues during DLL unload
g_dll_initialized = false;
}
g_safe_to_initialize = false;
LeaveCriticalSection(&g_dll_cs);
DeleteCriticalSection(&g_dll_cs);
std::cout << "[DllMain] VavCore.dll unloaded - Process Detach" << std::endl;
}
break;
}
return TRUE;
}
// Safe initialization function called from vavcore_initialize()
extern "C" bool PerformSafeDllInitialization()
{
EnterCriticalSection(&g_dll_cs);
bool result = false;
if (!g_safe_to_initialize) {
std::cout << "[DllMain] ERROR: DLL not ready for initialization" << std::endl;
LeaveCriticalSection(&g_dll_cs);
return false;
}
if (g_dll_initialized) {
std::cout << "[DllMain] Already initialized, skipping" << std::endl;
result = true;
}
else {
try {
std::cout << "[DllMain] Performing safe decoder registration..." << std::endl;
// Register all decoders in safe runtime environment
VavCore::RegisterAV1Decoders();
VavCore::RegisterNVDECDecoders();
VavCore::RegisterVPLDecoders();
VavCore::RegisterAMFDecoders();
g_dll_initialized = true;
result = true;
std::cout << "[DllMain] Safe decoder registration completed successfully" << std::endl;
}
catch (const std::exception& e) {
std::cout << "[DllMain] ERROR during initialization: " << e.what() << std::endl;
result = false;
}
catch (...) {
std::cout << "[DllMain] ERROR: Unknown exception during initialization" << std::endl;
result = false;
}
}
LeaveCriticalSection(&g_dll_cs);
return result;
}
// Check if DLL is ready for safe operations
extern "C" bool IsDllReadyForInitialization()
{
return g_safe_to_initialize;
}

View File

@@ -14,13 +14,9 @@
// Use VavCore namespace internally
using namespace VavCore;
// Forward declarations for decoder registration functions
namespace VavCore {
extern void RegisterAV1Decoders();
extern void RegisterNVDECDecoders();
extern void RegisterVPLDecoders();
extern void RegisterAMFDecoders();
}
// Forward declarations for DllMain-based initialization
extern "C" bool PerformSafeDllInitialization();
extern "C" bool IsDllReadyForInitialization();
// Global state
static bool g_initialized = false;
@@ -164,19 +160,21 @@ VAVCORE_API VavCoreResult vavcore_initialize(void) {
return VAVCORE_SUCCESS;
}
try {
// Initialize decoder factories and other subsystems
// Force decoder registration (in case static initialization fails)
RegisterAV1Decoders();
RegisterNVDECDecoders();
RegisterVPLDecoders();
RegisterAMFDecoders();
g_initialized = true;
return VAVCORE_SUCCESS;
} catch (...) {
// Check if DLL is ready for safe initialization
if (!IsDllReadyForInitialization()) {
std::cout << "[vavcore_initialize] ERROR: DLL not ready for initialization" << std::endl;
return VAVCORE_ERROR_INIT_FAILED;
}
// Perform safe DLL-level initialization
if (!PerformSafeDllInitialization()) {
std::cout << "[vavcore_initialize] ERROR: Safe DLL initialization failed" << std::endl;
return VAVCORE_ERROR_INIT_FAILED;
}
std::cout << "[vavcore_initialize] VavCore initialization completed successfully" << std::endl;
g_initialized = true;
return VAVCORE_SUCCESS;
}
VAVCORE_API void vavcore_cleanup(void) {