Font update to dynamic draw per view (#1085)

* Move AtomFont over to use the new per viewport dynamic draw context.

Remove scene tracking and listening for bootstrap scene created.
Remove build dependency on the Bootstrap gem.
Add build dependency on the AtomBridge gem.
FFont's are now initialized with a viewport Id.
Remove previous DynamicDraw context per scene system.
Verify FFont can get a dynamic draw context before attempting initialization.
Ensure a render scene exists before attempting font initialization (as a proxy for rendering has begun)

* Move AtomFont FFont to use ShaderInputNameIndex's

This allowed removing all of the InitFont function as no longer need to query compiled shader info for constant data offsets.

* cache the AZ::Name used to find the dynamic draw context rather than recreate it each use
This commit is contained in:
rgba16f
2021-06-02 19:49:38 -05:00
committed by GitHub
parent 312c704ba6
commit bb92e4c0b8
5 changed files with 51 additions and 168 deletions
@@ -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<AZ::RPI::DynamicDrawContext> dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(renderScene);
// Save draw srg input indices for later use
Data::Instance<RPI::ShaderResourceGroup> 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<AZ::RPI::DynamicDrawContext> 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)