add native MSDF font support for Render2D

This commit is contained in:
fibref
2026-02-19 15:41:48 +08:00
parent be4e1edc3e
commit 0f49503abd
2 changed files with 48 additions and 2 deletions

View File

@@ -2,6 +2,7 @@
#include "Render2D.h"
#include "Font.h"
#include "FontAsset.h"
#include "FontManager.h"
#include "FontTextureAtlas.h"
#include "RotatedRectangle.h"
@@ -74,6 +75,7 @@ enum class DrawCallType : byte
FillTexture,
FillTexturePoint,
DrawChar,
DrawCharMSDF,
DrawCharMaterial,
Custom,
Material,
@@ -164,6 +166,7 @@ struct CachedPSO
GPUPipelineState* PS_Color_NoAlpha;
GPUPipelineState* PS_Font;
GPUPipelineState* PS_FontMSDF;
GPUPipelineState* PS_BlurH;
GPUPipelineState* PS_BlurV;
@@ -455,6 +458,7 @@ CanDrawCallCallback CanDrawCallBatch[] =
CanDrawCallCallbackTexture, // FillTexture,
CanDrawCallCallbackTexture, // FillTexturePoint,
CanDrawCallCallbackChar, // DrawChar,
CanDrawCallCallbackChar, // DrawCharMSDF,
CanDrawCallCallbackCharMaterial, // DrawCharMaterial,
CanDrawCallCallbackFalse, // Custom,
CanDrawCallCallbackMaterial, // Material,
@@ -517,6 +521,12 @@ bool CachedPSO::Init(GPUShader* shader, bool useDepth)
if (PS_Font->Init(desc))
return true;
//
desc.BlendMode = BlendingMode::AlphaBlend;
desc.PS = shader->GetPS("PS_FontMSDF");
PS_FontMSDF = GPUDevice::Instance->CreatePipelineState();
if (PS_FontMSDF->Init(desc))
return true;
//
desc.PS = shader->GetPS("PS_LineAA");
PS_LineAA = GPUDevice::Instance->CreatePipelineState();
if (PS_LineAA->Init(desc))
@@ -994,6 +1004,10 @@ void DrawBatch(int32 startIndex, int32 count)
Context->BindSR(0, d.AsChar.Tex);
Context->SetState(CurrentPso->PS_Font);
break;
case DrawCallType::DrawCharMSDF:
Context->BindSR(0, d.AsChar.Tex);
Context->SetState(CurrentPso->PS_FontMSDF);
break;
case DrawCallType::DrawCharMaterial:
{
// Apply and bind material
@@ -1176,6 +1190,10 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color,
float scale = 1.0f / FontManager::FontScale;
const bool enableFallbackFonts = EnumHasAllFlags(Features, RenderingFeatures::FallbackFonts);
const FontAsset* asset = font->GetAsset();
const FontOptions& options = asset->GetOptions();
const bool useMSDF = options.RasterMode == FontRasterMode::MSDF;
// Render all characters
FontCharacterEntry entry;
Render2DDrawCall drawCall;
@@ -1186,7 +1204,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color,
}
else
{
drawCall.Type = DrawCallType::DrawChar;
drawCall.Type = useMSDF ? DrawCallType::DrawCharMSDF : DrawCallType::DrawChar;
drawCall.AsChar.Mat = nullptr;
}
Float2 pointer = location;
@@ -1291,6 +1309,10 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color,
float scale = layout.Scale / FontManager::FontScale;
const bool enableFallbackFonts = EnumHasAllFlags(Features, RenderingFeatures::FallbackFonts);
const FontAsset* asset = font->GetAsset();
const FontOptions& options = asset->GetOptions();
const bool useMSDF = options.RasterMode == FontRasterMode::MSDF;
// Process text to get lines
Lines.Clear();
font->ProcessText(text, Lines, layout);
@@ -1305,7 +1327,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color,
}
else
{
drawCall.Type = DrawCallType::DrawChar;
drawCall.Type = useMSDF ? DrawCallType::DrawCharMSDF : DrawCallType::DrawChar;
drawCall.AsChar.Mat = nullptr;
}
for (int32 lineIndex = 0; lineIndex < Lines.Count(); lineIndex++)

View File

@@ -96,6 +96,30 @@ float4 PS_Font(VS2PS input) : SV_Target0
return color;
}
META_PS(true, FEATURE_LEVEL_ES2)
float4 PS_FontMSDF(VS2PS input) : SV_Target0
{
PerformClipping(input);
float4 color = input.Color;
float3 msd = Image.Sample(SamplerLinearClamp, input.TexCoord).rgb;
float sd = max(min(msd.r, msd.g), min(max(msd.r, msd.g), msd.b));
uint width, height;
Image.GetDimensions(width, height);
float pxRange = 4.0f; // Must match C++ code
float unitRange = float2(pxRange, pxRange) / float2(width, height);
float2 dx = ddx(input.TexCoord);
float2 dy = ddy(input.TexCoord);
float2 screenTexSize = rsqrt(dx * dx + dy * dy);
float screenPxRange = max(0.5f * dot(screenTexSize, unitRange), 1.0f);
float screenPxDist = screenPxRange * (sd - 0.5f);
float opacity = saturate(screenPxDist + 0.5f);
return float4(color.rgb, opacity);
}
float4 GetSample(float weight, float offset, float2 uv)
{
#if BLUR_V