Files
2025-05-18 13:04:45 +08:00

474 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Windows/D3D/SlateD3DShaders.h"
#include "Windows/D3D/SlateD3DRenderer.h"
#include "Windows/D3D/SlateD3DRenderingPolicy.h"
#include "Misc/Paths.h"
#include "HAL/FileManager.h"
#include "Misc/FileHelper.h"
#include "Misc/App.h"
#define DEFINE_GUID_FOR_CURRENT_COMPILER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
static const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
DEFINE_GUID_FOR_CURRENT_COMPILER(IID_ID3D11ShaderReflectionForCurrentCompiler, 0x8d536ca1, 0x0cca, 0x4956, 0xa8, 0x37, 0x78, 0x69, 0x63, 0x75, 0x55, 0x84);
typedef HRESULT(WINAPI* pD3DReflect)
(__in_bcount(SrcDataSize) LPCVOID pSrcData,
__in SIZE_T SrcDataSize,
__in REFIID pInterface,
__out void** ppReflector);
static HMODULE GetCompilerModule()
{
// Override default compiler path to newer dll
FString CompilerPath = FPaths::EngineDir();
#if !PLATFORM_64BITS
CompilerPath.Append(TEXT("Binaries/ThirdParty/Windows/DirectX/x86/d3dcompiler_47.dll"));
#else
CompilerPath.Append(TEXT("Binaries/ThirdParty/Windows/DirectX/x64/d3dcompiler_47.dll"));
#endif
static bool bHasCompiler = false;
static HMODULE CompilerDLL = 0;
if (bHasCompiler == false)
{
CompilerDLL = LoadLibrary(*CompilerPath);
}
if (CompilerDLL == NULL)
{
// load the system one as the last resort
CompilerDLL = LoadLibrary(TEXT("d3dcompiler_47.dll"));
}
if (CompilerDLL == NULL)
{
LogSlateD3DRendererFailure(FString::Printf(TEXT("Critical error. Compiler DLL %s could not be found, and loading the system one failed"), *CompilerPath), E_FAIL);
}
return CompilerDLL;
}
// @return pointer to the D3DCompile function
static pD3DCompile GetD3DCompileFunc()
{
static HMODULE CompilerDLL = GetCompilerModule();
if (CompilerDLL)
{
return (pD3DCompile)(void*)GetProcAddress(CompilerDLL, "D3DCompile");
}
return nullptr;
}
// @return pointer to the D3DCompile function
static pD3DReflect GetD3DReflectFunc()
{
static HMODULE CompilerDLL = GetCompilerModule();
if (CompilerDLL)
{
return (pD3DReflect)(void*)GetProcAddress(CompilerDLL, "D3DReflect");
}
return nullptr;
}
class StandaloneD3DIncluder final : public ID3DInclude
{
public:
~StandaloneD3DIncluder()
{
}
STDMETHOD(Open)(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, uint32* pBytes) override
{
FString FileName(ANSI_TO_TCHAR(pFileName));
FString IncludePath = FPaths::EngineDir();
IncludePath.Append(TEXT("Shaders/StandaloneRenderer/D3D/"));
IncludePath.Append(FileName);
TArray<uint8>* ShaderFilePtr = new TArray<uint8>();
FFileHelper::LoadFileToArray(*ShaderFilePtr, *IncludePath);
*ppData = ShaderFilePtr->GetData();
*pBytes = ShaderFilePtr->Num();
IncludeMap.Add(*ppData, ShaderFilePtr);
return S_OK;
}
STDMETHOD(Close)(LPCVOID pData) override
{
TArray<uint8>* ShaderFilePtr = IncludeMap.FindChecked(pData);
IncludeMap.Remove(pData);
delete ShaderFilePtr;
return S_OK;
}
TMap<LPCVOID, TArray<uint8>*> IncludeMap;
};
static bool CompileShader( const FString& Filename, const FString& EntryPoint, const FString& ShaderModel, TRefCountPtr<ID3DBlob>& OutBlob )
{
uint32 ShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if UE_BUILD_DEBUG
ShaderFlags |= D3DCOMPILE_DEBUG;
#else
ShaderFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
#endif
pD3DCompile D3DCompilerFunc = GetD3DCompileFunc();
if (D3DCompilerFunc == nullptr)
{
GEncounteredCriticalD3DDeviceError = true;
return false;
}
StandaloneD3DIncluder Includer;
TArray<uint8> ShaderFile;
if(FFileHelper::LoadFileToArray(ShaderFile, *Filename))
{
TRefCountPtr<ID3DBlob> ErrorBlob;
HRESULT Hr = D3DCompilerFunc(ShaderFile.GetData(), ShaderFile.Num(), NULL, NULL, &Includer, TCHAR_TO_ANSI(*EntryPoint), TCHAR_TO_ANSI(*ShaderModel), ShaderFlags, 0, OutBlob.GetInitReference(), ErrorBlob.GetInitReference());
if (FAILED(Hr))
{
LogSlateD3DRendererFailure(TEXT("SlateD3DShaders::CompileShader() - D3DCompilerFunc"), Hr);
GEncounteredCriticalD3DDeviceError = true;
if (ErrorBlob.GetReference())
{
LogSlateD3DRendererFailure(ANSI_TO_TCHAR(ErrorBlob->GetBufferPointer()), Hr);
}
else
{
LogSlateD3DRendererFailure(TEXT("D3DCompilerFunc failed, no error text provided"), Hr);
}
return false;
}
}
else
{
LogSlateD3DRendererFailure(FString::Printf(TEXT("Failed to compile shader. %s could not be found "), *Filename), E_FAIL);
GEncounteredCriticalD3DDeviceError = true;
return false;
}
return true;
}
static void GetShaderBindings( TRefCountPtr<ID3D11ShaderReflection> Reflector, FSlateD3DShaderBindings& OutBindings )
{
D3D11_SHADER_DESC ShaderDesc;
Reflector->GetDesc( &ShaderDesc );
for( uint32 I = 0; I < ShaderDesc.BoundResources; ++I )
{
D3D11_SHADER_INPUT_BIND_DESC Desc;
Reflector->GetResourceBindingDesc( I, &Desc );
FSlateD3DShaderParameter* Param = FSlateShaderParameterMap::Get().Find( Desc.Name );
if( Param )
{
if( Desc.Type == D3D_SIT_TEXTURE )
{
OutBindings.ResourceViews.Add( (TSlateD3DTypedShaderParameter<ID3D11ShaderResourceView>*)Param );
}
else if( Desc.Type == D3D_SIT_CBUFFER )
{
OutBindings.ConstantBuffers.Add( (TSlateD3DTypedShaderParameter<ID3D11Buffer>*)Param );
}
else if( Desc.Type == D3D_SIT_SAMPLER )
{
OutBindings.SamplerStates.Add( (TSlateD3DTypedShaderParameter<ID3D11SamplerState>*)Param );
}
else
{
// unhandled param type
check(0);
}
}
else
{
// not registered
check(0);
}
}
}
void FSlateD3DVS::Create( const FString& Filename, const FString& EntryPoint, const FString& ShaderModel, D3D11_INPUT_ELEMENT_DESC* VertexLayout, uint32 VertexLayoutCount )
{
TRefCountPtr<ID3DBlob> Blob;
if(CompileShader( Filename, EntryPoint, ShaderModel, Blob))
{
HRESULT Hr = GD3DDevice->CreateVertexShader(Blob->GetBufferPointer(), Blob->GetBufferSize(), NULL, VertexShader.GetInitReference());
if (FAILED(Hr))
{
LogSlateD3DRendererFailure(TEXT("FSlateD3DVS::Create() - ID3D11Device::CreateVertexShader"), Hr);
GEncounteredCriticalD3DDeviceError = true;
return;
}
Hr = GD3DDevice->CreateInputLayout(VertexLayout, VertexLayoutCount, Blob->GetBufferPointer(), Blob->GetBufferSize(), InputLayout.GetInitReference());
if (FAILED(Hr))
{
LogSlateD3DRendererFailure(TEXT("FSlateD3DVS::Create() - ID3D11Device::CreateInputLayout"), Hr);
GEncounteredCriticalD3DDeviceError = true;
return;
}
pD3DReflect D3DReflectFunc = GetD3DReflectFunc();
if (D3DReflectFunc == nullptr)
{
GEncounteredCriticalD3DDeviceError = true;
return;
}
TRefCountPtr<ID3D11ShaderReflection> Reflector;
Hr = D3DReflectFunc(Blob->GetBufferPointer(), Blob->GetBufferSize(), IID_ID3D11ShaderReflectionForCurrentCompiler, (void**)Reflector.GetInitReference());
if (FAILED(Hr))
{
LogSlateD3DRendererFailure(TEXT("FSlateD3DVS::Create() - D3DReflect"), Hr);
GEncounteredCriticalD3DDeviceError = true;
return;
}
GetShaderBindings(Reflector, ShaderBindings);
}
else
{
GEncounteredCriticalD3DDeviceError = true;
}
}
void FSlateD3DVS::BindShader()
{
GD3DDeviceContext->IASetInputLayout( InputLayout );
GD3DDeviceContext->VSSetShader( VertexShader, NULL, 0 );
}
void FSlateD3DVS::BindParameters()
{
UpdateParameters();
int32 NumViews = ShaderBindings.ResourceViews.Num();
if( NumViews > 0 )
{
ID3D11ShaderResourceView** const Views = new ID3D11ShaderResourceView*[ NumViews ];
for( int32 I = 0; I < NumViews; ++I )
{
Views[I] = ShaderBindings.ResourceViews[I]->GetParameter().GetReference();
}
GD3DDeviceContext->VSSetShaderResources(0, NumViews, Views);
delete[] Views;
}
if( ShaderBindings.ConstantBuffers.Num() > 0 )
{
const uint32 BufferCount = ShaderBindings.ConstantBuffers.Num();
ID3D11Buffer** const ConstantBuffers = new ID3D11Buffer*[ BufferCount ];
for( uint32 I = 0; I < BufferCount; ++I )
{
ConstantBuffers[I] = ShaderBindings.ConstantBuffers[I]->GetParameter().GetReference();
}
GD3DDeviceContext->VSSetConstantBuffers(0, ShaderBindings.ConstantBuffers.Num(), ConstantBuffers);
delete[] ConstantBuffers;
}
}
void FSlateD3DPS::Create( const FString& Filename, const FString& EntryPoint, const FString& ShaderModel )
{
TRefCountPtr<ID3DBlob> Blob;
if(CompileShader( Filename, EntryPoint, ShaderModel, Blob))
{
HRESULT Hr = GD3DDevice->CreatePixelShader(Blob->GetBufferPointer(), Blob->GetBufferSize(), NULL, PixelShader.GetInitReference());
if (FAILED(Hr))
{
LogSlateD3DRendererFailure(TEXT("FSlateD3DPS::Create() - ID3D11Device::CreatePixelShader"), Hr);
GEncounteredCriticalD3DDeviceError = true;
return;
}
pD3DReflect D3DReflectFunc = GetD3DReflectFunc();
if (D3DReflectFunc == nullptr)
{
GEncounteredCriticalD3DDeviceError = true;
return;
}
TRefCountPtr<ID3D11ShaderReflection> Reflector;
Hr = D3DReflectFunc(Blob->GetBufferPointer(), Blob->GetBufferSize(), IID_ID3D11ShaderReflectionForCurrentCompiler, (void**)Reflector.GetInitReference());
if (FAILED(Hr))
{
LogSlateD3DRendererFailure(TEXT("FSlateD3DPS::Create() - D3DReflect"), Hr);
GEncounteredCriticalD3DDeviceError = true;
return;
}
GetShaderBindings(Reflector, ShaderBindings);
}
else
{
GEncounteredCriticalD3DDeviceError = true;
}
}
void FSlateD3DPS::BindShader()
{
GD3DDeviceContext->PSSetShader( PixelShader, NULL, 0 );
}
void FSlateD3DPS::BindParameters()
{
UpdateParameters();
int32 NumViews = ShaderBindings.ResourceViews.Num();
if( NumViews )
{
ID3D11ShaderResourceView** const Views = new ID3D11ShaderResourceView*[ NumViews ];
for( int32 I = 0; I < NumViews; ++I )
{
Views[I] = ShaderBindings.ResourceViews[I]->GetParameter().GetReference();
}
GD3DDeviceContext->PSSetShaderResources(0, NumViews, Views);
delete[] Views;
}
int32 NumBuffers = ShaderBindings.ConstantBuffers.Num();
if( NumBuffers )
{
ID3D11Buffer** const ConstantBuffers = new ID3D11Buffer*[ NumBuffers ];
for( int32 I = 0; I < NumBuffers; ++I )
{
ConstantBuffers[I] = ShaderBindings.ConstantBuffers[I]->GetParameter().GetReference();
}
GD3DDeviceContext->PSSetConstantBuffers(0, NumBuffers, ConstantBuffers);
delete[] ConstantBuffers;
}
if( ShaderBindings.SamplerStates.Num() )
{
const uint32 StateCount = ShaderBindings.SamplerStates.Num();
ID3D11SamplerState** const SamplerStates = new ID3D11SamplerState*[ StateCount ];
for( uint32 I = 0; I < StateCount; ++I )
{
SamplerStates[I] = ShaderBindings.SamplerStates[I]->GetParameter().GetReference();
}
GD3DDeviceContext->PSSetSamplers(0, ShaderBindings.SamplerStates.Num(), SamplerStates);
delete[] SamplerStates;
}
}
FSlateDefaultVS::FSlateDefaultVS()
{
Constants = &FSlateShaderParameterMap::Get().RegisterParameter<ID3D11Buffer>( "PerElementVSConstants" );
ConstantBuffer.Create();
D3D11_INPUT_ELEMENT_DESC Layout[] =
{
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 1, DXGI_FORMAT_B8G8R8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
Create( FString::Printf( TEXT("%s/StandaloneRenderer/D3D/SlateDefaultVertexShader.hlsl"), FPlatformProcess::ShaderDir() ), TEXT("Main"), TEXT("vs_4_0"), Layout, UE_ARRAY_COUNT(Layout) );
}
void FSlateDefaultVS::SetViewProjection( const FMatrix& ViewProjectionMatrix )
{
ConstantBuffer.GetBufferData().ViewProjection = (FMatrix44f)ViewProjectionMatrix; // LWC_TODO: Precision loss
}
void FSlateDefaultVS::SetShaderParams( const FVector4& InShaderParams )
{
ConstantBuffer.GetBufferData().VertexShaderParams = FVector4f(InShaderParams); // LWC_TODO: Precision loss
}
void FSlateDefaultVS::UpdateParameters()
{
ConstantBuffer.UpdateBuffer();
// Set the constant parameter to use our constant buffer
Constants->SetParameter( ConstantBuffer.GetResource() );
}
FSlateDefaultPS::FSlateDefaultPS()
{
Texture = &FSlateShaderParameterMap::Get().RegisterParameter<ID3D11ShaderResourceView>( "ElementTexture" );
TextureSampler = &FSlateShaderParameterMap::Get().RegisterParameter<ID3D11SamplerState>( "ElementTextureSampler" );
PerFrameCBufferParam = &FSlateShaderParameterMap::Get().RegisterParameter<ID3D11Buffer>("PerFramePSConstants");
PerElementCBufferParam = &FSlateShaderParameterMap::Get().RegisterParameter<ID3D11Buffer>("PerElementPSConstants");
PerFrameConstants.Create();
PerElementConstants.Create();
PerFrameConstants.GetBufferData().GammaValues = FVector2f(1, 1 / 2.2f);
PerFrameCBufferParam->SetParameter(PerFrameConstants.GetResource());
// Set the constant parameter to use our constant buffer
// @todo: If we go back to multiple pixel shaders this likely has be called more frequently
PerElementCBufferParam->SetParameter(PerElementConstants.GetResource());
Create( FString::Printf( TEXT("%s/StandaloneRenderer/D3D/SlateElementPixelShader.hlsl"), FPlatformProcess::ShaderDir()), TEXT("Main"), TEXT("ps_4_0") );
}
void FSlateDefaultPS::SetShaderType( uint32 InShaderType )
{
PerElementConstants.GetBufferData().ShaderType = InShaderType;
}
void FSlateDefaultPS::SetDrawEffects( ESlateDrawEffect InDrawEffects )
{
PerElementConstants.GetBufferData().IgnoreTextureAlpha = (uint32)(InDrawEffects & ESlateDrawEffect::IgnoreTextureAlpha);
PerElementConstants.GetBufferData().DisableEffect = (uint32)(InDrawEffects & ESlateDrawEffect::DisabledEffect);
}
void FSlateDefaultPS::SetShaderParams(const FShaderParams& InShaderParams)
{
PerElementConstants.GetBufferData().ShaderParams = InShaderParams.PixelParams;
PerElementConstants.GetBufferData().ShaderParams2 = InShaderParams.PixelParams2;
}
void FSlateDefaultPS::SetGammaValues(const FVector2f& InGammaValues)
{
PerFrameConstants.GetBufferData().GammaValues = InGammaValues;
}
void FSlateDefaultPS::UpdateParameters()
{
PerFrameConstants.UpdateBuffer();
PerElementConstants.UpdateBuffer();
TextureSampler->SetParameter( SamplerState );
}