Merge pull request #144 from aws-lumberyard-dev/nvsickle/MainFontFixes

Fix debug font rendering & assert on game mode transition
This commit is contained in:
Nicholas Van Sickle
2021-04-20 12:32:26 -07:00
committed by GitHub
6 changed files with 97 additions and 61 deletions
+9 -8
View File
@@ -276,9 +276,6 @@ void EditorViewportWidget::paintEvent([[maybe_unused]] QPaintEvent* event)
if ((ge && ge->IsLevelLoaded()) || (GetType() != ET_ViewportCamera))
{
setRenderOverlayVisible(true);
m_isOnPaint = true;
Update();
m_isOnPaint = false;
}
else
{
@@ -809,6 +806,10 @@ void EditorViewportWidget::OnBeginPrepareRender()
return;
}
m_isOnPaint = true;
Update();
m_isOnPaint = false;
float fNearZ = GetIEditor()->GetConsoleVar("cl_DefaultNearPlane");
float fFarZ = m_Camera.GetFarPlane();
@@ -880,6 +881,11 @@ void EditorViewportWidget::OnBeginPrepareRender()
GetIEditor()->GetSystem()->SetViewCamera(m_Camera);
if (GetIEditor()->IsInGameMode())
{
return;
}
PreWidgetRendering();
RenderAll();
@@ -905,11 +911,6 @@ void EditorViewportWidget::OnBeginPrepareRender()
m_debugDisplay->DepthTestOn();
PostWidgetRendering();
if (!m_renderer->IsStereoEnabled())
{
GetIEditor()->GetSystem()->RenderStatistics();
}
}
//////////////////////////////////////////////////////////////////////////
+4 -1
View File
@@ -418,8 +418,11 @@ void CLayoutWnd::CreateLayout(EViewLayout layout, bool bBindViewports, EViewport
QRect rcView = rect();
rcView.setBottom(rcView.bottom() - m_infoBar->height());
// Ensure we delete our old view immediately so it can relinquish its backing ViewportContext
if (m_maximizedView)
m_maximizedView->deleteLater();
{
delete m_maximizedView;
}
m_maximizedView = new CLayoutViewPane(this);
m_maximizedView->SetId(0);
@@ -95,6 +95,11 @@ bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFram
AZStd::optional<MouseButton> overrideButton;
AZStd::optional<MouseEvent> eventType;
// Because we receive events multiple times at separate priorities for manipulator events and
// viewport interaction events, we want to avoid updating our "last tick state" until we're on our last event,
// which currently is the low priority Interaction processor.
const bool finishedProcessingEvents = event.m_priority == InteractionPriority;
if (IsMouseMove(event.m_inputChannel))
{
// Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after
@@ -120,10 +125,11 @@ bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFram
}
else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None)
{
const AZ::u32 mouseButtonValue = static_cast<AZ::u32>(mouseButton);
overrideButton = mouseButton;
if (event.m_inputChannel.GetState() == InputChannel::State::Began)
{
m_state.m_mouseButtons.m_mouseButtons |= static_cast<AZ::u32>(mouseButton);
m_state.m_mouseButtons.m_mouseButtons |= mouseButtonValue;
if (IsDoubleClick(mouseButton))
{
// Only remove the double click flag once we're done processing both Manipulator and Interaction events
@@ -135,8 +141,8 @@ bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFram
}
else
{
// Only insert the double click timing once we're done processing both Manipulator and Interaction events, to avoid a false IsDoubleClick positive
if (event.m_priority == InteractionPriority)
// Only insert the double click timing once we're done processing events, to avoid a false IsDoubleClick positive
if (finishedProcessingEvents)
{
m_pendingDoubleClicks[mouseButton] = m_curTime;
}
@@ -145,8 +151,18 @@ bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFram
}
else if (event.m_inputChannel.GetState() == InputChannel::State::Ended)
{
m_state.m_mouseButtons.m_mouseButtons &= ~static_cast<AZ::u32>(mouseButton);
eventType = MouseEvent::Up;
// If we've actually logged a mouse down event, forward a mouse up event.
// This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this viewport,
// due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events.
if (m_state.m_mouseButtons.m_mouseButtons & mouseButtonValue)
{
// Erase the button from our state if we're done processing events.
if (event.m_priority == InteractionPriority)
{
m_state.m_mouseButtons.m_mouseButtons &= ~mouseButtonValue;
}
eventType = MouseEvent::Up;
}
}
}
else if (auto keyboardModifier = GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None)
@@ -164,6 +164,8 @@ namespace AtomToolsFramework
bool RenderViewportWidget::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
{
bool shouldConsumeEvent = true;
// Grab keyboard focus if we've been clicked on.
// Qt normally handles this for us, but we're filtering native events before they get
// synthesized into QMouseEvents.
@@ -175,9 +177,18 @@ namespace AtomToolsFramework
// Don't consume new input events if we don't currently have focus.
// We do forward Ended events, as they may be relevant to our current state
// (e.g. a key gets released after we lose focus, it shouldn't remain "stuck").
if (!hasFocus() && inputChannel.GetState() != AzFramework::InputChannel::State::Ended)
if (!hasFocus())
{
return false;
if (inputChannel.GetState() == AzFramework::InputChannel::State::Ended)
{
// Forward the input ended event to our controllers, but don't prevent other viewports from receiving it.
shouldConsumeEvent = false;
}
else
{
// Not an event we should listen to, abort.
return false;
}
}
// If we receive a mouse button event from outside of our viewport, ignore it even if we have focus.
@@ -196,7 +207,9 @@ namespace AtomToolsFramework
}
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
return m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it.
return eventHandled && shouldConsumeEvent;
}
void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time)
@@ -277,11 +277,11 @@ namespace AZ
void ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) const;
void InitDefaultWindowContext();
void InitDefaultViewportContext();
void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override;
RPI::WindowContextSharedPtr GetDefaultWindowContext() const;
RPI::ViewportContextPtr GetDefaultViewportContext() const;
private:
static constexpr uint32_t NumBuffers = 2;
static constexpr float WindowScaleWidth = 800.0f;
@@ -294,9 +294,6 @@ namespace AZ
size_t m_fontBufferSize = 0;
unsigned char* m_fontBuffer = nullptr;
AZStd::shared_ptr<RPI::WindowContext> m_defaultWindowContext;
AZStd::shared_ptr<AZ::RPI::ViewportContext> m_defaultViewportContext;
AZ::Data::Instance<AZ::RPI::StreamingImage> m_fontStreamingImage;
AZ::RHI::Ptr<AZ::RHI::Image> m_fontImage;
uint32_t m_fontImageVersion = 0;
@@ -304,7 +301,13 @@ namespace AZ
AtomFont* m_atomFont = nullptr;
bool m_fontTexDirty = false;
bool m_fontInitialized = false;
enum class InitializationState : AZ::u8
{
Uninitialized,
Initializing,
Initialized
};
AZStd::atomic<InitializationState> m_fontInitializationState = InitializationState::Uninitialized;
FontEffects m_effects;
@@ -345,26 +348,4 @@ namespace AZ
}
}
inline void AZ::FFont::InitDefaultWindowContext()
{
if (!m_defaultWindowContext)
{
// font is created before window & viewport in the editor so need to do late init
// TODO need to deal with multiple windows, such as the editor
AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_defaultWindowContext, &AZ::Render::Bootstrap::DefaultWindowInterface::GetDefaultWindowContext);
AZ_Assert(m_defaultWindowContext, "Unable to get the main window context");
}
}
inline void AZ::FFont::InitDefaultViewportContext()
{
if (!m_defaultViewportContext)
{
// font is created before window & viewport in the editor so need to do late init
auto viewContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
m_defaultViewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName());
AZ_Assert(m_defaultViewportContext, "Unable to get the viewport context");
}
}
#endif
@@ -84,19 +84,35 @@ AZ::FFont::FFont(AtomFont* atomFont, const char* fontName)
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
}
AZ::RPI::ViewportContextPtr AZ::FFont::GetDefaultViewportContext() const
{
auto viewContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
return viewContextManager->GetDefaultViewportContext();
}
AZ::RPI::WindowContextSharedPtr AZ::FFont::GetDefaultWindowContext() const
{
if (auto defaultViewportContext = GetDefaultViewportContext())
{
return defaultViewportContext->GetWindowContext();
}
return {};
}
bool AZ::FFont::InitFont()
{
if (m_fontInitialized)
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 true;
return initializationState == InitializationState::Initialized;
}
InitDefaultWindowContext();
InitDefaultViewportContext();
// Create and initialize DynamicDrawContext for font draw
AZ::RPI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(m_defaultViewportContext->GetRenderScene().get());
AZ::RPI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(GetDefaultViewportContext()->GetRenderScene().get());
// Save draw srg input indices for later use
Data::Instance<RPI::ShaderResourceGroup> drawSrg = dynamicDraw->NewDrawSrg();
@@ -117,7 +133,7 @@ bool AZ::FFont::InitFont()
m_vertexCount = 0;
m_indexCount = 0;
m_fontInitialized = true;
m_fontInitializationState = InitializationState::Initialized;
return true;
}
@@ -259,7 +275,7 @@ void AZ::FFont::DrawString(float x, float y, const char* str, const bool asciiMu
return;
}
DrawStringUInternal(m_defaultWindowContext->GetViewport(), m_defaultViewportContext.get(), x, y, 1.0f, str, asciiMultiLine, ctx);
DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext().get(), x, y, 1.0f, str, asciiMultiLine, ctx);
}
void AZ::FFont::DrawString(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx)
@@ -269,7 +285,7 @@ void AZ::FFont::DrawString(float x, float y, float z, const char* str, const boo
return;
}
DrawStringUInternal(m_defaultWindowContext->GetViewport(), m_defaultViewportContext.get(), x, y, z, str, asciiMultiLine, ctx);
DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext().get(), x, y, z, str, asciiMultiLine, ctx);
}
void AZ::FFont::DrawStringUInternal(
@@ -282,6 +298,12 @@ void AZ::FFont::DrawStringUInternal(
const bool asciiMultiLine,
const TextDrawContext& ctx)
{
// Lazily ensure we're initialized before attempting to render.
if (!InitFont())
{
return;
}
if (!str
|| !m_vertexBuffer // vertex buffer isn't created until BootstrapScene is ready, Editor tries to render text before that.
|| !m_fontTexture
@@ -400,7 +422,7 @@ Vec2 AZ::FFont::GetTextSize(const char* str, const bool asciiMultiLine, const Te
return Vec2(0.0f, 0.0f);
}
return GetTextSizeUInternal(m_defaultWindowContext->GetViewport(), str, asciiMultiLine, ctx);
return GetTextSizeUInternal(GetDefaultWindowContext()->GetViewport(), str, asciiMultiLine, ctx);
}
Vec2 AZ::FFont::GetTextSizeUInternal(
@@ -746,7 +768,7 @@ uint32_t AZ::FFont::WriteTextQuadsToBuffers(SVF_P2F_C4B_T2F_F4B* verts, uint16_t
return true;
};
CreateQuadsForText(m_defaultWindowContext->GetViewport(), x, y, z, str, asciiMultiLine, ctx, AddQuad);
CreateQuadsForText(GetDefaultWindowContext()->GetViewport(), x, y, z, str, asciiMultiLine, ctx, AddQuad);
return numQuadsWritten;
}
@@ -1438,7 +1460,7 @@ void AZ::FFont::AddCharsToFontTexture(const char* chars, int glyphSizeX, int gly
Vec2 AZ::FFont::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph, const TextDrawContext& ctx) const
{
return GetKerningInternal(m_defaultWindowContext->GetViewport(), leftGlyph, rightGlyph, ctx);
return GetKerningInternal(GetDefaultWindowContext()->GetViewport(), leftGlyph, rightGlyph, ctx);
}
Vec2 AZ::FFont::GetKerningInternal(const RHI::Viewport& viewport, uint32_t leftGlyph, uint32_t rightGlyph, const TextDrawContext& ctx) const
@@ -1454,7 +1476,7 @@ float AZ::FFont::GetAscender(const TextDrawContext& ctx) const
float AZ::FFont::GetBaseline(const TextDrawContext& ctx) const
{
return GetBaselineInternal(m_defaultWindowContext->GetViewport(), ctx);
return GetBaselineInternal(GetDefaultWindowContext()->GetViewport(), ctx);
}
float AZ::FFont::GetBaselineInternal(const RHI::Viewport& viewport, const TextDrawContext& ctx) const
@@ -1496,7 +1518,7 @@ bool AZ::FFont::UpdateTexture()
{
using namespace AZ;
if (!m_fontInitialized || !m_fontImage)
if (m_fontInitializationState != InitializationState::Initialized || !m_fontImage)
{
return false;
}
@@ -1564,7 +1586,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_fontInitialized && updateTexture && texUpdateNeeded && m_fontImage)
if (m_fontInitializationState == InitializationState::Initialized && updateTexture && texUpdateNeeded && m_fontImage)
{
UpdateTexture();
m_fontTexDirty = false;