diff --git a/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt index d3b8c8cde7..0045b37687 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomFont/Code/CMakeLists.txt @@ -29,7 +29,8 @@ ly_add_target( Legacy::CryCommon Gem::Atom_RHI.Reflect Gem::Atom_RPI.Public - Gem::Atom_Bootstrap.Headers + PUBLIC + Gem::Atom_AtomBridge.Static ) ################################################################################ diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h index d5463fc15c..d21796cf17 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h @@ -27,11 +27,14 @@ #include #include +#include namespace AZ { class FFont; + static constexpr char AtomFontDynamicDrawContextName[] = "AtomFont"; + //! AtomFont is the font system manager. //! AtomFont manages the lifetime of FFont instances, each of which represents an individual font (e.g Courier New Italic) @@ -90,13 +93,6 @@ namespace AZ AzFramework::FontDrawInterface* GetFontDrawInterface(AzFramework::FontId fontId) const override; AzFramework::FontDrawInterface* GetDefaultFontDrawInterface() const override; - void SceneAboutToBeRemoved(AzFramework::Scene& scene); - - - // Atom DynamicDraw interface management - AZ::RHI::Ptr GetOrCreateDynamicDrawForScene(AZ::RPI::Scene* scene); - - public: void UnregisterFont(const char* fontName); @@ -108,8 +104,6 @@ namespace AZ using FontFamilyMap = AZStd::unordered_map>; using FontFamilyReverseLookupMap = AZStd::unordered_map; - using SceneToDynamicDrawMap = AZStd::unordered_map>; - private: //! Convenience method for loading fonts IFFont* LoadFont(const char* fontName); @@ -145,9 +139,6 @@ namespace AZ int r_persistFontFamilies = 1; //!< Persist fonts for application lifetime to prevent unnecessary work; enabled by default. AZStd::vector m_persistedFontFamilies; //!< Stores persisted fonts (if "persist font families" is enabled) - - SceneToDynamicDrawMap m_sceneToDynamicDrawMap; - AZStd::shared_mutex m_sceneToDynamicDrawMutex; }; } #endif diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h index 1e224d6090..78d74a784a 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h @@ -42,11 +42,9 @@ #include #include #include +#include #include -#include -#include - struct ISystem; namespace AZ @@ -68,7 +66,6 @@ namespace AZ : public IFFont , public AZStd::intrusive_refcount , public AzFramework::FontDrawInterface - , private AZ::Render::Bootstrap::NotificationBus::Handler { using ref_count = AZStd::intrusive_refcount; friend FontDeleter; @@ -168,8 +165,8 @@ namespace AZ struct FontShaderData { - AZ::RHI::ShaderInputImageIndex m_imageInputIndex; - AZ::RHI::ShaderInputConstantIndex m_viewProjInputIndex; + AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture"; + AZ::RHI::ShaderInputNameIndex m_viewProjInputIndex = "m_worldToProj"; }; public: @@ -230,7 +227,6 @@ namespace AZ private: virtual ~FFont(); - bool InitFont(AZ::RPI::Scene* renderScene); bool InitTexture(); bool InitCache(); @@ -281,8 +277,6 @@ namespace AZ void ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) const; - void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override; - RPI::WindowContextSharedPtr GetDefaultWindowContext() const; RPI::ViewportContextPtr GetDefaultViewportContext() const; @@ -303,6 +297,8 @@ namespace AZ string m_name; string m_curPath; + AZ::Name m_dynamicDrawContextName = AZ::Name(AZ::AtomFontDynamicDrawContextName); + FontTexture* m_fontTexture = nullptr; size_t m_fontBufferSize = 0; @@ -315,13 +311,6 @@ namespace AZ AtomFont* m_atomFont = nullptr; bool m_fontTexDirty = false; - enum class InitializationState : AZ::u8 - { - Uninitialized, - Initializing, - Initialized - }; - AZStd::atomic m_fontInitializationState = InitializationState::Uninitialized; FontEffects m_effects; @@ -356,6 +345,7 @@ namespace AZ if (font && font->m_atomFont) { font->m_atomFont->UnregisterFont(font->m_name); + font->m_atomFont = nullptr; } delete font; diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp index 623a931ac9..fd8a4f26ed 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp @@ -354,17 +354,26 @@ AZ::AtomFont::AtomFont(ISystem* system) #endif AZ::Interface::Register(this); - m_sceneEventHandler = AzFramework::ISceneSystem::SceneEvent::Handler( - [this](AzFramework::ISceneSystem::EventType eventType, const AZStd::shared_ptr& scene) + // register font per viewport dynamic draw context. + static const char* shaderFilepath = "Shaders/SimpleTextured.azshader"; + AZ::AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext( + AZ::Name(AZ::AtomFontDynamicDrawContextName), + [](RPI::Ptr drawContext) { - if (eventType == AzFramework::ISceneSystem::EventType::ScenePendingRemoval) - { - SceneAboutToBeRemoved(*scene); - } + Data::Instance shader = AZ::RPI::LoadShader(shaderFilepath); + AZ::RPI::ShaderOptionList shaderOptions; + shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("false"))); + shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true"))); + drawContext->InitShaderWithVariant(shader, &shaderOptions); + drawContext->InitVertexFormat( + { + {"POSITION", RHI::Format::R32G32B32_FLOAT}, + {"COLOR", RHI::Format::B8G8R8A8_UNORM}, + {"TEXCOORD0", RHI::Format::R32G32_FLOAT} + }); + drawContext->EndInit(); }); - auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "Font created before the scene system is available."); - sceneSystem->ConnectToEvents(m_sceneEventHandler); + } AZ::AtomFont::~AtomFont() @@ -860,52 +869,5 @@ XmlNodeRef AZ::AtomFont::LoadFontFamilyXml(const char* fontFamilyName, string& o return root; } - -void AZ::AtomFont::SceneAboutToBeRemoved(AzFramework::Scene& scene) -{ - AZ::RPI::ScenePtr* rpiScene = scene.FindSubsystem(); - if (rpiScene) - { - AZStd::lock_guard lock(m_sceneToDynamicDrawMutex); - if (auto it = m_sceneToDynamicDrawMap.find(rpiScene->get()); it != m_sceneToDynamicDrawMap.end()) - { - m_sceneToDynamicDrawMap.erase(it); - } - } -} - -AZ::RHI::Ptr AZ::AtomFont::GetOrCreateDynamicDrawForScene(AZ::RPI::Scene* scene) -{ - static const char* shaderFilepath = "Shaders/SimpleTextured.azshader"; - - { - // shared lock while reading - AZStd::shared_lock lock(m_sceneToDynamicDrawMutex); - - if (auto it = m_sceneToDynamicDrawMap.find(scene); it != m_sceneToDynamicDrawMap.end()) - { - return it->second; - } - } - - // Create and initialize DynamicDrawContext for font draw - AZ::RHI::Ptr dynamicDraw = RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(scene); - - Data::Instance shader = AZ::RPI::LoadShader(shaderFilepath); - AZ::RPI::ShaderOptionList shaderOptions; - shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("false"))); - shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true"))); - dynamicDraw->InitShaderWithVariant(shader, &shaderOptions); - dynamicDraw->InitVertexFormat({{"POSITION", RHI::Format::R32G32B32_FLOAT}, {"COLOR", RHI::Format::B8G8R8A8_UNORM}, {"TEXCOORD0", RHI::Format::R32G32_FLOAT}}); - dynamicDraw->EndInit(); - - // exclusive lock while writing - AZStd::lock_guard lock(m_sceneToDynamicDrawMutex); - m_sceneToDynamicDrawMap.insert(AZStd::make_pair(scene, dynamicDraw)); - - return dynamicDraw; -} - - #endif diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp index 31eb089803..1976c69b45 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp @@ -60,14 +60,7 @@ static const size_t MaxVerts = 8 * 1024; // 2048 quads static const size_t MaxIndices = (MaxVerts * 6) / 4; // 6 indices per quad, 6/4 * MaxVerts static const char DrawList2DPassName[] = "2dpass"; -namespace ShaderInputs -{ - static const char TextureIndexName[] = "m_texture"; - static const char WorldToProjIndexName[] = "m_worldToProj"; - static const char SamplerIndexName[] = "m_sampler"; -} - -AZ::FFont::FFont(AtomFont* atomFont, const char* fontName) +AZ::FFont::FFont(AZ::AtomFont* atomFont, const char* fontName) : m_name(fontName) , m_atomFont(atomFont) { @@ -78,9 +71,14 @@ AZ::FFont::FFont(AtomFont* atomFont, const char* fontName) FontEffect* effect = AddEffect("default"); effect->AddPass(); - AddRef(); + // Create cpu memory to cache the font draw data before submit + m_vertexBuffer = new SVF_P3F_C4B_T2F[MaxVerts]; + m_indexBuffer = new u16[MaxIndices]; - AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); + m_vertexCount = 0; + m_indexCount = 0; + + AddRef(); } AZ::RPI::ViewportContextPtr AZ::FFont::GetDefaultViewportContext() const @@ -98,55 +96,10 @@ AZ::RPI::WindowContextSharedPtr AZ::FFont::GetDefaultWindowContext() const return {}; } -bool AZ::FFont::InitFont(AZ::RPI::Scene* renderScene) -{ - if (!renderScene) - { - return false; - } - - auto initializationState = InitializationState::Uninitialized; - // Do an atomic transition to Initializing if we're in the Uninitialized state. - // Otherwise, check the current state. - // If we're Initialized, there's no more work to be done, return true to indicate we're good to go. - // If we're Initializing (on another thread), return false to let the consumer know it's not safe for us to be used yet. - if (!m_fontInitializationState.compare_exchange_strong(initializationState, InitializationState::Initializing)) - { - return initializationState == InitializationState::Initialized; - } - - // Create and initialize DynamicDrawContext for font draw - AZ::RPI::Ptr dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(renderScene); - - // Save draw srg input indices for later use - Data::Instance drawSrg = dynamicDraw->NewDrawSrg(); - const RHI::ShaderResourceGroupLayout* layout = drawSrg->GetAsset()->GetLayout(); - - m_fontShaderData.m_imageInputIndex = layout->FindShaderInputImageIndex(AZ::Name(ShaderInputs::TextureIndexName)); - AZ_Error("AtomFont::FFont", m_fontShaderData.m_imageInputIndex.IsValid(), "Failed to find shader input constant %s.", - ShaderInputs::TextureIndexName); - - m_fontShaderData.m_viewProjInputIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::WorldToProjIndexName)); - AZ_Error("AtomFont::FFont", m_fontShaderData.m_viewProjInputIndex.IsValid(), "Failed to find shader input constant %s.", - ShaderInputs::WorldToProjIndexName); - - // Create cpu memory to cache the font draw data before submit - m_vertexBuffer = new SVF_P3F_C4B_T2F[MaxVerts]; - m_indexBuffer = new u16[MaxIndices]; - - m_vertexCount = 0; - m_indexCount = 0; - - m_fontInitializationState = InitializationState::Initialized; - return true; -} - AZ::FFont::~FFont() { AZ_Assert(m_atomFont == nullptr, "The font should already be unregistered through a call to AZ::FFont::Release()"); - AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect(); - delete[] m_vertexBuffer; delete[] m_indexBuffer; @@ -303,7 +256,8 @@ void AZ::FFont::DrawStringUInternal( const TextDrawContext& ctx) { // Lazily ensure we're initialized before attempting to render. - if (!viewportContext || !InitFont(viewportContext->GetRenderScene().get())) + // Validate that there is a render scene before attempting to init. + if (!viewportContext || !viewportContext->GetRenderScene()) { return; } @@ -323,12 +277,6 @@ void AZ::FFont::DrawStringUInternal( return; } - // if the font is about to be deleted then m_atomFont can be nullptr - if (!m_atomFont) - { - return; - } - const bool orthoMode = ctx.m_overrideViewProjMatrices; const float viewX = viewport.m_minX; @@ -406,14 +354,17 @@ void AZ::FFont::DrawStringUInternal( if (numQuads) { - auto dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(viewportContext->GetRenderScene().get()); - //setup per draw srg - auto drawSrg = dynamicDraw->NewDrawSrg(); - drawSrg->SetConstant(m_fontShaderData.m_viewProjInputIndex, modelViewProjMat); - drawSrg->SetImageView(m_fontShaderData.m_imageInputIndex, m_fontStreamingImage->GetImageView()); - drawSrg->Compile(); + AZ::RPI::Ptr dynamicDraw = AZ::AtomBridge::PerViewportDynamicDraw::Get()->GetDynamicDrawContextForViewport(m_dynamicDrawContextName, viewportContext->GetId()); + if (dynamicDraw) + { + //setup per draw srg + auto drawSrg = dynamicDraw->NewDrawSrg(); + drawSrg->SetConstant(m_fontShaderData.m_viewProjInputIndex, modelViewProjMat); + drawSrg->SetImageView(m_fontShaderData.m_imageInputIndex, m_fontStreamingImage->GetImageView()); + drawSrg->Compile(); - dynamicDraw->DrawIndexed(m_vertexBuffer, m_vertexCount, m_indexBuffer, m_indexCount, RHI::IndexFormat::Uint16, drawSrg); + dynamicDraw->DrawIndexed(m_vertexBuffer, m_vertexCount, m_indexBuffer, m_indexCount, RHI::IndexFormat::Uint16, drawSrg); + } m_indexCount = 0; m_vertexCount = 0; } @@ -694,12 +645,6 @@ uint32_t AZ::FFont::WriteTextQuadsToBuffers(SVF_P2F_C4B_T2F_F4B* verts, uint16_t return numQuadsWritten; } - // if the font is about to be deleted then m_atomFont can be nullptr - if (!m_atomFont) - { - return numQuadsWritten; - } - SVF_P2F_C4B_T2F_F4B* vertexData = verts; uint16_t* indexData = indices; size_t vertexOffset = 0; @@ -1523,7 +1468,7 @@ bool AZ::FFont::UpdateTexture() { using namespace AZ; - if (m_fontInitializationState != InitializationState::Initialized || !m_fontImage) + if (!m_fontImage) { return false; } @@ -1591,7 +1536,7 @@ void AZ::FFont::Prepare(const char* str, bool updateTexture, const AtomFont::Gly const bool rerenderGlyphs = m_sizeBehavior == SizeBehavior::Rerender; const AtomFont::GlyphSize usedGlyphSize = rerenderGlyphs ? glyphSize : AtomFont::defaultGlyphSize; bool texUpdateNeeded = m_fontTexture->PreCacheString(str, nullptr, m_sizeRatio, usedGlyphSize, m_fontHintParams) == 1 || m_fontTexDirty; - if (m_fontInitializationState == InitializationState::Initialized && updateTexture && texUpdateNeeded && m_fontImage) + if (updateTexture && texUpdateNeeded && m_fontImage) { UpdateTexture(); m_fontTexDirty = false; @@ -1625,12 +1570,6 @@ void AZ::FFont::ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) co y *= height / WindowScaleHeight; } - -void AZ::FFont::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) -{ - InitFont(bootstrapScene); -} - static void SetCommonContextFlags(AZ::TextDrawContext& ctx, const AzFramework::TextDrawParameters& params) { if (params.m_hAlign == AzFramework::TextHorizontalAlignment::Center)