419 lines
13 KiB
C++
419 lines
13 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Windows/D3D/SlateD3DRenderingPolicy.h"
|
|
#include "Windows/D3D/SlateD3DRenderer.h"
|
|
#include "Windows/D3D/SlateD3DTextureManager.h"
|
|
#include "Windows/D3D/SlateD3DTextures.h"
|
|
#include "Layout/Clipping.h"
|
|
|
|
|
|
/** Offset to apply to UVs to line up texels with pixels */
|
|
const float PixelCenterOffsetD3D11 = 0.0f;
|
|
|
|
|
|
static D3D11_PRIMITIVE_TOPOLOGY GetD3D11PrimitiveType( ESlateDrawPrimitive SlateType )
|
|
{
|
|
switch( SlateType )
|
|
{
|
|
case ESlateDrawPrimitive::LineList:
|
|
return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
|
|
case ESlateDrawPrimitive::TriangleList:
|
|
default:
|
|
return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
|
}
|
|
|
|
};
|
|
|
|
FSlateD3D11RenderingPolicy::FSlateD3D11RenderingPolicy( TSharedRef<FSlateFontServices> InSlateFontServices, TSharedRef<FSlateD3DTextureManager> InTexureManager )
|
|
: FSlateRenderingPolicy( InSlateFontServices, PixelCenterOffsetD3D11 )
|
|
, TextureManager( InTexureManager )
|
|
{
|
|
InitResources();
|
|
}
|
|
|
|
FSlateD3D11RenderingPolicy::~FSlateD3D11RenderingPolicy()
|
|
{
|
|
ReleaseResources();
|
|
}
|
|
|
|
void FSlateD3D11RenderingPolicy::InitResources()
|
|
{
|
|
VertexShader = nullptr;
|
|
PixelShader = nullptr;
|
|
|
|
D3D11_SAMPLER_DESC SamplerDesc;
|
|
FMemory::Memzero( &SamplerDesc, sizeof(D3D11_SAMPLER_DESC) );
|
|
SamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
|
SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
|
SamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
|
SamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
|
SamplerDesc.MaxAnisotropy = 1;
|
|
SamplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
|
SamplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
|
SamplerDesc.MinLOD = 0;
|
|
|
|
HRESULT Hr = GD3DDevice->CreateSamplerState( &SamplerDesc, PointSamplerState_Wrap.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateSamplerState"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
SamplerDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
|
|
Hr = GD3DDevice->CreateSamplerState( &SamplerDesc, BilinearSamplerState_Wrap.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateSamplerState(BilinearSamplerState_Wrap)"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
SamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
SamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
SamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
|
|
Hr = GD3DDevice->CreateSamplerState( &SamplerDesc, BilinearSamplerState_Clamp.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateSamplerState(BilinearSamplerState_Clamp)"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
SamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
|
Hr = GD3DDevice->CreateSamplerState( &SamplerDesc, PointSamplerState_Clamp.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateSamplerState(PointSamplerState_Clamp)"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
WhiteTexture = TextureManager->CreateColorTexture( TEXT("DefaultWhite"), FColor::White )->Resource;
|
|
|
|
VertexBuffer.CreateBuffer( sizeof(FSlateVertex) );
|
|
IndexBuffer.CreateBuffer();
|
|
|
|
VertexShader = new FSlateDefaultVS;
|
|
PixelShader = new FSlateDefaultPS;
|
|
|
|
D3D11_BLEND_DESC BlendDesc;
|
|
BlendDesc.AlphaToCoverageEnable = false;
|
|
BlendDesc.IndependentBlendEnable = false;
|
|
BlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
|
BlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
|
|
|
// dest.a = 1-(1-dest.a)*src.a + dest.a
|
|
BlendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
|
|
BlendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
|
|
BlendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
|
|
|
BlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
|
BlendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
|
BlendDesc.RenderTarget[0].BlendEnable = true;
|
|
|
|
Hr = GD3DDevice->CreateBlendState( &BlendDesc, AlphaBlendState.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateBlendState( &BlendDesc, AlphaBlendState.GetInitReference() )"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
BlendDesc.RenderTarget[0].BlendEnable = false;
|
|
Hr = GD3DDevice->CreateBlendState( &BlendDesc, NoBlendState.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateBlendState( &BlendDesc, NoBlendState.GetInitReference() )"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
D3D11_RASTERIZER_DESC RasterDesc;
|
|
RasterDesc.CullMode = D3D11_CULL_NONE;
|
|
RasterDesc.FillMode = D3D11_FILL_SOLID;
|
|
RasterDesc.FrontCounterClockwise = true;
|
|
RasterDesc.DepthBias = 0;
|
|
RasterDesc.DepthBiasClamp = 0;
|
|
RasterDesc.SlopeScaledDepthBias = 0;
|
|
RasterDesc.ScissorEnable = false;
|
|
RasterDesc.MultisampleEnable = false;
|
|
RasterDesc.AntialiasedLineEnable = false;
|
|
|
|
Hr = GD3DDevice->CreateRasterizerState( &RasterDesc, NormalRasterState.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateRasterizerState( &RasterDesc, NormalRasterState.GetInitReference() )"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
RasterDesc.ScissorEnable = true;
|
|
Hr = GD3DDevice->CreateRasterizerState( &RasterDesc, ScissorRasterState.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateRasterizerState( &RasterDesc, ScissorRasterState.GetInitReference())"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
RasterDesc.AntialiasedLineEnable = false;
|
|
RasterDesc.ScissorEnable = false;
|
|
RasterDesc.FillMode = D3D11_FILL_WIREFRAME;
|
|
Hr = GD3DDevice->CreateRasterizerState( &RasterDesc, WireframeRasterState.GetInitReference() );
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateRasterizerState( &RasterDesc, WireframeRasterState.GetInitReference() )"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
|
|
D3D11_DEPTH_STENCIL_DESC DSDesc;
|
|
|
|
// Depth test parameters
|
|
DSDesc.DepthEnable = false;
|
|
DSDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
DSDesc.DepthFunc = D3D11_COMPARISON_LESS;
|
|
|
|
// Stencil test parameters
|
|
DSDesc.StencilEnable = false;
|
|
DSDesc.StencilReadMask = 0xFF;
|
|
DSDesc.StencilWriteMask = 0xFF;
|
|
|
|
Hr = GD3DDevice->CreateDepthStencilState(&DSDesc, DSStateOff.GetInitReference());
|
|
if (FAILED(Hr))
|
|
{
|
|
LogSlateD3DRendererFailure(TEXT("FSlateD3D11RenderingPolicy::InitResources() - ID3D11Device::CreateDepthStencilState"), Hr);
|
|
GEncounteredCriticalD3DDeviceError = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
/** Releases RHI resources used by the element batcher */
|
|
void FSlateD3D11RenderingPolicy::ReleaseResources()
|
|
{
|
|
VertexBuffer.DestroyBuffer();
|
|
IndexBuffer.DestroyBuffer();
|
|
|
|
if (VertexShader != nullptr)
|
|
{
|
|
delete VertexShader;
|
|
VertexShader = nullptr;
|
|
}
|
|
|
|
if (PixelShader != nullptr)
|
|
{
|
|
delete PixelShader;
|
|
PixelShader = nullptr;
|
|
}
|
|
}
|
|
|
|
void FSlateD3D11RenderingPolicy::BuildRenderingBuffers( FSlateBatchData& InBatchData )
|
|
{
|
|
if (!VertexBuffer.GetResource().IsValid() ||
|
|
!IndexBuffer.GetResource().IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( InBatchData.GetRenderBatches().Num() > 0 )
|
|
{
|
|
const FSlateVertexArray& FinalVertexData = InBatchData.GetFinalVertexData();
|
|
const FSlateIndexArray& FinalIndexData = InBatchData.GetFinalIndexData();
|
|
|
|
if (FinalVertexData.Num() > 0)
|
|
{
|
|
const uint32 NumVertices = FinalVertexData.Num();
|
|
|
|
// resize if needed
|
|
if( NumVertices*sizeof(FSlateVertex) > VertexBuffer.GetBufferSize() )
|
|
{
|
|
uint32 NumBytesNeeded = NumVertices*sizeof(FSlateVertex);
|
|
VertexBuffer.ResizeBuffer( NumBytesNeeded + (NumVertices / 4) * sizeof(FSlateVertex) );
|
|
}
|
|
}
|
|
|
|
if (FinalIndexData.Num() > 0)
|
|
{
|
|
const uint32 NumIndices = FinalIndexData.Num();
|
|
|
|
// resize if needed
|
|
if( NumIndices > IndexBuffer.GetMaxNumIndices() )
|
|
{
|
|
IndexBuffer.ResizeBuffer( NumIndices + (NumIndices / 4) );
|
|
}
|
|
}
|
|
|
|
uint8* VerticesPtr = nullptr;
|
|
uint8* IndicesPtr = nullptr;
|
|
{
|
|
VerticesPtr = (uint8*)VertexBuffer.Lock(0);
|
|
IndicesPtr = (uint8*)IndexBuffer.Lock(0);
|
|
}
|
|
|
|
{
|
|
FMemory::Memcpy(VerticesPtr, FinalVertexData.GetData(), FinalVertexData.Num() * sizeof(FSlateVertex));
|
|
FMemory::Memcpy(IndicesPtr, FinalIndexData.GetData(), FinalIndexData.Num() * sizeof(SlateIndex));
|
|
}
|
|
|
|
{
|
|
VertexBuffer.Unlock();
|
|
IndexBuffer.Unlock();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSlateD3D11RenderingPolicy::DrawElements(const FMatrix& ViewProjectionMatrix, int32 FirstBatchIndex, const TArray<FSlateRenderBatch>& RenderBatches)
|
|
{
|
|
if (!VertexBuffer.GetResource().IsValid() ||
|
|
!IndexBuffer.GetResource().IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
VertexShader->BindShader();
|
|
|
|
ID3D11Buffer* Buffer = VertexBuffer.GetResource();
|
|
const uint32 Stride = sizeof(FSlateVertex);
|
|
|
|
#if SLATE_USE_32BIT_INDICES
|
|
#define D3D_INDEX_FORMAT DXGI_FORMAT_R32_UINT
|
|
#else
|
|
#define D3D_INDEX_FORMAT DXGI_FORMAT_R16_UINT
|
|
#endif
|
|
|
|
|
|
GD3DDeviceContext->IASetIndexBuffer( IndexBuffer.GetResource(), D3D_INDEX_FORMAT, 0 );
|
|
|
|
VertexShader->SetViewProjection( ViewProjectionMatrix );
|
|
|
|
PixelShader->BindShader();
|
|
|
|
const FSlateClippingState* LastClippingState = nullptr;
|
|
|
|
int32 NextRenderBatchIndex = FirstBatchIndex;
|
|
while(NextRenderBatchIndex != INDEX_NONE)
|
|
{
|
|
const FSlateRenderBatch& RenderBatch = RenderBatches[NextRenderBatchIndex];
|
|
|
|
NextRenderBatchIndex = RenderBatch.NextBatchIndex;
|
|
|
|
const FSlateShaderResource* ShaderResource = RenderBatch.GetShaderResource();
|
|
|
|
const ESlateBatchDrawFlag DrawFlags = RenderBatch.GetDrawFlags();
|
|
|
|
const ESlateDrawEffect DrawEffects = RenderBatch.GetDrawEffects();
|
|
|
|
const FShaderParams& ShaderParams = RenderBatch.GetShaderParams();
|
|
|
|
VertexShader->BindParameters();
|
|
|
|
if( EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::NoBlending) )
|
|
{
|
|
GD3DDeviceContext->OMSetBlendState( NoBlendState, 0, 0xFFFFFFFF );
|
|
}
|
|
else
|
|
{
|
|
GD3DDeviceContext->OMSetBlendState( AlphaBlendState, 0, 0xFFFFFFFF );
|
|
}
|
|
|
|
if( EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::Wireframe) )
|
|
{
|
|
GD3DDeviceContext->RSSetState( WireframeRasterState );
|
|
}
|
|
|
|
if (EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::NoGamma))
|
|
{
|
|
PixelShader->SetGammaValues(FVector2f(1.0f, 1.0f));
|
|
}
|
|
else
|
|
{
|
|
PixelShader->SetGammaValues(FVector2f(1, 1 / 2.2f));
|
|
}
|
|
|
|
const FSlateClippingState* ClippingState = RenderBatch.GetClippingState();
|
|
if (ClippingState != LastClippingState)
|
|
{
|
|
LastClippingState = ClippingState;
|
|
|
|
if (ClippingState)
|
|
{
|
|
const FSlateClippingState& ClipState = *ClippingState;
|
|
if (ClipState.ScissorRect.IsSet())
|
|
{
|
|
const FSlateClippingZone& ScissorRect = ClipState.ScissorRect.GetValue();
|
|
|
|
D3D11_RECT R;
|
|
R.left = ScissorRect.TopLeft.X;
|
|
R.top = ScissorRect.TopLeft.Y;
|
|
R.right = ScissorRect.BottomRight.X;
|
|
R.bottom = ScissorRect.BottomRight.Y;
|
|
GD3DDeviceContext->RSSetScissorRects(1, &R);
|
|
GD3DDeviceContext->RSSetState(ScissorRasterState);
|
|
}
|
|
else
|
|
{
|
|
// We don't support stencil clipping on the d3d rendering policy.
|
|
GD3DDeviceContext->RSSetState(NormalRasterState);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GD3DDeviceContext->RSSetState(NormalRasterState);
|
|
}
|
|
}
|
|
|
|
PixelShader->SetShaderType( static_cast<uint8>(RenderBatch.GetShaderType()) );
|
|
|
|
// Disable stenciling and depth testing by default
|
|
GD3DDeviceContext->OMSetDepthStencilState( DSStateOff, 0x00);
|
|
|
|
if(ShaderResource)
|
|
{
|
|
TRefCountPtr<ID3D11SamplerState> SamplerState;
|
|
if( EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::TileU) || EnumHasAllFlags(DrawFlags, ESlateBatchDrawFlag::TileV) )
|
|
{
|
|
SamplerState = BilinearSamplerState_Wrap;
|
|
}
|
|
else
|
|
{
|
|
SamplerState = BilinearSamplerState_Clamp;
|
|
}
|
|
|
|
PixelShader->SetTexture( ((FSlateD3DTexture*)ShaderResource)->GetTypedResource(), SamplerState );
|
|
}
|
|
else
|
|
{
|
|
PixelShader->SetTexture( ((FSlateD3DTexture*)WhiteTexture)->GetTypedResource(), BilinearSamplerState_Clamp );
|
|
}
|
|
|
|
PixelShader->SetShaderParams(ShaderParams);
|
|
PixelShader->SetDrawEffects( DrawEffects );
|
|
|
|
PixelShader->BindParameters();
|
|
|
|
const uint32 Offset = RenderBatch.VertexOffset * sizeof(FSlateVertex);
|
|
|
|
GD3DDeviceContext->IASetPrimitiveTopology(GetD3D11PrimitiveType(RenderBatch.GetDrawPrimitiveType()));
|
|
|
|
const uint32 IndexCount = RenderBatch.GetNumIndices();
|
|
|
|
check(IndexCount > 0);
|
|
|
|
GD3DDeviceContext->IASetVertexBuffers(0, 1, &Buffer, &Stride, &Offset);
|
|
check(RenderBatch.GetIndexOffset() + RenderBatch.GetNumIndices() <= IndexBuffer.GetMaxNumIndices());
|
|
GD3DDeviceContext->DrawIndexed(IndexCount, RenderBatch.GetIndexOffset(), 0);
|
|
}
|
|
|
|
// Reset the Raster state when finished, there are places that are making assumptions about the raster state
|
|
// that need to be fixed.
|
|
GD3DDeviceContext->RSSetState(NormalRasterState);
|
|
}
|
|
|
|
TSharedRef<FSlateShaderResourceManager> FSlateD3D11RenderingPolicy::GetResourceManager() const
|
|
{
|
|
return TextureManager;
|
|
}
|
|
|