diff --git a/source/graphics/Font.cpp b/source/graphics/Font.cpp index 600238ced9..d00af9f7c5 100644 --- a/source/graphics/Font.cpp +++ b/source/graphics/Font.cpp @@ -180,7 +180,7 @@ bool CFont::SetFontParams(const std::string& fontName, float size, float strokeW FT_Stroker_Set(m_Stroker.get(), FloatToF26Dot6(m_StrokeWidth), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); } - if (!ConstructTextureAtlas()) + if (!ConstructAtlasTexture()) { LOGERROR("Failed to create font texture atlas %s", fontName); return false; @@ -262,7 +262,7 @@ Renderer::Backend::Sampler::Desc CFont::ChooseTextureFormatAndSampler() return defaultSamplerDesc; } -bool CFont::ConstructTextureAtlas() +bool CFont::ConstructAtlasTexture() { Renderer::Backend::IDevice* backendDevice = g_Renderer.GetDeviceCommandContext()->GetDevice(); @@ -287,7 +287,7 @@ bool CFont::ConstructTextureAtlas() m_Texture = g_Renderer.GetTextureManager().WrapBackendTexture(backendDevice->CreateTexture2D( ("Font Texture " + m_FontName).c_str(), Renderer::Backend::ITexture::Usage::TRANSFER_DST | - Renderer::Backend::ITexture::Usage::SAMPLED, + Renderer::Backend::ITexture::Usage::SAMPLED, m_TextureFormat, textureSize, textureSize, defaultSamplerDesc )); @@ -298,18 +298,27 @@ bool CFont::ConstructTextureAtlas() return false; } - m_IsLoadingTextureToGPU = true; - // Initialise texture with transparency, for the areas we don't // overwrite with uploading later. m_TexData = std::make_unique(m_AtlasSize); std::fill_n(m_TexData.get(), m_AtlasSize, 0x00); - g_Renderer.GetDeviceCommandContext()->UploadTexture( + m_IsTextureInitialized = false; + + return true; +} + +void CFont::InitalizeAtlasTextureIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext) +{ + if (m_IsTextureInitialized) + return; + + deviceCommandContext->UploadTexture( m_Texture->GetBackendTexture(), m_TextureFormat, m_TexData.get(), m_AtlasSize); - return true; + m_IsTextureInitialized = true; } const CFont::GlyphData* CFont::GetGlyph(u16 codepoint) @@ -492,24 +501,16 @@ std::optional CFont::GenerateGlyphBitmap(FT_Glyph& glyph, u16 codepoi return newOffset; } -void CFont::UploadTextureAtlasToGPU() +void CFont::UploadAtlasTextureToGPU(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - if (std::exchange(m_IsLoadingTextureToGPU, false)) - return; - if (!m_IsDirty) return; - Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); - PROFILE2("Loading font texture"); - GPU_SCOPED_LABEL(deviceCommandContext, "Loading font texture"); - - deviceCommandContext->UploadTextureRegion( + deviceCommandContext->UploadTexture( m_Texture->GetBackendTexture(), m_TextureFormat, m_TexData.get(), - m_AtlasSize, - 0, 0, m_AtlasWidth, m_AtlasHeight + m_AtlasSize ); m_IsDirty = false; diff --git a/source/graphics/Font.h b/source/graphics/Font.h index 8232902cf9..9b992822da 100644 --- a/source/graphics/Font.h +++ b/source/graphics/Font.h @@ -38,6 +38,7 @@ #include class CVector2D; +namespace Renderer::Backend { class IDeviceCommandContext; } namespace Renderer::Backend::Sampler { struct Desc; } /** @@ -110,7 +111,10 @@ public: } CTexturePtr GetTexture() const { return m_Texture; } - void UploadTextureAtlasToGPU(); + void InitalizeAtlasTextureIfNeeded( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); + void UploadAtlasTextureToGPU( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); const GlyphData* GetGlyph(u16 i); private: @@ -140,7 +144,7 @@ private: std::optional GenerateGlyphBitmap(FT_Glyph& glyph, u16 codepoint, FT_Render_Mode renderMode, CVector2D offset, const float baselineInAtlas); const GlyphData* ExtractAndGenerateGlyph(u16 codepoint); - bool ConstructTextureAtlas(); + bool ConstructAtlasTexture(); Renderer::Backend::Sampler::Desc ChooseTextureFormatAndSampler(); CTexturePtr m_Texture; @@ -166,7 +170,7 @@ private: int m_AtlasPadding; bool m_IsDirty{false}; - bool m_IsLoadingTextureToGPU{false}; + bool m_IsTextureInitialized{false}; float m_StrokeWidth{0.0f}; float m_Scale{1.0f}; diff --git a/source/graphics/FontManager.cpp b/source/graphics/FontManager.cpp index 9a981fbb7f..846cac9b87 100644 --- a/source/graphics/FontManager.cpp +++ b/source/graphics/FontManager.cpp @@ -28,6 +28,7 @@ #include "ps/CStrInternStatic.h" #include "ps/ConfigDB.h" #include "ps/Filesystem.h" +#include "renderer/backend/IDeviceCommandContext.h" #include #include @@ -230,13 +231,16 @@ std::shared_ptr CFontManager::LoadFont(CStrIntern fontName, CStrIntern lo return font; } -void CFontManager::UploadTexturesAtlasToGPU() +void CFontManager::UploadAtlasTexturesToGPU(Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { + PROFILE2("Loading font textures"); + GPU_SCOPED_LABEL(deviceCommandContext, "Loading font textures"); + for (auto& [fontName, fontPtr] : m_Fonts) { if (!fontPtr) continue; - fontPtr->UploadTextureAtlasToGPU(); + fontPtr->UploadAtlasTextureToGPU(deviceCommandContext); } } diff --git a/source/graphics/FontManager.h b/source/graphics/FontManager.h index cee47f905d..c068739311 100644 --- a/source/graphics/FontManager.h +++ b/source/graphics/FontManager.h @@ -30,6 +30,8 @@ class CFont; struct FT_LibraryRec_; +namespace Renderer::Backend { class IDeviceCommandContext; } + /** * Font manager: loads and caches bitmap fonts. */ @@ -41,7 +43,8 @@ public: NONCOPYABLE(CFontManager); std::shared_ptr LoadFont(CStrIntern fontName, CStrIntern locale); - void UploadTexturesAtlasToGPU(); + void UploadAtlasTexturesToGPU( + Renderer::Backend::IDeviceCommandContext* deviceCommandContext); private: static void ftLibraryDeleter(FT_Library library) diff --git a/source/graphics/TextRenderer.cpp b/source/graphics/TextRenderer.cpp index 5e70530d59..2467cc7c72 100644 --- a/source/graphics/TextRenderer.cpp +++ b/source/graphics/TextRenderer.cpp @@ -214,7 +214,7 @@ void CTextRenderer::Render( std::vector uvs; const bool debugFontBox{g_ConfigDB.Get("fonts.debugbox", false)}; - const std::string debugFontBoxColor{ g_ConfigDB.Get("fonts.debugboxcolor", std::string{"128 0 128"})}; + const std::string debugFontBoxColor{g_ConfigDB.Get("fonts.debugboxcolor", std::string{"128 0 128"})}; CColor debugBoxColor; debugBoxColor.ParseString(debugFontBoxColor.c_str()); @@ -248,6 +248,7 @@ void CTextRenderer::Render( if (lastTexture != batch.font->GetTexture().get()) { + batch.font->InitalizeAtlasTextureIfNeeded(deviceCommandContext); lastTexture = batch.font->GetTexture().get(); lastTexture->UploadBackendTextureIfNeeded(deviceCommandContext); deviceCommandContext->SetTexture(texBindingSlot, lastTexture->GetBackendTexture()); diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index d47d8f4f39..0ab581a3cd 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -662,7 +662,7 @@ void CRenderer::RenderFrame2D(const bool renderGUI, const bool renderLogger) g_ProfileViewer.RenderProfile(canvas); } - this->GetFontManager().UploadTexturesAtlasToGPU(); + GetFontManager().UploadAtlasTexturesToGPU(m->deviceCommandContext.get()); } void CRenderer::RenderScreenShot(const bool needsPresent) diff --git a/source/renderer/backend/ITexture.h b/source/renderer/backend/ITexture.h index b2083d6346..77be12576f 100644 --- a/source/renderer/backend/ITexture.h +++ b/source/renderer/backend/ITexture.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2024 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify diff --git a/source/renderer/backend/dummy/Texture.h b/source/renderer/backend/dummy/Texture.h index 91ee199552..be222d82b4 100644 --- a/source/renderer/backend/dummy/Texture.h +++ b/source/renderer/backend/dummy/Texture.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify diff --git a/source/renderer/backend/gl/Device.h b/source/renderer/backend/gl/Device.h index 9d5299fc6f..833a947f71 100644 --- a/source/renderer/backend/gl/Device.h +++ b/source/renderer/backend/gl/Device.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2024 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify diff --git a/source/renderer/backend/gl/Texture.h b/source/renderer/backend/gl/Texture.h index c7e0d986aa..516418806e 100644 --- a/source/renderer/backend/gl/Texture.h +++ b/source/renderer/backend/gl/Texture.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify diff --git a/source/renderer/backend/vulkan/Texture.cpp b/source/renderer/backend/vulkan/Texture.cpp index cc06862bf5..fa9db28e25 100644 --- a/source/renderer/backend/vulkan/Texture.cpp +++ b/source/renderer/backend/vulkan/Texture.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2024 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify diff --git a/source/renderer/backend/vulkan/Texture.h b/source/renderer/backend/vulkan/Texture.h index 63eb0bad47..4c3b092bd7 100644 --- a/source/renderer/backend/vulkan/Texture.h +++ b/source/renderer/backend/vulkan/Texture.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify