Merge pull request #1475 from aws-lumberyard-dev/nvsickle/ViewportInfoDpiScaling

Make IMGUI & viewport info scale with DPI
main
Terry Michaels 5 years ago committed by GitHub
commit 24d21cadae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -219,6 +219,7 @@ public:
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override { return 1.0f; };
void ConnectViewportInteractionRequestBus();
void DisconnectViewportInteractionRequestBus();

@ -116,6 +116,11 @@ namespace AzFramework
SetFullScreenState(!GetFullScreenState());
}
float NativeWindow::GetDpiScaleFactor() const
{
return m_pimpl->GetDpiScaleFactor();
}
/*static*/ bool NativeWindow::GetFullScreenStateOfDefaultWindow()
{
NativeWindowHandle defaultWindowHandle = nullptr;
@ -228,4 +233,10 @@ namespace AzFramework
return false;
}
float NativeWindow::Implementation::GetDpiScaleFactor() const
{
// For platforms that aren't DPI-aware, we simply return a 1.0 ratio for no scaling
return 1.0f;
}
} // namespace AzFramework

@ -128,6 +128,7 @@ namespace AzFramework
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override;
//! Get the full screen state of the default window.
//! \return True if the default window is currently in full screen, false otherwise.
@ -169,6 +170,7 @@ namespace AzFramework
virtual bool GetFullScreenState() const;
virtual void SetFullScreenState(bool fullScreenState);
virtual bool CanToggleFullScreenState() const;
virtual float GetDpiScaleFactor() const;
protected:
uint32_t m_width = 0;

@ -68,6 +68,11 @@ namespace AzFramework
//! Toggle the full screen state of the window.
virtual void ToggleFullScreenState() = 0;
//! Returns a scalar multiplier representing how many dots-per-inch this window has, compared
//! to a "standard" value of 96, the default for Windows in a DPI unaware setting. This can
//! be used to scale user interface elements to ensure legibility on high density displays.
virtual float GetDpiScaleFactor() const = 0;
};
using WindowRequestBus = AZ::EBus<WindowRequests>;
@ -87,6 +92,9 @@ namespace AzFramework
//! This is called once when the window is Activated and also called if the user resizes the window.
virtual void OnWindowResized(uint32_t width, uint32_t height) { AZ_UNUSED(width); AZ_UNUSED(height); };
//! This is called if the window's underyling DPI scaling factor changes.
virtual void OnDpiScaleFactorChanged(float dpiScaleFactor) { AZ_UNUSED(dpiScaleFactor); }
//! This is called when the window is deactivated from code or if the user closes the window.
virtual void OnWindowClosed() {};
};

@ -8,6 +8,7 @@
#include <AzFramework/Input/Buses/Notifications/RawInputNotificationBus_Windows.h>
#include <AzFramework/Windowing/NativeWindow.h>
#include <AzCore/Module/DynamicModuleHandle.h>
#include <AzCore/PlatformIncl.h>
namespace AzFramework
@ -17,7 +18,7 @@ namespace AzFramework
{
public:
AZ_CLASS_ALLOCATOR(NativeWindowImpl_Win32, AZ::SystemAllocator, 0);
NativeWindowImpl_Win32() = default;
NativeWindowImpl_Win32();
~NativeWindowImpl_Win32() override;
// NativeWindow::Implementation overrides...
@ -33,6 +34,7 @@ namespace AzFramework
bool GetFullScreenState() const override;
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override { return true; }
float GetDpiScaleFactor() const override;
private:
static DWORD ConvertToWin32WindowStyleMask(const WindowStyleMasks& styleMasks);
@ -49,6 +51,9 @@ namespace AzFramework
RECT m_windowRectToRestoreOnFullScreenExit; //!< The position and size of the window to restore when exiting full screen.
UINT m_windowStyleToRestoreOnFullScreenExit; //!< The style(s) of the window to restore when exiting full screen.
bool m_isInBorderlessWindowFullScreenState = false; //!< Was a borderless window used to enter full screen state?
using GetDpiForWindowType = UINT(HWND hwnd);
GetDpiForWindowType* m_getDpiFunction = nullptr;
};
const char* NativeWindowImpl_Win32::s_defaultClassName = "O3DEWin32Class";
@ -58,6 +63,15 @@ namespace AzFramework
return aznew NativeWindowImpl_Win32();
}
NativeWindowImpl_Win32::NativeWindowImpl_Win32()
{
// Attempt to load GetDpiForWindow from user32 at runtime, available on Windows 10+ versions >= 1607
if (auto user32module = AZ::DynamicModuleHandle::Create("user32"); user32module->Load(false))
{
m_getDpiFunction = user32module->GetFunction<GetDpiForWindowType*>("GetDpiForWindow");
}
}
NativeWindowImpl_Win32::~NativeWindowImpl_Win32()
{
DestroyWindow(m_win32Handle);
@ -237,6 +251,12 @@ namespace AzFramework
// Send all other WM_SYSKEYDOWN messages to the default WndProc.
break;
}
case WM_DPICHANGED:
{
const float newScaleFactor = nativeWindowImpl->GetDpiScaleFactor();
WindowNotificationBus::Event(nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnDpiScaleFactorChanged, newScaleFactor);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
@ -330,6 +350,17 @@ namespace AzFramework
}
}
float NativeWindowImpl_Win32::GetDpiScaleFactor() const
{
constexpr UINT defaultDotsPerInch = 96;
UINT dotsPerInch = defaultDotsPerInch;
if (m_getDpiFunction)
{
dotsPerInch = m_getDpiFunction(m_win32Handle);
}
return aznumeric_cast<float>(dotsPerInch) / aznumeric_cast<float>(defaultDotsPerInch);
}
void NativeWindowImpl_Win32::EnterBorderlessWindowFullScreen()
{
if (m_isInBorderlessWindowFullScreenState)

@ -122,6 +122,8 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
FOLDER ${project_name}
)
# After ensuring that we correctly support DPI scaling, this should be switched to "PerMonitor"
set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DPI_AWARE "OFF")
if(LY_DEFAULT_PROJECT_PATH)
set_property(TARGET ${project_name}.GameLauncher APPEND PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "--project-path=\"${LY_DEFAULT_PROJECT_PATH}\"")
endif()

@ -65,9 +65,15 @@ namespace AZ
ConstViewPtr GetDefaultView() const;
//! Gets the current size of the viewport.
//! This value is cached and updated on-demand, so may be efficiently queried.
AzFramework::WindowSize GetViewportSize() const;
// SceneNotificationBus interface
//! Gets the screen DPI scaling factor.
//! This value is cached and updated on-demand, so may be efficiently queried.
//! \see AzFramework::WindowRequests::GetDpiScaleFactor
float GetDpiScalingFactor() const;
// SceneNotificationBus interface overrides...
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override;
//! Ensures our default view remains set when our scene's render pipelines are modified.
@ -75,15 +81,22 @@ namespace AZ
//! OnBeginPrepareRender is forwarded to our RenderTick notification to allow subscribers to do rendering.
void OnBeginPrepareRender() override;
//WindowNotificationBus interface
//! Used to fire a notification when our window resizes
// WindowNotificationBus interface overrides...
//! Used to fire a notification when our window resizes.
void OnWindowResized(uint32_t width, uint32_t height) override;
//! Used to fire a notification when our window DPI changes.
void OnDpiScaleFactorChanged(float dpiScaleFactor) override;
using SizeChangedEvent = AZ::Event<AzFramework::WindowSize>;
//! Notifies consumers when the viewport size has changed.
//! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportSizeChanged.
void ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler);
using ScalarChangedEvent = AZ::Event<float>;
//! Notifies consumers when the viewport DPI scaling ratio has changed.
//! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged.
void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler);
using MatrixChangedEvent = AZ::Event<const AZ::Matrix4x4&>;
//! Notifies consumers when the view matrix has changed.
void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
@ -106,7 +119,7 @@ namespace AZ
//! Notifies consumers when this ViewportContext is about to be destroyed.
void ConnectAboutToBeDestroyedHandler(ViewportIdEvent::Handler& handler);
// ViewportRequestBus interface
// ViewportRequestBus interface overrides...
//! Gets the current camera's view matrix.
const AZ::Matrix4x4& GetCameraViewMatrix() const override;
//! Sets the current camera's view matrix.
@ -130,8 +143,10 @@ namespace AZ
WindowContextSharedPtr m_windowContext;
ViewPtr m_defaultView;
AzFramework::WindowSize m_viewportSize;
float m_viewportDpiScaleFactor = 1.0f;
SizeChangedEvent m_sizeChangedEvent;
ScalarChangedEvent m_dpiScalingFactorChangedEvent;
MatrixChangedEvent m_viewMatrixChangedEvent;
MatrixChangedEvent::Handler m_onViewMatrixChangedHandler;
MatrixChangedEvent m_projectionMatrixChangedEvent;

@ -105,8 +105,10 @@ namespace AZ
class ViewportContextNotifications
{
public:
//! Called when the underlying native window size changes for a given viewport context name.
//! Called when the underlying native window size changes for a given viewport context.
virtual void OnViewportSizeChanged(AzFramework::WindowSize size){AZ_UNUSED(size);}
//! Called when the window DPI scaling changes for a given viewport context.
virtual void OnViewportDpiScalingChanged(float dpiScale){AZ_UNUSED(dpiScale);}
//! Called when the active view for a given viewport context name changes.
virtual void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view){AZ_UNUSED(view);}
//! Called when the viewport is to be rendered.

@ -51,6 +51,7 @@ namespace AZ
{
AZStd::weak_ptr<ViewportContext> context;
ViewportContext::SizeChangedEvent::Handler sizeChangedHandler;
ViewportContext::ScalarChangedEvent::Handler dpiScalingChangedHandler;
};
// ViewportContextManager is a singleton owned solely by RPISystem, which is tagged as a friend

@ -28,6 +28,10 @@ namespace AZ
m_viewportSize,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetClientAreaSize);
AzFramework::WindowRequestBus::EventResult(
m_viewportDpiScaleFactor,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetDpiScaleFactor);
AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow);
AzFramework::ViewportRequestBus::Handler::BusConnect(id);
@ -148,11 +152,21 @@ namespace AZ
return m_viewportSize;
}
float ViewportContext::GetDpiScalingFactor() const
{
return m_viewportDpiScaleFactor;
}
void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler)
{
handler.Connect(m_sizeChangedEvent);
}
void ViewportContext::ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler)
{
handler.Connect(m_dpiScalingFactorChangedEvent);
}
void ViewportContext::ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
{
handler.Connect(m_viewMatrixChangedEvent);
@ -289,5 +303,11 @@ namespace AZ
m_sizeChangedEvent.Signal(m_viewportSize);
}
}
void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor)
{
m_viewportDpiScaleFactor = dpiScaleFactor;
m_dpiScalingFactorChangedEvent.Signal(dpiScaleFactor);
}
} // namespace RPI
} // namespace AZ

@ -55,16 +55,28 @@ namespace AZ
auto onSizeChanged = [this, viewportId](AzFramework::WindowSize size)
{
// Ensure we emit OnViewportSizeChanged with the correct name.
auto viewportContext = this->GetViewportContextById(viewportId);
auto viewportContext = GetViewportContextById(viewportId);
if (viewportContext)
{
ViewportContextNotificationBus::Event(viewportContext->GetName(), &ViewportContextNotificationBus::Events::OnViewportSizeChanged, size);
}
ViewportContextIdNotificationBus::Event(viewportId, &ViewportContextIdNotificationBus::Events::OnViewportSizeChanged, size);
};
auto onDpiScalingChanged = [this, viewportId](float dpiScalingFactor)
{
// Ensure we emit OnViewportDpiScalingChanged with the correct name.
auto viewportContext = GetViewportContextById(viewportId);
if (viewportContext)
{
ViewportContextNotificationBus::Event(viewportContext->GetName(), &ViewportContextNotificationBus::Events::OnViewportDpiScalingChanged, dpiScalingFactor);
}
ViewportContextIdNotificationBus::Event(viewportId, &ViewportContextIdNotificationBus::Events::OnViewportDpiScalingChanged, dpiScalingFactor);
};
viewportContext->m_name = contextName;
viewportData.sizeChangedHandler = ViewportContext::SizeChangedEvent::Handler(onSizeChanged);
viewportData.dpiScalingChangedHandler = ViewportContext::ScalarChangedEvent::Handler(onDpiScalingChanged);
viewportContext->ConnectSizeChangedHandler(viewportData.sizeChangedHandler);
viewportContext->ConnectDpiScalingFactorChangedHandler(viewportData.dpiScalingChangedHandler);
ViewPtrStack& associatedViews = GetOrCreateViewStackForContext(contextName);
viewportContext->SetDefaultView(associatedViews.back());
onSizeChanged(viewportContext->GetViewportSize());
@ -176,6 +188,7 @@ namespace AZ
UpdateViewForContext(newContextName);
// Ensure anyone listening on per-name viewport size updates gets notified.
ViewportContextNotificationBus::Event(newContextName, &ViewportContextNotificationBus::Events::OnViewportSizeChanged, viewportContext->GetViewportSize());
ViewportContextNotificationBus::Event(newContextName, &ViewportContextNotificationBus::Events::OnViewportDpiScalingChanged, viewportContext->GetDpiScalingFactor());
}
void ViewportContextManager::EnumerateViewportContexts(AZStd::function<void(ViewportContextPtr)> visitorFunction)

@ -113,6 +113,7 @@ namespace AtomToolsFramework
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override;
protected:
// AzFramework::InputChannelEventListener ...

@ -540,4 +540,9 @@ namespace AtomToolsFramework
{
// The RenderViewportWidget does not currently support full screen.
}
float RenderViewportWidget::GetDpiScaleFactor() const
{
return aznumeric_cast<float>(devicePixelRatioF());
}
} //namespace AtomToolsFramework

@ -155,9 +155,9 @@ namespace AZ::Render
m_drawParams.m_drawViewportId = viewportContext->GetId();
auto viewportSize = viewportContext->GetViewportSize();
m_drawParams.m_position = AZ::Vector3(viewportSize.m_width, 0.0f, 1.0f) + AZ::Vector3(r_topRightBorderPadding);
m_drawParams.m_position = AZ::Vector3(viewportSize.m_width, 0.0f, 1.0f) + AZ::Vector3(r_topRightBorderPadding) * viewportContext->GetDpiScalingFactor();
m_drawParams.m_color = AZ::Colors::White;
m_drawParams.m_scale = AZ::Vector2(0.7f);
m_drawParams.m_scale = AZ::Vector2(BaseFontSize * viewportContext->GetDpiScalingFactor());
m_drawParams.m_hAlign = AzFramework::TextHorizontalAlignment::Right;
m_drawParams.m_monospace = false;
m_drawParams.m_depthTest = false;

@ -60,6 +60,8 @@ namespace AZ
void DrawPassInfo();
void DrawFramerate();
static constexpr float BaseFontSize = 0.7f;
AZStd::string m_rendererDescription;
AzFramework::TextDrawParameters m_drawParams;
AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr;

@ -50,7 +50,8 @@ namespace AZ
{
ImGui::OtherActiveImGuiRequestBus::Handler::BusConnect();
auto atomViewportRequests = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
auto atomViewportRequests = AZ::RPI::ViewportContextRequests::Get();
AZ_Assert(atomViewportRequests, "AtomViewportContextRequests interface not found!");
const AZ::Name contextName = atomViewportRequests->GetDefaultViewportContextName();
AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(contextName);
@ -105,10 +106,20 @@ namespace AZ
// Let our ImguiAtomSystemComponent know once we successfully connect and update the viewport size.
if (!m_initialized)
{
auto atomViewportRequests = AZ::RPI::ViewportContextRequests::Get();
auto defaultViewportContext = atomViewportRequests->GetDefaultViewportContext();
OnViewportDpiScalingChanged(defaultViewportContext->GetDpiScalingFactor());
m_initialized = true;
}
});
#endif
#endif //define(IMGUI_ENABLED)
}
void ImguiAtomSystemComponent::OnViewportDpiScalingChanged(float dpiScale)
{
#if defined(IMGUI_ENABLED)
ImGui::ImGuiManagerBus::Broadcast(&ImGui::ImGuiManagerBus::Events::SetDpiScalingFactor, dpiScale);
#endif //define(IMGUI_ENABLED)
}
}
}

@ -51,6 +51,7 @@ namespace AZ
// ViewportContextNotificationBus overrides...
void OnRenderTick() override;
void OnViewportSizeChanged(AzFramework::WindowSize size) override;
void OnViewportDpiScalingChanged(float dpiScale) override;
DebugConsole m_debugConsole;
bool m_initialized = false;

@ -86,6 +86,8 @@ namespace ImGui
virtual void SetImGuiRenderResolution(const ImVec2& res) = 0;
virtual void OverrideRenderWindowSize(uint32_t width, uint32_t height) = 0;
virtual void RestoreRenderWindowSizeToDefault() = 0;
virtual void SetDpiScalingFactor(float dpiScalingFactor) = 0;
virtual float GetDpiScalingFactor() const = 0;
virtual void Render() = 0;
};

@ -277,6 +277,20 @@ void ImGui::ImGuiManager::RestoreRenderWindowSizeToDefault()
InitWindowSize();
}
void ImGui::ImGuiManager::SetDpiScalingFactor(float dpiScalingFactor)
{
ImGuiIO& io = ImGui::GetIO();
// Set the global font scale to size our UI to the scaling factor
// Note: Currently we use the default, 13px fixed-size IMGUI font, so this can get somewhat blurry
io.FontGlobalScale = dpiScalingFactor;
}
float ImGui::ImGuiManager::GetDpiScalingFactor() const
{
ImGuiIO& io = ImGui::GetIO();
return io.FontGlobalScale;
}
void ImGuiManager::Render()
{
if (m_clientMenuBarState == DisplayState::Hidden && m_editorWindowState == DisplayState::Hidden)

@ -57,6 +57,8 @@ namespace ImGui
void SetImGuiRenderResolution(const ImVec2& res) override { m_renderResolution = res; }
void OverrideRenderWindowSize(uint32_t width, uint32_t height) override;
void RestoreRenderWindowSizeToDefault() override;
void SetDpiScalingFactor(float dpiScalingFactor) override;
float GetDpiScalingFactor() const override;
void Render() override;
// -- ImGuiManagerBus Interface -------------------------------------------------------------------
@ -82,7 +84,7 @@ namespace ImGui
DisplayState m_editorWindowState = DisplayState::Hidden;
// ImGui Resolution Settings
ImGuiResolutionMode m_resolutionMode = ImGuiResolutionMode::MatchToMaxRenderResolution;
ImGuiResolutionMode m_resolutionMode = ImGuiResolutionMode::MatchRenderResolution;
ImVec2 m_renderResolution = ImVec2(1920.0f, 1080.0f);
ImVec2 m_lastRenderResolution;
AzFramework::WindowSize m_windowSize = AzFramework::WindowSize(1920, 1080);

@ -133,7 +133,7 @@ class LogMonitor(object):
except AssertionError: # Raised by waiter when timeout is reached.
logger.warning(f"Timeout of '{timeout}' seconds was reached, log lines may not have been found")
# exception will be raised below by _validate_results with failure analysis
finally:
logger.info("Python log output:\n" + self.py_log)
logger.info(
"Finished log monitoring for '{}' seconds, validating results.\n"
@ -265,12 +265,21 @@ class LogMonitor(object):
self.unexpected_lines_found = unexpected_lines_found
self.expected_lines_not_found = expected_lines_not_found
exception_info = None
# To avoid race conditions, we will check *before reading*
# If in the mean time the file is closed, we will make sure we read everything by issuing an extra call
# by returning the previous alive state
process_runing = self.launcher.is_alive()
for line in log:
line = line[:-1] # remove /n
try:
process_line(line)
except LogMonitorException as e:
if exception_info is None:
exception_info = e.args
if exception_info is not None:
raise LogMonitorException(*exception_info)
return not process_runing # Will loop until the process ends

Loading…
Cancel
Save