// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Stats/Stats.h" #include "Logging/LogMacros.h" #include "RHIStaticStates.h" #include "HAL/ThreadSafeBool.h" #include "HAL/ThreadSafeCounter.h" #include "HAL/Runnable.h" #include "HAL/RunnableThread.h" #include "HAL/Event.h" #include "Misc/ScopeExit.h" #include "ShaderCore.h" #include "ProfilingDebugging/CsvProfiler.h" #include "RHI.h" #include "RHIResources.h" // // Macros to control some things during development // #RVF : Remove this when cleaning up // #define WRITE_TO_FILE 0 #define LIVESTREAMING 0 #if UE_BUILD_SHIPPING #define GAMEPLAYMEDIAENCODER_DEBUG 0 #else #define GAMEPLAYMEDIAENCODER_DEBUG 0 #endif // // Includes common to Windows and XboxOne // #if PLATFORM_WINDOWS || PLATFORM_XBOXONE #include "Templates/RefCounting.h" #endif // // Windows only include // #if PLATFORM_WINDOWS #include "Windows/AllowWindowsPlatformTypes.h" #include "Windows/PreWindowsApi.h" #include #include #include #include #include #include #include #include #include "Windows/PostWindowsApi.h" #include "Windows/HideWindowsPlatformTypes.h" #include "D3D11State.h" #include "D3D11Resources.h" #endif // // XboxOne only includes // #if PLATFORM_XBOXONE #include "XboxOne/XboxOneAllowPlatformTypes.h" #include "XboxOne/XboxOnePreApi.h" #include #include #include #include #include #include #include #include #include #include #include "XboxOne/XboxOnePostApi.h" #include "XboxOne/XboxOneHidePlatformTypes.h" #endif #if GAMEPLAYMEDIAENCODER_DEBUG #define GAMEPLAYMEDIAENCODER_START PRAGMA_DISABLE_OPTIMIZATION #define GAMEPLAYMEDIAENCODER_END PRAGMA_ENABLE_OPTIMIZATION #else #define GAMEPLAYMEDIAENCODER_START #define GAMEPLAYMEDIAENCODER_END #endif #define WMFMEDIA_SUPPORTED_PLATFORM (PLATFORM_WINDOWS && (WINVER >= 0x0600 /*Vista*/) && !UE_SERVER) DECLARE_LOG_CATEGORY_EXTERN(GameplayMediaEncoder, Log, VeryVerbose); // // Windows and XboxOne common code/macros // #if PLATFORM_WINDOWS || PLATFORM_XBOXONE inline const FString GetComErrorDescription(HRESULT Res) { const uint32 BufSize = 4096; WIDECHAR buffer[4096]; if (::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, Res, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), buffer, sizeof(buffer) / sizeof(*buffer), nullptr)) { return buffer; } else { return TEXT("[cannot find error description]"); } } #if PLATFORM_WINDOWS #include "Windows/AllowWindowsPlatformTypes.h" #elif PLATFORM_XBOXONE #include "XboxOne/XboxOneAllowPlatformTypes.h" #endif // macro to deal with COM calls inside a function that returns `false` on error #define CHECK_HR(COM_call)\ {\ HRESULT Res = COM_call;\ if (FAILED(Res))\ {\ UE_LOG(GameplayMediaEncoder, Error, TEXT("`" #COM_call "` failed: 0x%X - %s"), Res, *GetComErrorDescription(Res));\ return false;\ }\ } // macro to deal with COM calls inside COM method (that returns HRESULT) #define CHECK_HR_COM(COM_call)\ {\ HRESULT Res = COM_call;\ if (FAILED(Res))\ {\ UE_LOG(GameplayMediaEncoder, Error, TEXT("`" #COM_call "` failed: 0x%X - %s"), Res, *GetComErrorDescription(Res));\ return Res;\ }\ } // macro to deal with COM calls inside COM method (that simply returns) #define CHECK_HR_VOID(COM_call)\ {\ HRESULT Res = COM_call;\ if (FAILED(Res))\ {\ UE_LOG(GameplayMediaEncoder, Error, TEXT("`" #COM_call "` failed: 0x%X - %s"), Res, *GetComErrorDescription(Res));\ return;\ }\ } #if PLATFORM_WINDOWS #include "Windows/HideWindowsPlatformTypes.h" #elif PLATFORM_XBOXONE #include "XboxOne/XboxOneHidePlatformTypes.h" #endif // following commented include causes name clash between UE4 and Windows `IMediaEventSink`, // we just need a couple of GUIDs from there so the solution is to duplicate them below //#include "wmcodecdsp.h" const GUID CLSID_AACMFTEncoder = { 0x93AF0C51, 0x2275, 0x45d2, { 0xA3, 0x5B, 0xF2, 0xBA, 0x21, 0xCA, 0xED, 0x00 } }; const GUID CLSID_CMSH264EncoderMFT = { 0x6ca50344, 0x051a, 0x4ded, { 0x97, 0x79, 0xa4, 0x33, 0x05, 0x16, 0x5e, 0x35 } }; const GUID CLSID_VideoProcessorMFT = { 0x88753b26, 0x5b24, 0x49bd, { 0xb2, 0xe7, 0xc, 0x44, 0x5c, 0x78, 0xc9, 0x82 } }; // `MF_LOW_LATENCY` is defined in "mfapi.h" for >= WIN8 // UE4 supports lower Windows versions at the moment and so `WINVER` is < `_WIN32_WINNT_WIN8` // to be able to use `MF_LOW_LATENCY` with default UE4 build we define it ourselves and check actual // Windows version in runtime #if (WINVER < _WIN32_WINNT_WIN8) const GUID MF_LOW_LATENCY = { 0x9c27891a, 0xed7a, 0x40e1,{ 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee } }; #endif #endif // // Windows only utility code/macros // #if PLATFORM_WINDOWS ID3D11Device* GetUE4DxDevice(); // scope-disable particular DX11 Debug Layer errors class FScopeDisabledDxDebugErrors final { private: public: FScopeDisabledDxDebugErrors(TArray&& ErrorsToDisable) { TRefCountPtr Debug; HRESULT HRes = GetUE4DxDevice()->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast(Debug.GetInitReference())); if (HRes == E_NOINTERFACE) { // Debug Layer is not enabled, so no need to disable its errors return; } if (!SUCCEEDED(HRes) || !SUCCEEDED(HRes = InfoQueue->QueryInterface(__uuidof(ID3D11InfoQueue), reinterpret_cast(Debug.GetInitReference())))) { UE_LOG(GameplayMediaEncoder, VeryVerbose, TEXT("Failed to get ID3D11InfoQueue: 0x%X - %s"), HRes, *GetComErrorDescription(HRes)); return; } D3D11_INFO_QUEUE_FILTER filter = {}; filter.DenyList.NumIDs = ErrorsToDisable.Num(); filter.DenyList.pIDList = ErrorsToDisable.GetData(); bSucceeded = SUCCEEDED(InfoQueue->PushStorageFilter(&filter)); } ~FScopeDisabledDxDebugErrors() { if (bSucceeded) { InfoQueue->PopStorageFilter(); } } private: TRefCountPtr InfoQueue; bool bSucceeded = false; }; #endif // // XboxOne only utility code/macros // #if PLATFORM_XBOXONE ID3D12Device* GetUE4DxDevice(); #endif class FThread final : public FRunnable { public: using FCallback = TFunction; explicit FThread(TCHAR const* ThreadName, const FCallback& Callback) : Callback(Callback) { Thread.Reset(FRunnableThread::Create(this, ThreadName, TPri_BelowNormal)); } void Join() { Thread->WaitForCompletion(); } virtual uint32 Run() override { Callback(); return 0; } private: FCallback Callback; TUniquePtr Thread; private: FThread(const FThread&) = delete; FThread& operator=(const FThread&) = delete; }; template inline void ExecuteRHICommand(F&& Functor) { FRHICommandList& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList(); if (RHICmdList.Bypass()) { Functor(); } else { struct FLocalRHICommand final : public FRHICommand { F Functor; FLocalRHICommand(F InFunctor) : Functor(MoveTemp(InFunctor)) {} void Execute(FRHICommandListBase& CmdList) { Functor(); } }; new (RHICmdList.AllocCommand()) FLocalRHICommand(Functor); } } // #RVF : Remove this once the code is production ready. struct FMemoryCheckpoint { FString Name; float UsedPhysicalMB; float DeltaMB; float AccumulatedMB; }; extern TArray gMemoryCheckpoints; uint64 MemoryCheckpoint(const FString& Name); void LogMemoryCheckpoints(const FString& Name);