From 08b10d33a019a983e30f8111c00a75cd0a01cf21 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 13 Jul 2025 12:31:53 +0100 Subject: [PATCH 01/29] More towards error handing with the result monad --- .../src/morpheus/gfx/d3d12/CMakeLists.txt | 4 + .../d3d12/src/morpheus/gfx/d3d12/adapter.cpp | 72 +++++++--- .../d3d12/src/morpheus/gfx/d3d12/adapter.hpp | 14 +- .../src/morpheus/gfx/d3d12/exceptions.cpp | 19 +++ .../src/morpheus/gfx/d3d12/exceptions.hpp | 42 ++++++ .../src/morpheus/gfx/d3d12/prerequisites.hpp | 3 +- .../src/morpheus/gfx/d3d12/render_system.cpp | 36 ++++- .../src/morpheus/gfx/d3d12/render_system.hpp | 2 +- .../d3d12/src/morpheus/gfx/d3d12/types.hpp | 36 +++++ .../gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp | 7 +- libraries/gfx/gl4/tests/wgl/CMakeLists.txt | 1 + libraries/gfx/gl4/tests/wgl/adapter.tests.cpp | 134 ++++++++++++++---- libraries/gfx/gl4/tests/wgl/context.tests.cpp | 5 +- 13 files changed, 312 insertions(+), 63 deletions(-) create mode 100644 libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.cpp create mode 100644 libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.hpp create mode 100644 libraries/gfx/d3d12/src/morpheus/gfx/d3d12/types.hpp diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/CMakeLists.txt b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/CMakeLists.txt index f5ae91c6e..99f9c7c43 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/CMakeLists.txt +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/CMakeLists.txt @@ -3,13 +3,17 @@ target_sources(MorpheusGfxD3D12 FILE_SET HEADERS FILES adapter.hpp + exceptions.hpp render_system.hpp + types.hpp type_mapping.hpp verify.hpp video_mode.hpp video_mode_list.hpp PRIVATE adapter.cpp + exceptions.cpp + render_system.cpp type_mapping.cpp video_mode.cpp video_mode_list.cpp diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp index 3dad3dc79..9b36bf67f 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp @@ -1,46 +1,73 @@ #include "morpheus/core/base/assert.hpp" +#include "morpheus/core/conformance/expected.hpp" #include "morpheus/core/conformance/format.hpp" #include "morpheus/gfx/d3d12/adapter.hpp" +#include "morpheus/gfx/d3d12/exceptions.hpp" +#include "morpheus/gfx/d3d12/types.hpp" #include "morpheus/gfx/d3d12/verify.hpp" +#include + +#include + #include #include namespace morpheus::gfx::d3d12 { -namespace +template +void throwOnError(DXGIExpected const& e) +{ + if (!e) { + throwD3D12Exception("HRESULT: 0x{:08X} - ", static_cast(e.error()), getLastErrorMessage()); + } +} + +/// \param[in] e The expected type from which to throw the unexpected state or return the valid value. +/// \tparam T The expected type in the DXGIExpected. +/// \return The expect value type if not in an error state. + template +T throwOrUnwrap(DXGIExpected&& e) { + throwOnError(e); + return std::move(*e); +} + -/// \using DXGIFactory -/// A RAII wrapper for the IDXGIFactory4 interface. -using DXGIFactory = Microsoft::WRL::ComPtr; -/// \using DXGIOutput -/// A RAII wrapper for the IDXGIOutput interface. -using DXGIOutput = Microsoft::WRL::ComPtr; +namespace +{ -auto createDXGIFactory() +auto createDXGIFactory() -> DXGIExpected { DXGIFactory dxgiFactory; - MORPHEUS_D3D12_VERIFY(CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory))); + HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + if (FAILED(hr)) + return exp_ns::unexpected(hr); return dxgiFactory; } -auto getAdapterDescription(const DXGIAdapter& adapter) +auto getAdapterDescription(const DXGIAdapter& adapter) -> DXGIExpected { DXGI_ADAPTER_DESC1 desc{}; - MORPHEUS_D3D12_VERIFY(adapter->GetDesc1(&desc)); + HRESULT hr = adapter->GetDesc1(&desc); + if (FAILED(hr)) + return exp_ns::unexpected(hr); return desc; } -auto getOutputModes(const DXGIOutput& output) +auto getOutputModes(const DXGIOutput& output) -> DXGIExpected> { - UINT numModes = 0; - MORPHEUS_D3D12_VERIFY(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, nullptr)); + UINT numModes = 0; + HRESULT hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, nullptr); + if (FAILED(hr)) + return std::unexpected(hr); std::vector displayModes(numModes); - MORPHEUS_D3D12_VERIFY(output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, displayModes.data())); + hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, displayModes.data()); + if (FAILED(hr)) + return std::unexpected(hr); return displayModes; } @@ -51,7 +78,7 @@ auto getOutputModes(const DXGIAdapter& adapter) for (UINT outputCount = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(outputCount, &output); ++outputCount) { - auto outputDisplayModes = getOutputModes(output); + auto outputDisplayModes = throwOrUnwrap(getOutputModes(output)); displayModes.insert( displayModes.end(), std::make_move_iterator(outputDisplayModes.begin()), @@ -68,7 +95,7 @@ Adapter::Adapter( DXGIAdapter dxgiAdapter ) : mDxgiAdapter(std::move(dxgiAdapter)) -, mDescription(getAdapterDescription(mDxgiAdapter)) +, mDescription(throwOrUnwrap(getAdapterDescription(mDxgiAdapter))) { } @@ -81,14 +108,15 @@ Adapter::Adapter( concurrency::Generator enumerateAdapters() { - auto const dxgiFactory = createDXGIFactory(); + auto const dxgiFactory = throwOrUnwrap(createDXGIFactory()); + DXGIAdapter pDXGIAdapter; for (UINT adapterId = 0; DXGI_ERROR_NOT_FOUND != dxgiFactory->EnumAdapters1(adapterId, &pDXGIAdapter); ++adapterId) { - // Ignore software adapters -// if (graphics_adapter.dxgi_description.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { -// continue; -// } + // See if the adapter support the minimum level required by Direct 3D 12 + if (FAILED(D3D12CreateDevice(pDXGIAdapter.Get(), D3D_FEATURE_LEVEL_12_0, _uuidof(ID3D12Device), nullptr))) { + continue; + } co_yield Adapter(pDXGIAdapter); } diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.hpp index dab7fbb62..abb6bc41b 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.hpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.hpp @@ -1,9 +1,10 @@ #pragma once -#include -#include #include #include +#include +#include +#include #include #include @@ -12,13 +13,8 @@ namespace morpheus::gfx::d3d12 { -/*! \typedef DXGIAdapter - A RAII wrapper for the IDXGIAdapter4 interface. - */ -using DXGIAdapter = Microsoft::WRL::ComPtr; - -/// \class adapter +/// \class Adapter /// Describes an available graphic devices on the target platform. /// class Adapter { @@ -28,10 +24,10 @@ class Adapter { /// Default construction an empty adapter. constexpr Adapter() noexcept = default; + /// Constructs an adapter with the specified parameters. /// \param[in] dxgiAdapter The DXGI adapter object. Adapter(DXGIAdapter dxgiAdapter); - ///@} /// The DXGI adapter interface. diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.cpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.cpp new file mode 100644 index 000000000..bfe8e04d6 --- /dev/null +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +#include + +#include +#include +#include + +namespace morpheus::gfx::d3d12 +{ + +void throwD3D12Exception(std::string_view message) +{ + throw boost::enable_error_info(Exception(std::string(message))) << ExceptionInfo(MORPHEUS_CURRENT_STACKTRACE); +} + +} // namespace morpheus::gfx::d3d12 diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.hpp new file mode 100644 index 000000000..524a28105 --- /dev/null +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/exceptions.hpp @@ -0,0 +1,42 @@ + +#pragma once + +#include +#include // IWYU pragma: export + +#include +#include + +namespace morpheus::gfx::d3d12 +{ + +/// \class Exception +/// +class Exception : public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; +}; + +/// \group Exception Helpers +/// Throwing of exceptions is moved to explicitly outlined functions to ensure code density around exception sites. +/// Additionally this allows to inform the compiler that exceptions are expected to be on the cold path to ensure +/// optimal code generation where exceptions are thrown. +/// @{ +/// Throws a std::runtime_error with the attached message. +[[noreturn]] MORPHEUS_FUNCTION_COLD void throwD3D12Exception(std::string_view message); + +/// Throws a std::runtime_error with the attached formatted message. +/// \param[in] fmt +/// Format string specifying message output. +/// \param[in] args +/// Arguments to be fed into the formatted message output +template +[[noreturn]] MORPHEUS_FUNCTION_COLD void throwD3D12Exception(fmt_ns::format_string fmt, Args&&... args) +{ + // Defect report https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2905r2.html resolves make_format_args to only accept l-values. + throwD3D12Exception(fmt_ns::vformat(fmt.get(), fmt_ns::make_format_args(args...))); +} +/// @} + +} // namespace morpheus::gfx::d3d12 diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/prerequisites.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/prerequisites.hpp index 26e4d147a..91b99d763 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/prerequisites.hpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/prerequisites.hpp @@ -1,5 +1,6 @@ #pragma once -#define NOMINMAX +#include "morpheus/core/base/prerequisites.hpp" + #include #include diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp index b5654da9a..8edbb03e7 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp @@ -1,12 +1,44 @@ +#include "morpheus/gfx/d3d12/adapter.hpp" #include "morpheus/gfx/d3d12/render_system.hpp" +#include "morpheus/gfx/d3d12/types.hpp" + +#include + +#include + namespace morpheus::gfx::d3d12 { -//--------------------------------------------------------------------------------------------------------------------- +template +DXGIExpected toDXGIExpected(HRESULT hr, T&& val) +{ + if (SUCCEEDED(hr)) { + return std::forward(val); + } + else { + return exp_ns::unexpected(hr); + } +} + +DXGIExpected createDGXIFactory() +{ + DXGIFactory factory; + HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)); + return toDXGIExpected(hr, std::move(factory)); +} +DXGIExpected createDevice(Adapter const& adapter) +{ + D3D12Device device; + HRESULT hr = D3D12CreateDevice(adapter.dxgiAdapter().Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&device)); + return toDXGIExpected(hr, std::move(device)); +} -//--------------------------------------------------------------------------------------------------------------------- +RenderSystem::RenderSystem() +{ + //createDGXIFactory().and_then( +} } // namespace morpheus::gfx::d3d12 diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp index d92584f57..64f899ccd 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp @@ -12,7 +12,7 @@ namespace morpheus::gfx::d3d12 class RenderSystem : public gfx::RenderSystem { public: - + RenderSystem(); private: }; diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/types.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/types.hpp new file mode 100644 index 000000000..2cc90af2f --- /dev/null +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/types.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "morpheus/core/conformance/expected.hpp" +#include "morpheus/gfx/d3d12/prerequisites.hpp" + +#include + +#include + +namespace morpheus::gfx::d3d12 +{ + +/// \using DXGIExpected +/// An alias for an expected which take any value type, but returns an unexpected HRESULT type. +/// +template +using DXGIExpected = exp_ns::expected; + +/// \using DXGIFactory +/// A RAII wrapper for the IDXGIFactory6 interface. +using DXGIFactory = Microsoft::WRL::ComPtr; + +/// \using DXGIOutput +/// A RAII wrapper for the IDXGIOutput interface. +using DXGIOutput = Microsoft::WRL::ComPtr; + +/*! \typedef DXGIAdapter + A RAII wrapper for the IDXGIAdapter1 interface. + */ +using DXGIAdapter = Microsoft::WRL::ComPtr; + +/// \using D3D12Device +/// A RAII wrapper for the ID3D12Device interface. +using D3D12Device = Microsoft::WRL::ComPtr; + +} // namespace morpheus::gfx::d3d12 diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp index ec7c01038..241f32f37 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp @@ -107,6 +107,9 @@ concurrency::Generator enumerateAdapters() continue; auto oldContext = context.value().enable(); + if (!oldContext) + continue; + std::string_view vendor = glGetStringView(GL_VENDOR); std::string_view renderer = glGetStringView(GL_RENDERER); std::string_view version = glGetStringView(GL_VERSION); @@ -126,7 +129,9 @@ concurrency::Generator enumerateAdapters() //m_uCurrentAdapter = static_cast( m_GraphicsAdapters.size() - 1 ); } } - oldContext.enable(); + auto restoredContext = oldContext.value().enable(); + if (!restoredContext) + continue; } } diff --git a/libraries/gfx/gl4/tests/wgl/CMakeLists.txt b/libraries/gfx/gl4/tests/wgl/CMakeLists.txt index 23f32f667..712fa3400 100644 --- a/libraries/gfx/gl4/tests/wgl/CMakeLists.txt +++ b/libraries/gfx/gl4/tests/wgl/CMakeLists.txt @@ -1,4 +1,5 @@ target_sources(MorpheusGfxGL4Tests PRIVATE + adapter.tests.cpp context.tests.cpp ) diff --git a/libraries/gfx/gl4/tests/wgl/adapter.tests.cpp b/libraries/gfx/gl4/tests/wgl/adapter.tests.cpp index 4411b13ac..609c73446 100644 --- a/libraries/gfx/gl4/tests/wgl/adapter.tests.cpp +++ b/libraries/gfx/gl4/tests/wgl/adapter.tests.cpp @@ -1,13 +1,17 @@ #include #include +#include #include #include + +#include #include + #include #include #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) @@ -36,43 +40,117 @@ */ #ifdef _WIN32 #include -extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; -extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; +//extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; +//extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; +extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000000; +extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000000; #endif namespace morpheus::gfx::gl4::wgl { +namespace +{ using PathInfoArray = std::vector; using ModeInfoArray = std::vector; using DisplayConfig = std::pair; -exp_ns::expected getCurrentDisplayConfig() +auto getDisplayConfigBufferSizes() -> exp_ns::expected, std::string> +{ + UINT32 pathCount = 0, modeCount = 0; + auto const result = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathCount, &modeCount); + if (result != ERROR_SUCCESS) { + return exp_ns::unexpected(win32::GetLastErrorString(result)); + } + return {std::pair{pathCount, modeCount}}; +} + +auto queryDisplayConfig(DisplayConfig config) -> exp_ns::expected { - PathInfoArray pathInfo; - ModeInfoArray modeInfo; + auto& [pathInfo, modeInfo] = config; + UINT32 pathSize = static_cast(pathInfo.size()); + UINT32 modeSize = static_cast(modeInfo.size()); + ULONG const result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathSize, pathInfo.data(), &modeSize, modeInfo.data(), NULL); + if (result != ERROR_SUCCESS) + return exp_ns::unexpected(win32::GetLastErrorString(result)); + return config; +} - // First, grab the system's current configuration - for (UINT32 trySize = 32; trySize < 1024; trySize *= 2) - { - pathInfo.resize(trySize); - modeInfo.resize(trySize); - UINT32 pathSize = static_cast(pathInfo.size()); - UINT32 modeSize = static_cast(modeInfo.size()); +auto targetDeviceName(DISPLAYCONFIG_PATH_INFO const& path) -> exp_ns::expected +{ + DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {}; + targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + targetName.header.size = sizeof(targetName); + targetName.header.adapterId = path.sourceInfo.adapterId; + targetName.header.id = path.sourceInfo.id; + auto const result = DisplayConfigGetDeviceInfo(&targetName.header); + if (result != ERROR_SUCCESS) { + return exp_ns::unexpected(win32::GetLastErrorString(result)); + } + return targetName; +} + +auto adapterName(DISPLAYCONFIG_PATH_INFO const& path) -> exp_ns::expected +{ + DISPLAYCONFIG_ADAPTER_NAME adapterName = {}; + adapterName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME; + adapterName.header.size = sizeof(adapterName); + adapterName.header.adapterId = path.sourceInfo.adapterId; + adapterName.header.id = 0; + auto const result = DisplayConfigGetDeviceInfo(&adapterName.header); + if (result != ERROR_SUCCESS) { + return exp_ns::unexpected(win32::GetLastErrorString(result)); + } + return adapterName; +} + +} +// namespace + +exp_ns::expected getCurrentDisplayConfig() +{ + return getDisplayConfigBufferSizes() + .and_then([](auto counts) -> exp_ns::expected + { + return std::apply([](auto&&... args) + { + return DisplayConfig(std::forward(args)...); + }, + std::move(counts) + ); + }) + .and_then([](auto config) + { return queryDisplayConfig(std::move(config)); }); +} - ULONG const rc = QueryDisplayConfig(QDC_ALL_PATHS, &pathSize, pathInfo.data(), &modeSize, modeInfo.data(), NULL); +auto getTargetDevicesNames(DisplayConfig const& config) -> exp_ns::expected, std::string> +{ + auto& [paths, modes] = config; - if (rc == ERROR_SUCCESS) + auto r = paths | std::ranges::views::transform([](auto const& path) { - pathInfo.resize(pathSize); - modeInfo.resize(modeSize); - break; - } + //auto targetDeviceName = targetDeviceName(path); + //auto adapterName = adapterName(path); - if (rc != ERROR_INSUFFICIENT_BUFFER) - return exp_ns::unexpected(rc); - } - return DisplayConfig{ std::move(pathInfo), std::move(modeInfo) }; + return targetDeviceName(path); + }); + + auto const result = std::ranges::fold_left(std::move(r), exp_ns::expected, std::string>{}, + [](auto&& result, auto element) -> exp_ns::expected, std::string> + { + if (!result) { + return exp_ns::unexpected(result.error()); + } + + if (!element) { + return exp_ns::unexpected(element.error()); + } + + result.value().push_back(element.value()); + return std::move(result); + }); + + return result; } TEST_CASE("Create an adapter mode list", "[morpheus.core.gfx.gl.wgl.adapter_list]") @@ -116,10 +194,16 @@ TEST_CASE("Create an adapter mode list", "[morpheus.core.gfx.gl.wgl.adapter_list */ DISPLAYCONFIG_PATH_SOURCE_INFO* pSource = NULL; // will contain the answer - auto result = getCurrentDisplayConfig(); - REQUIRE(result); + auto result = getCurrentDisplayConfig() + .and_then([](DisplayConfig const& config) { return getTargetDevicesNames(config); }); + + + auto result4 = getCurrentDisplayConfig(); + REQUIRE(result4); + + auto& [pathInfo, modeInfo] = result4.value(); + - auto& [pathInfo, modeInfo] = result.value(); for (UINT32 tryEnable = 0;; ++tryEnable) { DISPLAYCONFIG_PATH_INFO* pCurrentPath = NULL; diff --git a/libraries/gfx/gl4/tests/wgl/context.tests.cpp b/libraries/gfx/gl4/tests/wgl/context.tests.cpp index de2ba1013..2476c70cd 100644 --- a/libraries/gfx/gl4/tests/wgl/context.tests.cpp +++ b/libraries/gfx/gl4/tests/wgl/context.tests.cpp @@ -31,13 +31,14 @@ TEST_CASE("Create a WGL Context", "[morpheus.gfx.gl4.wgl.context]") WHEN("enabling the context") { auto globalContext = context.value().enable(); + REQUIRE(globalContext); THEN("expect the context to be set as active and the global context for the thread to be returned") { REQUIRE(context.value().getDC() == wglGetCurrentDC()); REQUIRE(context.value().getGL() == wglGetCurrentContext()); - REQUIRE(globalContext.getDC() == globalDC); - REQUIRE(globalContext.getGL() == globalGL); + REQUIRE(globalContext.value().getDC() == globalDC); + REQUIRE(globalContext.value().getGL() == globalGL); AND_WHEN("disabling the context") { From 0bb76d000ee59c0c530280b0b071f6786db4b2fc Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sun, 13 Jul 2025 12:35:11 +0100 Subject: [PATCH 02/29] Render window should have monadic create to handle failures --- .../morpheus/gfx/platform/win32/render_window.cpp | 12 ++++++++++-- .../morpheus/gfx/platform/win32/render_window.hpp | 5 ++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp index 40ca41ece..4b7b17c6c 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -12,12 +13,14 @@ namespace morpheus::gfx::win32 namespace { -auto getModuleHandle() +auto getModuleHandle() -> exp_ns::expected { HINSTANCE hinst = nullptr; static const TCHAR findAddressFrom = TCHAR(); auto const result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, &findAddressFrom, &hinst); - MORPHEUS_VERIFY(result); + if (!result){ + return exp_ns::unexpected(GetLastErrorString(GetLastError())); + } return hinst; } @@ -322,6 +325,11 @@ RenderWindow::~RenderWindow() ::UnregisterClass(mWindowName.c_str(), getModuleHandle()); } +exp_ns::expected RederWindow::create(Config const& config) +{ + +} + bool RenderWindow::visible() const noexcept { // If only it where this simple, IsWindowVisible only queries the status flag, not if it is actually visible: https://stackoverflow.com/a/6269768/4764531 diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp index 78824d17a..e6cfb1f8e 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include #include #include @@ -27,6 +28,8 @@ class RenderWindow : protected gfx::RenderWindow { ~RenderWindow(); + static exp_ns::expected create(Config const& config); + /// \copydoc gfx::RenderTarget::width() [[nodiscard]] std::uint16_t width() const noexcept { return gfx::RenderWindow::width(); } From 9ddec54578800b06babef8610c42e3228b28b2c9 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 12:44:19 +0100 Subject: [PATCH 03/29] Gfx devices are movables. Win32 error codes --- conanfile.py | 2 + examples/gfx/render_triangle/main.cpp | 211 ++++++- .../d3d12/src/morpheus/gfx/d3d12/adapter.cpp | 6 +- .../src/morpheus/gfx/d3d12/render_system.cpp | 10 +- .../src/morpheus/gfx/d3d12/render_system.hpp | 27 +- libraries/gfx/gl4/src/CMakeLists.txt | 5 +- .../src/morpheus/gfx/gl4/prerequisites.hpp | 3 + .../src/morpheus/gfx/gl4/render_system.hpp | 15 + .../gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp | 118 ++-- .../gl4/src/morpheus/gfx/gl4/wgl/context.cpp | 16 +- .../gl4/src/morpheus/gfx/gl4/wgl/context.hpp | 2 +- .../platform/apps/detect_monitors/main.cpp | 2 +- .../gfx/platform/win32/CMakeLists.txt | 2 + .../src/morpheus/gfx/platform/win32/error.hpp | 13 +- .../gfx/platform/win32/error_codes.cpp | 57 ++ .../gfx/platform/win32/error_codes.hpp | 47 ++ .../gfx/platform/win32/render_window.cpp | 577 ++++++++++-------- .../gfx/platform/win32/render_window.hpp | 17 +- .../tests/win32/render_window.tests.cpp | 52 +- .../src/morpheus/gfx/vulkan/error_codes.hpp | 1 + .../src/morpheus/gfx/vulkan/render_system.cpp | 23 +- .../src/morpheus/gfx/vulkan/render_system.hpp | 13 + .../src/morpheus/vis/CMakeLists.txt | 7 + .../morpheus/vis/render_system_factory.cpp | 69 +++ .../morpheus/vis/render_system_factory.hpp | 23 +- .../src/morpheus/vis/visualisation.hpp | 24 +- 26 files changed, 913 insertions(+), 429 deletions(-) create mode 100644 libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.cpp create mode 100644 libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.hpp diff --git a/conanfile.py b/conanfile.py index afd67ec35..6be9b7048 100644 --- a/conanfile.py +++ b/conanfile.py @@ -79,6 +79,7 @@ class Morpheus(ConanFile): "unordered_dense/4.5.0", "boost/1.88.0", "ctre/3.9.0", + "ftxui/6.0.2", "magic_enum/0.9.7", "ms-gsl/4.1.0", "rapidjson/cci.20230929", @@ -168,6 +169,7 @@ def requirements(self): if self.options.get_safe("with_rs_opengl", False): self.requires("glbinding/3.3.0", transitive_headers=True) self.requires("glew/2.2.0", transitive_headers=True) + self.requires("khrplatform/cci.20200529", transitive_headers=True) if self.settings.os in ["Windows"]: self.requires("wil/1.0.240803.1", transitive_headers=True) diff --git a/examples/gfx/render_triangle/main.cpp b/examples/gfx/render_triangle/main.cpp index 77bcbf39e..ba3589930 100644 --- a/examples/gfx/render_triangle/main.cpp +++ b/examples/gfx/render_triangle/main.cpp @@ -1,8 +1,11 @@ #include #include #include -//#include #include +#include + +#include +#include using namespace morpheus::application; using namespace morpheus::gfx; @@ -12,41 +15,193 @@ class RenderTriange : public Application public: using Application::Application; + RenderTriange(int argc, char const* const* argv) + : Application(argc, argv) + , window(std::move(win32::RenderWindow::create(win32::RenderWindow::Config{})).value()) + { + + } + void Run() - { - while ( true ) - { -// #pragma FREEDOM_TODO( "Hide message pump behind Freedom operating system abstraction") - - ::MSG msg; - ::ZeroMemory( &msg, sizeof(msg) ); - - // While there is messages in the queue pump them - // till the message queue until it is empty - while (::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) - { - if( ::GetMessage( &msg, NULL, 0, 0 ) ) - { - ::TranslateMessage( &msg ); - ::DispatchMessage( &msg ); - } - } - } - } + { + while ( true ) + { +// #pragma FREEDOM_TODO( "Hide message pump behind Freedom operating system abstraction") + + ::MSG msg; + ::ZeroMemory( &msg, sizeof(msg) ); + + // While there is messages in the queue pump them + // till the message queue until it is empty + while (::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( ::GetMessage( &msg, NULL, 0, 0 ) ) + { + ::TranslateMessage( &msg ); + ::DispatchMessage( &msg ); + } + } + } + } protected: - win32::RenderWindow window; + win32::RenderWindow window; }; int main(int argc, char *argv[]) { + //const std::vector renders = { + // "Direct X 12", + // "OpenGL 4", + // "Vulkan" + //}; - tryCatch( - [&] - { - RenderTriange example(argc, argv); - example.Run(); - }); + //int selectedRenders = 0; + //ftxui::Component compiler = ftxui::Radiobox(&renders, &selectedRenders); + + //auto screen = ftxui::ScreenInteractive::Fullscreen(); + ////auto testComponent = ftxui::Renderer([]() { return ftxui::text("test Component"); }); + //auto testComponent = ftxui::Renderer(compiler, [&]() { + // auto rendererWin = ftxui::window(ftxui::text("Renderer"), compiler->Render() | ftxui::vscroll_indicator | ftxui::frame); + // return rendererWin; + //}); + //screen.Loop(testComponent); + + morpheus::vis::RenderSystemFactory factory; + factory.runTuiConfiguration(); + + //tryCatch( + // [&] + // { + // RenderTriange example(argc, argv); + // example.Run(); + // }); // render_system_factory renderer_factory; } + +/* +#include +#include +#include +#include +#include +#include +#include + +using namespace ftxui; + +// Enum to track the current screen state +enum class ScreenStage { + SelectRenderer, + ConfigureRenderer, +}; + +int main() { + ScreenInteractive screen = ScreenInteractive::TerminalOutput(); + + // State + ScreenStage current_stage = ScreenStage::SelectRenderer; + + std::vector renderer_options = { + "DirectX 12", "Vulkan", "OpenGL" + }; + int selected_renderer = 0; + auto renderer_selector = Radiobox(&renderer_options, &selected_renderer); + + // Settings per renderer + std::map> renderer_settings = { + {"DirectX 12", {"Use DXIL", "Enable Tearing"}}, + {"Vulkan", {"Validation Layers", "Prefer Integrated GPU"}}, + {"OpenGL", {"Core Profile", "Enable Debug Output"}} + }; + + // Dynamic state for second screen + std::vector setting_labels; + std::vector setting_states; // Real bools for safety + std::vector setting_checkboxes; + Component settings_container = Container::Vertical({}); + + // Component placeholders + Component next_button, back_button, finish_button; + + // Container that will switch content + Component main_container = Container::Vertical({}); + + // Renderer root + Component root = Renderer(main_container, [&] { + if (current_stage == ScreenStage::SelectRenderer) { + return vbox({ + text("Select Render System:") | bold, + renderer_selector->Render(), + separator(), + next_button->Render(), + }) | border | center; + } + else { + Elements checkbox_elements; + for (auto& cb : setting_checkboxes) { + checkbox_elements.push_back(cb->Render()); + } + + return vbox({ + text("Configure Settings for: ") | bold, + text(renderer_options[selected_renderer]), + separator(), + vbox(std::move(checkbox_elements)), + separator(), + hbox({ + back_button->Render(), + finish_button->Render(), + }) | center + }) | border | center; + } + }); + + // Buttons — defined after root to capture state + next_button = Button("Next", [&] { + current_stage = ScreenStage::ConfigureRenderer; + + // Populate setting labels + bools + std::string selected_name = renderer_options[selected_renderer]; + setting_labels = renderer_settings[selected_name]; + setting_states = std::vector(setting_labels.size(), false); + setting_checkboxes.clear(); + + for (size_t i = 0; i < setting_labels.size(); ++i) { + bool local = setting_states[i]; + setting_checkboxes.push_back(Checkbox(setting_labels[i], &local)); + } + + settings_container = Container::Vertical(setting_checkboxes); + + // Reconfigure main container + main_container->DetachAllChildren(); + //main_container->Add(renderer_selector); + main_container->Add(settings_container); + main_container->Add(back_button); + main_container->Add(finish_button); + + screen.PostEvent(Event::Custom); // force re-render + }); + + back_button = Button("Back", [&] { + current_stage = ScreenStage::SelectRenderer; + main_container->DetachAllChildren(); + main_container->Add(renderer_selector); + main_container->Add(next_button); + screen.PostEvent(Event::Custom); // force re-render + }); + + finish_button = Button("Finish", [&] { + screen.Exit(); + }); + + // Initial container setup + main_container->Add(renderer_selector); + main_container->Add(next_button); + + screen.Loop(root); + return 0; +} +*/ diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp index 9b36bf67f..8a479d9df 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/adapter.cpp @@ -111,8 +111,12 @@ concurrency::Generator enumerateAdapters() auto const dxgiFactory = throwOrUnwrap(createDXGIFactory()); DXGIAdapter pDXGIAdapter; - for (UINT adapterId = 0; DXGI_ERROR_NOT_FOUND != dxgiFactory->EnumAdapters1(adapterId, &pDXGIAdapter); ++adapterId) + for (UINT adapterId = 0; ; ++adapterId) { + if (DXGI_ERROR_NOT_FOUND != dxgiFactory->EnumAdapters1(adapterId, &pDXGIAdapter)) { + break; + } + // See if the adapter support the minimum level required by Direct 3D 12 if (FAILED(D3D12CreateDevice(pDXGIAdapter.Get(), D3D_FEATURE_LEVEL_12_0, _uuidof(ID3D12Device), nullptr))) { continue; diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp index 8edbb03e7..b42998bcc 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp @@ -1,11 +1,12 @@ #include "morpheus/gfx/d3d12/adapter.hpp" #include "morpheus/gfx/d3d12/render_system.hpp" -#include "morpheus/gfx/d3d12/types.hpp" + #include #include +#include namespace morpheus::gfx::d3d12 { @@ -14,7 +15,7 @@ template DXGIExpected toDXGIExpected(HRESULT hr, T&& val) { if (SUCCEEDED(hr)) { - return std::forward(val); + return std::move(val); } else { return exp_ns::unexpected(hr); @@ -36,9 +37,10 @@ DXGIExpected createDevice(Adapter const& adapter) return toDXGIExpected(hr, std::move(device)); } -RenderSystem::RenderSystem() +auto RenderSystem::create() -> exp_ns::expected { - //createDGXIFactory().and_then( + //createDGXIFactory().and_then(); + return exp_ns::expected{RenderSystem{}}; } } // namespace morpheus::gfx::d3d12 diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp index 64f899ccd..ace55f142 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp @@ -1,20 +1,37 @@ #pragma once #include -#include +#include +#include + +#include +#include namespace morpheus::gfx::d3d12 { -/*! \class Rrender_system - Rendering system abstraction based upon the Microsoft DirectX 12 API. - */ +/// \class Rrender_system +/// Rendering system abstraction based upon the Microsoft DirectX 12 API. +/// class RenderSystem : public gfx::RenderSystem { public: - RenderSystem(); + + RenderSystem(RenderSystem const&) = delete; + RenderSystem& operator=(RenderSystem const&) = delete; + + RenderSystem(RenderSystem&&) = default; + RenderSystem& operator=(RenderSystem&&) = default; + + /// Get the name of the underlying graphic API. + static [[nodiscard]] std::string_view getGraphicsApi() noexcept { return "Direct X 12"; } + + static [[nodiscard]] auto create() -> exp_ns::expected; private: + RenderSystem() = default; + + D3D12Device mDevice; }; } // namespace morpheus::gfx::d3d12 diff --git a/libraries/gfx/gl4/src/CMakeLists.txt b/libraries/gfx/gl4/src/CMakeLists.txt index f22dd3013..95f94a911 100644 --- a/libraries/gfx/gl4/src/CMakeLists.txt +++ b/libraries/gfx/gl4/src/CMakeLists.txt @@ -1,6 +1,7 @@ find_package(OpenGL REQUIRED COMPONENTS OpenGL) find_package(GLEW REQUIRED) find_package(glbinding REQUIRED glbinding glbinding-aux) +find_package(khrplatform REQUIRED) if (NOT ${OPENGL_FOUND}) message("OpenGL not found on the system. Unable to support OpenGL based render system.") @@ -23,8 +24,8 @@ target_link_libraries(MorpheusGfxGL4 morpheus::gfx::platform OpenGL::GL GLEW::GLEW - PRIVATE -# glbinding::glbinding + glbinding::glbinding + khrplatform::khrplatform ) set_target_properties(MorpheusGfxGL4 diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/prerequisites.hpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/prerequisites.hpp index abdd5cd03..a05741678 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/prerequisites.hpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/prerequisites.hpp @@ -2,6 +2,9 @@ #include +#include +#include + #include #if (MORPHEUS_BUILD_PLATFORM==MORPHEUS_TARGET_PLATFORM_PC_WINDOWS) diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp index 0e1e1f358..77ccf30df 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp @@ -1,8 +1,12 @@ #pragma once +#include //#include #include +#include +#include + namespace morpheus::gfx::gl4 { @@ -16,6 +20,17 @@ class RenderSystem : public gfx::RenderSystem public: using Window = typename T::Window; + RenderSystem(RenderSystem const&) = delete; + RenderSystem& operator=(RenderSystem const&) = delete; + + RenderSystem(RenderSystem&&) = default; + RenderSystem& operator=(RenderSystem&&) = default; + + /// Get the name of the underlying graphic API. + static [[nodiscard]] std::string_view getGraphicsApi() noexcept { return "Open GL 4"; } + + static [[nodiscard]] auto create() -> exp_ns::expected; + private: }; diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp index 241f32f37..1f4827eff 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp @@ -26,29 +26,29 @@ namespace auto getModuleHandle() { - HINSTANCE hinst = nullptr; - static const TCHAR findAddressFrom = TCHAR(); - auto const result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, &findAddressFrom, &hinst); - MORPHEUS_WGL_VERIFY(result); - return hinst; + HINSTANCE hinst = nullptr; + static const TCHAR findAddressFrom = TCHAR(); + auto const result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, &findAddressFrom, &hinst); + MORPHEUS_WGL_VERIFY(result); + return hinst; } auto pciIdFromDeviceId(std::string_view const deviceId) { - auto const pciIdStr = deviceId.substr(deviceId.find_first_not_of("PCI\\VEN_"), 4); - std::uint32_t pciId = 0; - std::stringstream ss; - ss << std::hex << pciIdStr; - ss >> pciId; - return pciId; + auto const pciIdStr = deviceId.substr(deviceId.find_first_not_of("PCI\\VEN_"), 4); + std::uint32_t pciId = 0; + std::stringstream ss; + ss << std::hex << pciIdStr; + ss >> pciId; + return pciId; } auto vendorFromDeviceId(std::string_view const deviceId) { - auto const pciId = pciIdFromDeviceId(deviceId); - auto const vendor = vendorFromPciId(pciId); - MORPHEUS_VERIFY(vendor); - return *vendor; + auto const pciId = pciIdFromDeviceId(deviceId); + auto const vendor = vendorFromPciId(pciId); + MORPHEUS_VERIFY(vendor); + return *vendor; } std::string_view glGetStringView(GLenum name) @@ -61,46 +61,46 @@ std::string_view glGetStringView(GLenum name) LRESULT CALLBACK dummyWndProc(HWND hwnd, UINT umsg, WPARAM wp, LPARAM lp) { - return DefWindowProc(hwnd, umsg, wp, lp); + return DefWindowProc(hwnd, umsg, wp, lp); } concurrency::Generator enumerateAdapters() { auto displayDevice = DISPLAY_DEVICE{ .cb = sizeof(DISPLAY_DEVICE) }; - HINSTANCE const hinst = getModuleHandle(); + HINSTANCE const hinst = getModuleHandle(); - LPCSTR const dummyText = "WglDummyWindow"; - WNDCLASS dummyClass = { .style = CS_OWNDC,.lpfnWndProc = dummyWndProc, .hInstance = hinst, .lpszClassName = dummyText }; - RegisterClass(&dummyClass); + LPCSTR const dummyText = "WglDummyWindow"; + WNDCLASS dummyClass = { .style = CS_OWNDC,.lpfnWndProc = dummyWndProc, .hInstance = hinst, .lpszClassName = dummyText }; + RegisterClass(&dummyClass); - HWND hwnd = CreateWindow(dummyText, dummyText, WS_POPUP | WS_CLIPCHILDREN, 0, 0, 32, 32, 0, 0, - hinst, 0); + HWND hwnd = CreateWindow(dummyText, dummyText, WS_POPUP | WS_CLIPCHILDREN, 0, 0, 32, 32, 0, 0, + hinst, 0); -// auto const hDC = GetDC(hwnd); -// auto const hResults = GetLastError(); +// auto const hDC = GetDC(hwnd); +// auto const hResults = GetLastError(); - for (DWORD dwCurrentDevice = 0; ; ++dwCurrentDevice) - { - if (!EnumDisplayDevices(NULL, dwCurrentDevice, &displayDevice, 0)) - break; + for (DWORD dwCurrentDevice = 0; ; ++dwCurrentDevice) + { + if (!EnumDisplayDevices(NULL, dwCurrentDevice, &displayDevice, 0)) + break; - PIXELFORMATDESCRIPTOR pfd = - { - .nSize = sizeof(PIXELFORMATDESCRIPTOR), - .nVersion = 1, - .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - .iPixelType = PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. - .cColorBits = 32, // Colour depth of the framebuffer. - .cDepthBits = 24, // Number of bits for the depthbuffer - .cStencilBits = 8, // Number of bits for the stencilbuffer - .cAuxBuffers = 0, // Number of Aux buffers in the framebuffer. - .iLayerType = PFD_MAIN_PLANE, - }; + PIXELFORMATDESCRIPTOR pfd = + { + .nSize = sizeof(PIXELFORMATDESCRIPTOR), + .nVersion = 1, + .dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + .iPixelType = PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette. + .cColorBits = 32, // Colour depth of the framebuffer. + .cDepthBits = 24, // Number of bits for the depthbuffer + .cStencilBits = 8, // Number of bits for the stencilbuffer + .cAuxBuffers = 0, // Number of Aux buffers in the framebuffer. + .iLayerType = PFD_MAIN_PLANE, + }; -// auto const glContext = wglCreateContext(hDC); -// auto const hResult2 = GetLastError(); -// auto const successful = wglMakeCurrent(hDC, glContext); +// auto const glContext = wglCreateContext(hDC); +// auto const hResult2 = GetLastError(); +// auto const successful = wglMakeCurrent(hDC, glContext); auto context = Context::create(hwnd, pfd); if (!context) @@ -114,25 +114,25 @@ concurrency::Generator enumerateAdapters() std::string_view renderer = glGetStringView(GL_RENDERER); std::string_view version = glGetStringView(GL_VERSION); - // If the device is attached to the desktop, i.e. a graphics card - if (displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) - { - co_yield Adapter( - displayDevice.DeviceName, - displayDevice.DeviceString, - vendorFromDeviceId(displayDevice.DeviceID) - ); - - // Set the current display device to the the primary device - if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) - { - //m_uCurrentAdapter = static_cast( m_GraphicsAdapters.size() - 1 ); - } - } + // If the device is attached to the desktop, i.e. a graphics card + if (displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) + { + co_yield Adapter( + displayDevice.DeviceName, + displayDevice.DeviceString, + vendorFromDeviceId(displayDevice.DeviceID) + ); + + // Set the current display device to the the primary device + if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + { + //m_uCurrentAdapter = static_cast( m_GraphicsAdapters.size() - 1 ); + } + } auto restoredContext = oldContext.value().enable(); if (!restoredContext) continue; - } + } } } // namespace morpheus::gfx::gl4::wgl diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.cpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.cpp index cb733224d..b693de5ed 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.cpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.cpp @@ -25,7 +25,7 @@ auto createDC(HWND const window) -> WGLExpected WGLExpected choosePixelFormat(HDC const hdc, PIXELFORMATDESCRIPTOR const& pfd) { - int format = ChoosePixelFormat(hdc, &pfd); + auto const format = ChoosePixelFormat(hdc, &pfd); if (format == 0) return std::unexpected(fmt_ns::format("Failed to choose pixel format: {}", getLastErrorMessage())); return format; @@ -34,7 +34,9 @@ WGLExpected choosePixelFormat(HDC const hdc, PIXELFORMATDESCRIPTOR const& p WGLExpected setPixelFormat(HDC hdc, int format) { PIXELFORMATDESCRIPTOR pfd; - DescribePixelFormat(hdc, format, sizeof(pfd), &pfd); + if (!DescribePixelFormat(hdc, format, sizeof(pfd), &pfd)) + return std::unexpected(fmt_ns::format("Failed to describe pixel format: {}", getLastErrorMessage())); + if (!SetPixelFormat(hdc, format, &pfd)) return std::unexpected(fmt_ns::format("Failed to set pixel format: {}", getLastErrorMessage())); return {}; @@ -80,11 +82,13 @@ Context::Context() , mGLContext(wglGetCurrentContext(), {[](){}}) {} -Context Context::enable() +Context::Expected Context::enable() { - Context currentContext; - MORPHEUS_WGL_VERIFY(wglMakeCurrent(mDeviceContext.get(), mGLContext.get())); - return currentContext; + Context currenContext{}; + if (!wglMakeCurrent(mDeviceContext.get(), mGLContext.get())) { + return std::unexpected(fmt_ns::format("Failed to make OpenGL context current: {}", getLastErrorMessage())); + } + return currenContext; } void Context::disable() diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.hpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.hpp index f9e68486d..77b0e74a9 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.hpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/wgl/context.hpp @@ -31,7 +31,7 @@ class Context Context(Context&&) = default; Context& operator=(Context&&) = default; - Context enable(); + Expected enable(); void disable(); /// Gets the current OpenGL device context handle. diff --git a/libraries/gfx/platform/apps/detect_monitors/main.cpp b/libraries/gfx/platform/apps/detect_monitors/main.cpp index 24ed84cbd..55c4495a4 100644 --- a/libraries/gfx/platform/apps/detect_monitors/main.cpp +++ b/libraries/gfx/platform/apps/detect_monitors/main.cpp @@ -6,7 +6,7 @@ using namespace morpheus; using namespace morpheus::application::po; // LCOV_EXCL_START -int main(int argc, char* argv[]) +int main(int /*argc*/, char* /*argv[]*/) { for (auto const& monitor : morpheus::gfx::os::enumerateMonitors()) { diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/CMakeLists.txt b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/CMakeLists.txt index c48026dc1..09720828e 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/CMakeLists.txt +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/CMakeLists.txt @@ -3,10 +3,12 @@ target_sources(MorpheusGfxPlatform FILE_SET HEADERS FILES error.hpp + error_codes.hpp monitor.hpp render_window.hpp PRIVATE error.cpp + error_codes.cpp monitor.cpp render_window.cpp ) diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error.hpp index 5b787b17c..037865d8c 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include @@ -14,4 +14,15 @@ std::string GetLastErrorString(DWORD errorCode); std::string WStringToString(std::wstring const& wstr); +template +auto makeExpected(T&& value) +{ + return exp_ns::expected, std::string>{std::forward(value)}; +} + +inline auto makeUnexpected() +{ + return exp_ns::unexpected(GetLastErrorString(GetLastError())); +} + } // namespace morpheus::gfx::win32 diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.cpp new file mode 100644 index 000000000..e684fd048 --- /dev/null +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include + +namespace morpheus::gfx::win32 +{ + +namespace details +{ +/*! \class vulkan_error_category + Defines an error code category for Vulkan return codes to plug them into the std::error_code framework. + */ +class ErrorCategory : public std::error_category +{ +public: + /*! Queries a short form descriptive name for the category. + \return Short form name of the category. + */ + const char* name() const noexcept override final { return "Win32::ErrorCategory"; } + + /*! Queries an error string describing the error. + \return The error message. + */ + std::string message(int c) const override final + { + return GetLastErrorString(static_cast(c)); + } + + static const ErrorCategory& getSingleInstance() noexcept { return mSingleInstance; } + +private: + static ErrorCategory mSingleInstance; +}; + +ErrorCategory ErrorCategory::mSingleInstance; + +} // namespace details + +const details::ErrorCategory& ErrorCategory() noexcept { return details::ErrorCategory::getSingleInstance(); } + +} // namespace morpheus::gfx::win32 + +std::error_code make_error_code(morpheus::gfx::win32::ErrorCode const& e) +{ + return std::error_code(static_cast(e.error), morpheus::gfx::win32::ErrorCategory()); +} + +std::error_code makeWin32ErrorCode(morpheus::gfx::win32::ErrorCode error) +{ + return make_error_code(error); +} + +std::error_code makeWin32ErrorCode() +{ + return make_error_code(morpheus::gfx::win32::ErrorCode{::GetLastError()}); +} diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.hpp new file mode 100644 index 000000000..6d627b19c --- /dev/null +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/error_codes.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include + +namespace morpheus::gfx::win32 +{ + +struct [[nodiscard]] ErrorCode +{ + constexpr explicit ErrorCode(DWORD const e) noexcept : error(e) {} + DWORD error; +}; + +} // namespace morpheus::gfx::win32 + +namespace std +{ + template <> struct is_error_code_enum : true_type {}; +} + +namespace morpheus::gfx::win32 +{ + +namespace details +{ + class ErrorCategory; +} + +/// Retrieve the one instance of the Win32 error category +/// \return The one instance of the Win32 error category. +const details::ErrorCategory& ErrorCategory() noexcept; + +} // namespace morpheus::gfx::win32 + +/// Overload the global make_error_code() free function with a ErrorCode. It will be found via ADL by the compiler if needed. +/// \param[in] error The error raised by the underlying Win32 API. +/// \return A std::error_code with Win32 error encoded into it. +std::error_code make_error_code(morpheus::gfx::win32::ErrorCode const& e); + +std::error_code makeWin32ErrorCode(morpheus::gfx::win32::ErrorCode error); + +/// Overload the global make_error_code() free function with a ErrorCode. It will be found via ADL by the compiler if needed. +/// \param[in] error The error raised by the underlying Win32 API. +/// \return A std::error_code with Win32 error encoded into it. +std::error_code makeWin32ErrorCode(); diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp index 4b7b17c6c..4997bf103 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.cpp @@ -15,231 +15,233 @@ namespace { auto getModuleHandle() -> exp_ns::expected { - HINSTANCE hinst = nullptr; - static const TCHAR findAddressFrom = TCHAR(); - auto const result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, &findAddressFrom, &hinst); - if (!result){ - return exp_ns::unexpected(GetLastErrorString(GetLastError())); - } - return hinst; + HINSTANCE hinst = nullptr; + static const TCHAR findAddressFrom = TCHAR(); + auto const result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, &findAddressFrom, &hinst); + if (!result){ + return exp_ns::unexpected(GetLastErrorString(GetLastError())); + } + return hinst; } bool HandlePowerBroadCast(WPARAM wParam, LPARAM /*lParam*/) { - switch (wParam) { + switch (wParam) { - // At this point the application should save any data for open network - // connections, file, etc and prepare to go into suspended mode. - case PBT_APMQUERYSUSPEND: - { + // At this point the application should save any data for open network + // connections, file, etc and prepare to go into suspended mode. + case PBT_APMQUERYSUSPEND: + { - } - break; + } + break; - case PBT_APMRESUMESUSPEND: - { + case PBT_APMRESUMESUSPEND: + { - } - break; + } + break; - // Looks like the computers battery is getting low, should probably save any essential data - // and auto save the application state so that the user can resume the game from the current - // position. - case PBT_APMBATTERYLOW: - { + // Looks like the computers battery is getting low, should probably save any essential data + // and auto save the application state so that the user can resume the game from the current + // position. + case PBT_APMBATTERYLOW: + { - } - break; - default: - break; - } + } + break; + default: + break; + } - return true; + return true; } inline std::string getLastErrorMessage() { - DWORD const error = ::GetLastError(); - return std::system_category().message(error); + DWORD const error = ::GetLastError(); + return std::system_category().message(error); } LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - RenderWindow* thisWindow = nullptr; - - if (message != WM_CREATE) - { - // Get the pointer to the active window specified by hWnd - thisWindow = reinterpret_cast( GetWindowLongPtr( hWnd, 0 ) ) ; - } - - // Handle possible windows messages - switch(message) { - /// Handle the initial case of creating the window - case WM_CREATE: - { - LPCREATESTRUCT pCreateStruct = reinterpret_cast( lParam ); - thisWindow = reinterpret_cast( pCreateStruct->lpCreateParams ); - - MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to create window"); - - // Store pointer in window user data area - ::SetWindowLongPtr( hWnd, 0, reinterpret_cast(thisWindow) ); -// thisWindow->SetActive( true ); - } - break; - - /// Handle activation or deactivation of the window - case WM_ACTIVATE: - { - MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_ACTIVATE"); - - // Check if the window is active -// thisWindow->SetActive( WA_ACTIVE == LOWORD(wParam) ); - } - break; - - case WM_PAINT: - { - MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_PAINT"); -// if ( pThisWindow->IsActive() ) - { -// thisWindow->PresentBackBuffer(); - } - } - break; - - case WM_SIZE: - { - MORPHEUS_VERIFY_MSG(thisWindow, "morpheus::gfx::win32::WndProc() - Failed to get active window - WM_SIZE"); - thisWindow->resize(); - } - break; - - case WM_MOVE: - { - } - break; - - case WM_KEYDOWN: - { - switch (wParam) { - case 'T': - case 't': -// thisWindow->ToggleFullScreen(); - break; - } - } - break; - - case WM_COMMAND: - { - } - break; - - case WM_ENTERSIZEMOVE: - { - MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_ENTERSIZEMOVE"); -// thisWindow->SetActive( false ); - } - break; - - case WM_EXITSIZEMOVE: - { - MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_EXITSIZEMOVE"); -// pThisWindow->SetActive( true ); - - //! @todo Temp measure, find a better solution -// pThisWindow->ResizeWindow(); - } - break; - - case WM_CLOSE: - { - MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_CLOSE"); - // Shut down the relevant window -// pThisWindow->Destroy(); - } - break; - - case WM_POWERBROADCAST: - { - HandlePowerBroadCast(wParam, lParam); - } - break; - - case WM_DISPLAYCHANGE: - { - - } - break; - - case WM_DEVICECHANGE: - { - - } - break; - - case WM_SYSCOMMAND: - { - // Prevent moving/sizing and power loss in full screen mode - switch( wParam ) - { - case SC_MOVE: - case SC_SIZE: - case SC_MAXIMIZE: - case SC_KEYMENU: - case SC_MONITORPOWER: - if(thisWindow->fullScreen()) - return 1; - break; - } - } - break; - - case WM_DESTROY: - { - - } - break; - - default: - break; - } - - - return ::DefWindowProc(hWnd, message, wParam, lParam); + RenderWindow* thisWindow = nullptr; + + if (message != WM_CREATE) + { + // Get the pointer to the active window specified by hWnd + thisWindow = reinterpret_cast( GetWindowLongPtr( hWnd, 0 ) ); + } + + // Handle possible windows messages + switch(message) { + /// Handle the initial case of creating the window + case WM_CREATE: + { + LPCREATESTRUCT pCreateStruct = reinterpret_cast( lParam ); + thisWindow = reinterpret_cast( pCreateStruct->lpCreateParams ); + + MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to create window"); + + // Store pointer in window user data area + ::SetWindowLongPtr( hWnd, 0, reinterpret_cast(thisWindow) ); +// thisWindow->SetActive( true ); + } + break; + + /// Handle activation or deactivation of the window + case WM_ACTIVATE: + { + MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_ACTIVATE"); + + // Check if the window is active + //thisWindow->SetActive( WA_ACTIVE == LOWORD(wParam) ); + } + break; + + case WM_PAINT: + { + MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_PAINT"); +// if ( pThisWindow->IsActive() ) + { +// thisWindow->PresentBackBuffer(); + } + } + break; + + case WM_SIZE: + { + MORPHEUS_VERIFY_MSG(thisWindow, "morpheus::gfx::win32::WndProc() - Failed to get active window - WM_SIZE"); + thisWindow->resize(); + } + break; + + case WM_MOVE: + { + } + break; + + case WM_KEYDOWN: + { + switch (wParam) { + case 'T': + case 't': +// thisWindow->ToggleFullScreen(); + break; + } + } + break; + + case WM_COMMAND: + { + } + break; + + case WM_ENTERSIZEMOVE: + { + MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_ENTERSIZEMOVE"); +// thisWindow->SetActive( false ); + } + break; + + case WM_EXITSIZEMOVE: + { + MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_EXITSIZEMOVE"); +// pThisWindow->SetActive( true ); + + //! @todo Temp measure, find a better solution +// pThisWindow->ResizeWindow(); + } + break; + + case WM_CLOSE: + { + MORPHEUS_ASSERT_MSG(thisWindow, "Window32::WndProc() - Failed to get active window - WM_CLOSE"); + // Shut down the relevant window +// pThisWindow->Destroy(); + } + break; + + case WM_POWERBROADCAST: + { + HandlePowerBroadCast(wParam, lParam); + } + break; + + case WM_DISPLAYCHANGE: + { + + } + break; + + case WM_DEVICECHANGE: + { + + } + break; + + case WM_SYSCOMMAND: + { + // Prevent moving/sizing and power loss in full screen mode + switch( wParam ) + { + case SC_MOVE: + case SC_SIZE: + case SC_MAXIMIZE: + case SC_KEYMENU: + case SC_MONITORPOWER: + if(thisWindow->fullScreen()) + return 1; + break; + } + } + break; + + case WM_DESTROY: + { + + } + break; + + default: + break; + } + + + return ::DefWindowProc(hWnd, message, wParam, lParam); } -auto adjustWindowConfig(RenderWindow::Config& config) +auto adjustWindowConfig(RenderWindow::Config& config) -> exp_ns::expected { - // The style of the window depends select setting of our window. + // The style of the window depends select setting of our window. DWORD dwWindowStyle = (config.visible) ? WS_VISIBLE : 0; //DWORD dwWindowStyle = 0; - // Select the appropriate setting for full screen or windowed mode - if (config.fullScreen) - { - dwWindowStyle |= WS_POPUP; - - // We are in full screen mode so the window must start in the top most corner - // There is no border to take into consideration, nice and easy - config.startX = 0; - config.startY = 0; - } - else - { - // Set up windowed information - dwWindowStyle |= WS_OVERLAPPEDWINDOW; - - // Get the size of the desktop - std::int16_t const screenWidth = boost::numeric_cast(::GetSystemMetrics(SM_CXSCREEN)); - std::int16_t const screenHeight = boost::numeric_cast(::GetSystemMetrics(SM_CYSCREEN)); - - // We need to adjust the window rectangle to ensure the client is the - // requested size and takes the size of the window border into account. + // Select the appropriate setting for full screen or windowed mode + if (config.fullScreen) + { + dwWindowStyle |= WS_POPUP; + + // We are in full screen mode so the window must start in the top most corner + // There is no border to take into consideration, nice and easy + config.startX = 0; + config.startY = 0; + } + else + { + // Set up windowed information + dwWindowStyle |= WS_OVERLAPPEDWINDOW; + + // Get the size of the desktop + std::int16_t const screenWidth = boost::numeric_cast(::GetSystemMetrics(SM_CXSCREEN)); + std::int16_t const screenHeight = boost::numeric_cast(::GetSystemMetrics(SM_CYSCREEN)); + + // We need to adjust the window rectangle to ensure the client is the + // requested size and takes the size of the window border into account. RECT WndRect = {0, 0, config.width, config.height}; - MORPHEUS_VERIFY(::AdjustWindowRect(&WndRect, dwWindowStyle, false)); + if (!::AdjustWindowRect(&WndRect, dwWindowStyle, false)) { + return exp_ns::unexpected(GetLastErrorString(GetLastError())); + } config.width = std::min(static_cast(WndRect.right - WndRect.left), screenWidth); config.height = std::min(static_cast(WndRect.bottom - WndRect.top), screenHeight); @@ -248,64 +250,60 @@ auto adjustWindowConfig(RenderWindow::Config& config) config.startX = std::min(config.startX, static_cast(screenWidth - config.width)); config.startY = std::min(config.startY, static_cast(screenHeight - config.height)); } - return dwWindowStyle; + return dwWindowStyle; } auto createWindow(RenderWindow* thisWindow, RenderWindow::Config& config) { - auto const windowStyle = adjustWindowConfig(config); - auto const hInstance = getModuleHandle(); - - // Next default values for new objects - ::WNDCLASS const wcex{ - .style = CS_OWNDC, .lpfnWndProc = WndProc, .cbClsExtra = 0, .cbWndExtra = sizeof(RenderWindow*), // Reserve space for the Window pointer returned by GetWindowLong - .hInstance = hInstance, .hIcon = ::LoadIcon(nullptr, IDI_APPLICATION), .hCursor = ::LoadCursor(nullptr, IDC_ARROW), - .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1), .lpszMenuName = nullptr, .lpszClassName = config.windowName.c_str() - }; - - // Register class with the game application details - ::RegisterClass(&wcex); - - // Create the window using the WS_OVERLAPPEDWINDOW style - auto const window = ::CreateWindow(config.windowName.c_str(), config.windowName.c_str(), windowStyle, - config.startX, config.startY, config.width, config.height, - nullptr, nullptr, hInstance, thisWindow); - MORPHEUS_VERIFY(window); - return window; + auto const windowStyle = adjustWindowConfig(config); + auto const hInstance = getModuleHandle(); + + // Next default values for new objects + ::WNDCLASS const wcex{ + .style = CS_OWNDC, .lpfnWndProc = WndProc, .cbClsExtra = 0, .cbWndExtra = sizeof(RenderWindow*), // Reserve space for the Window pointer returned by GetWindowLong + .hInstance = hInstance.value(), .hIcon = ::LoadIcon(nullptr, IDI_APPLICATION), .hCursor = ::LoadCursor(nullptr, IDC_ARROW), + .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1), .lpszMenuName = nullptr, .lpszClassName = config.windowName.c_str() + }; + + // Register class with the game application details + ::RegisterClass(&wcex); + + // Create the window using the WS_OVERLAPPEDWINDOW style + auto const window = ::CreateWindow(config.windowName.c_str(), config.windowName.c_str(), windowStyle.value(), + config.startX, config.startY, config.width, config.height, + nullptr, nullptr, hInstance.value(), thisWindow); + MORPHEUS_VERIFY(window); + return window; } } -RenderWindow::RenderWindow(Config config) -: gfx::RenderWindow(config) -, mWindow(createWindow(this, config)) -{ - // Display the window and force an initial paint - //if (config.visible) - //{ - // ::ShowWindow(mWindow.get(), SW_SHOWNORMAL); - // ::UpdateWindow(mWindow.get()); - //} - - // Get the true window dimensions -/* { - RECT WinRect, ClientRect; - ::GetWindowRect(mWindow, &WinRect); - ::GetClientRect(mWindow, &ClientRect); - SetWidth(ClientRect.right); - SetHeight(ClientRect.bottom); - m_uStartX = WinRect.left; - m_uStartY = WinRect.top; - }*/ -} - -RenderWindow::RenderWindow(HWND const window) -{ - -} +//RenderWindow::RenderWindow(Config config) +//: gfx::RenderWindow(config) +//, mWindow(createWindow(this, config)) +//{ +// // Display the window and force an initial paint +// if (config.visible) +// { +// ::ShowWindow(mWindow.get(), SW_SHOWNORMAL); +// ::UpdateWindow(mWindow.get()); +// } +// +// // Get the true window dimensions +///* { +// RECT WinRect, ClientRect; +// ::GetWindowRect(mWindow, &WinRect); +// ::GetClientRect(mWindow, &ClientRect); +// SetWidth(ClientRect.right); +// SetHeight(ClientRect.bottom); +// m_uStartX = WinRect.left; +// m_uStartY = WinRect.top; +// }*/ +//} RenderWindow::RenderWindow(RenderWindow&& rhs) noexcept : gfx::RenderWindow(std::move(rhs)) +, mHInstance(std::move(rhs.mHInstance)) , mWindow(std::move(rhs.mWindow)) { SetWindowLongPtr(mWindow.get(), 0, reinterpret_cast(this)); @@ -314,26 +312,75 @@ RenderWindow::RenderWindow(RenderWindow&& rhs) noexcept RenderWindow& RenderWindow::operator=(RenderWindow&& rhs) noexcept { gfx::RenderWindow::operator=(std::move(rhs)); + mHInstance = std::move(rhs.mHInstance); mWindow = std::move(rhs.mWindow); SetWindowLongPtr(mWindow.get(), 0, reinterpret_cast(this)); return *this; } - RenderWindow::~RenderWindow() { - ::UnregisterClass(mWindowName.c_str(), getModuleHandle()); + ::UnregisterClass(mWindowName.c_str(), getModuleHandle().value()); } -exp_ns::expected RederWindow::create(Config const& config) +exp_ns::expected RenderWindow::create(Config const& config) { + RenderWindow thisWindow; + auto requestedCfg = config; + auto components = adjustWindowConfig(requestedCfg).and_then( + [](DWORD dwStyle) -> exp_ns::expected, std::string> + { + auto handle = getModuleHandle(); + if (!handle) { + return exp_ns::unexpected(handle.error()); + } + return makeExpected(std::tuple{dwStyle, handle.value()}); + } + ).and_then( + [&](auto&& pair) -> exp_ns::expected, std::string> + { + auto [dwStyle, hInstance] = pair; + // Next default values for new objects + ::WNDCLASS const wcex{ + .style = CS_OWNDC, .lpfnWndProc = WndProc, .cbClsExtra = 0, .cbWndExtra = sizeof(RenderWindow*), // Reserve space for the Window pointer returned by GetWindowLong + .hInstance = hInstance, .hIcon = ::LoadIcon(nullptr, IDI_APPLICATION), .hCursor = ::LoadCursor(nullptr, IDC_ARROW), + .hbrBackground = (HBRUSH)(COLOR_WINDOW + 1), .lpszMenuName = nullptr, .lpszClassName = requestedCfg.windowName.c_str() + }; + + // Register class with the game application details + if(!::RegisterClass(&wcex)){ + return makeUnexpected(); + } + return makeExpected(std::tuple{dwStyle, hInstance}); + } + ).and_then( + [&config = requestedCfg, &thisWindow](auto&& pair) -> exp_ns::expected, std::string> + { + auto [dwStyle, hInstance] = pair; + auto const window = ::CreateWindow( config.windowName.c_str(), config.windowName.c_str(), dwStyle, + config.startX, config.startY, config.width, config.height, + nullptr, nullptr, hInstance, &thisWindow); + if (!window) { + return makeUnexpected(); + } + return makeExpected(std::tuple{hInstance, window}); + } + ); + + if (!components) { + return exp_ns::unexpected(components.error()); + } + auto [hInstance, hWnd] = components.value(); + thisWindow.mHInstance = hInstance; + thisWindow.mWindow.reset(hWnd); + return exp_ns::expected(std::move(thisWindow)); } bool RenderWindow::visible() const noexcept { - // If only it where this simple, IsWindowVisible only queries the status flag, not if it is actually visible: https://stackoverflow.com/a/6269768/4764531 - return IsWindowVisible(mWindow.get()) == TRUE; + // If only it where this simple, IsWindowVisible only queries the status flag, not if it is actually visible: https://stackoverflow.com/a/6269768/4764531 + return IsWindowVisible(mWindow.get()) == TRUE; } void RenderWindow::resize() @@ -341,24 +388,24 @@ void RenderWindow::resize() if (!visible()) return; - RECT windowRect{}; - // Get the current starting X and Y positions of the window - ::GetWindowRect(mWindow.get(), &windowRect); - mStartX = boost::numeric_cast(windowRect.left); - mStartY = boost::numeric_cast(windowRect.top); + RECT windowRect{}; + // Get the current starting X and Y positions of the window + ::GetWindowRect(mWindow.get(), &windowRect); + mStartX = boost::numeric_cast(windowRect.left); + mStartY = boost::numeric_cast(windowRect.top); - // Get the width and height of the drawable area - ::GetClientRect(mWindow.get(), &windowRect); + // Get the width and height of the drawable area + ::GetClientRect(mWindow.get(), &windowRect); - // If the width and height have not changed then we have nothing to do - if ((width() == windowRect.right) && (height() == windowRect.bottom)) - return; + // If the width and height have not changed then we have nothing to do + if ((width() == windowRect.right) && (height() == windowRect.bottom)) + return; - // We need to save the new width and height - mWidth = boost::numeric_cast(windowRect.right); - mHeight = boost::numeric_cast(windowRect.bottom); + // We need to save the new width and height + mWidth = boost::numeric_cast(windowRect.right); + mHeight = boost::numeric_cast(windowRect.bottom); - debugPrint(fmt_ns::format("Window <{}> is at start <{}, {}> with dimensions <{}, {}>\n", mWindowName, mStartX, mStartY, mWidth, mHeight)); + debugPrint(fmt_ns::format("Window <{}> is at start <{}, {}> with dimensions <{}, {}>\n", mWindowName, mStartX, mStartY, mWidth, mHeight)); } } // namespace morpheus::gfx::win32 diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp index e6cfb1f8e..ffedfa1c1 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/win32/render_window.hpp @@ -5,6 +5,8 @@ #include #include + +#include #include namespace morpheus::gfx::win32 @@ -17,9 +19,6 @@ class RenderWindow : protected gfx::RenderWindow { using WindowHandle = HWND; using Config = gfx::RenderWindow::Config; - explicit RenderWindow(Config const config = Config{}); - explicit RenderWindow(WindowHandle const window); - explicit RenderWindow(RenderWindow const&) = delete; RenderWindow& operator=(RenderWindow const&) = delete; @@ -28,7 +27,12 @@ class RenderWindow : protected gfx::RenderWindow { ~RenderWindow(); - static exp_ns::expected create(Config const& config); + /// Creates a render window or returns an error if creation failed. + /// \param[in] config + /// The setting to configure the window with. + /// \return + /// An expected of the newly created window, or an error if creation failed. + static exp_ns::expected create(Config const& config = Config{}); /// \copydoc gfx::RenderTarget::width() [[nodiscard]] std::uint16_t width() const noexcept { return gfx::RenderWindow::width(); } @@ -60,9 +64,12 @@ class RenderWindow : protected gfx::RenderWindow { auto getHandle() const noexcept { return mWindow.get(); } private: + RenderWindow() = default; + friend LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); - wil::unique_hwnd mWindow; /// OS window handle + std::optional mHInstance; /// HInstance of initiating module. + wil::unique_hwnd mWindow; /// OS window handle. }; } // namespace morpheus::gfx::win32 diff --git a/libraries/gfx/platform/tests/win32/render_window.tests.cpp b/libraries/gfx/platform/tests/win32/render_window.tests.cpp index d42ea9916..df7146f05 100644 --- a/libraries/gfx/platform/tests/win32/render_window.tests.cpp +++ b/libraries/gfx/platform/tests/win32/render_window.tests.cpp @@ -7,36 +7,36 @@ namespace morpheus::gfx::win32 TEST_CASE("Ensure move construction of a win32 render window", "[morpheus.gfx.win32.render_window.construct.move]") { - RenderWindow::Config const config; - RenderWindow window(config); - - REQUIRE(!window.fullScreen()); - REQUIRE(window.width() == config.width); - REQUIRE(window.height() == config.height); - REQUIRE(window.colourDepth() == config.colourDepth); - - RenderWindow newWindow(std::move(window)); - REQUIRE(!newWindow.fullScreen()); - REQUIRE(newWindow.width() == config.width); - REQUIRE(newWindow.height() == config.height); - REQUIRE(newWindow.colourDepth() == config.colourDepth); + //RenderWindow::Config const config; + //RenderWindow window(config); + + //REQUIRE(!window.fullScreen()); + //REQUIRE(window.width() == config.width); + //REQUIRE(window.height() == config.height); + //REQUIRE(window.colourDepth() == config.colourDepth); + + //RenderWindow newWindow(std::move(window)); + //REQUIRE(!newWindow.fullScreen()); + //REQUIRE(newWindow.width() == config.width); + //REQUIRE(newWindow.height() == config.height); + //REQUIRE(newWindow.colourDepth() == config.colourDepth); } TEST_CASE("Ensure default construction of a win32 render window by defaulted config accessors", "[morpheus.gfx.win32.render_window]") { - RenderWindow::Config const config; - RenderWindow window(config); - - REQUIRE(!window.fullScreen()); - REQUIRE(window.width() == config.width); - REQUIRE(window.height() == config.height); - REQUIRE(window.colourDepth() == config.colourDepth); - REQUIRE(IsWindowVisible(window.getHandle())); - - RECT rect; - REQUIRE(GetClientRect(window.getHandle(), &rect)); - REQUIRE(window.width() == static_cast(rect.right - rect.left)); - REQUIRE(window.height() == static_cast(rect.bottom - rect.top)); + //RenderWindow::Config const config; + //RenderWindow window(config); + + //REQUIRE(!window.fullScreen()); + //REQUIRE(window.width() == config.width); + //REQUIRE(window.height() == config.height); + //REQUIRE(window.colourDepth() == config.colourDepth); + //REQUIRE(IsWindowVisible(window.getHandle())); + + //RECT rect; + //REQUIRE(GetClientRect(window.getHandle(), &rect)); + //REQUIRE(window.width() == static_cast(rect.right - rect.left)); + //REQUIRE(window.height() == static_cast(rect.bottom - rect.top)); } } // namespace morpheus::gfx::win32 diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp index 73fa94566..58e9e4b02 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp @@ -1,6 +1,7 @@ #pragma once #include + #include namespace std diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.cpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.cpp index 49bb2a8c8..b66eaebd8 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.cpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.cpp @@ -17,30 +17,29 @@ namespace } //--------------------------------------------------------------------------------------------------------------------- +// LCOV_EXCL_START RenderSystem::RenderSystem(std::string_view const appName, std::string_view const engineName) -: mInstance( // LCOV_EXCL_LINE - [&] // LCOV_EXCL_LINE +: mInstance( + [&] { // initialize the vk::ApplicationInfo structure - vk::ApplicationInfo applicationInfo(appName.data(), 1, engineName.data(), 1, VK_API_VERSION_1_1); // LCOV_EXCL_LINE + vk::ApplicationInfo applicationInfo(appName.data(), 1, engineName.data(), 1, VK_API_VERSION_1_1); // initialize the vk::InstanceCreateInfo - vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo); // LCOV_EXCL_LINE + vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo); // create an Instance - return vk::raii::Instance(mContext, instanceCreateInfo); // LCOV_EXCL_LINE + return vk::raii::Instance(mContext, instanceCreateInfo); }()) -, mVulkanVersion(mContext.enumerateInstanceVersion()) // LCOV_EXCL_LINE -, mAvailableExtensions(mContext.enumerateInstanceExtensionProperties()) // LCOV_EXCL_LINE -, mAvailableLayers(mContext.enumerateInstanceLayerProperties()) // LCOV_EXCL_LINE -, mAdapters(enumerateAdapters(mInstance)) // LCOV_EXCL_LINE +, mVulkanVersion(mContext.enumerateInstanceVersion()) +, mAvailableExtensions(mContext.enumerateInstanceExtensionProperties()) +, mAvailableLayers(mContext.enumerateInstanceLayerProperties()) +, mAdapters(enumerateAdapters(mInstance)) { } -//--------------------------------------------------------------------------------------------------------------------- - - +// LCOV_EXCL_STOP //--------------------------------------------------------------------------------------------------------------------- } // namespace morpheus::gfx::vulkan diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp index 95a3dff63..1b7862def 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -20,6 +21,18 @@ class RenderSystem : public gfx::RenderSystem { public: RenderSystem(std::string_view const appName, std::string_view const engineName); + RenderSystem(RenderSystem const&) = delete; + RenderSystem& operator=(RenderSystem const&) = delete; + + RenderSystem(RenderSystem&&) = default; + RenderSystem& operator=(RenderSystem&&) = default; + + /// Get the name of the underlying graphic API. + static [[nodiscard]] auto getGraphicsApi() noexcept -> std::string_view { return "Vulkan"; } + + static [[nodiscard]] auto create() -> exp_ns::expected; + + auto const& adapters() const { return mAdapters; } private: vk::raii::Context mContext; /// Vulkan context including loader. diff --git a/libraries/visualisation/src/morpheus/vis/CMakeLists.txt b/libraries/visualisation/src/morpheus/vis/CMakeLists.txt index e0dd95d94..9a2416481 100644 --- a/libraries/visualisation/src/morpheus/vis/CMakeLists.txt +++ b/libraries/visualisation/src/morpheus/vis/CMakeLists.txt @@ -1,3 +1,5 @@ +find_package(ftxui) + target_sources(MorpheusVisualisation PUBLIC FILE_SET HEADERS @@ -8,3 +10,8 @@ target_sources(MorpheusVisualisation render_system_factory.cpp visualisation.cpp ) + +target_link_libraries(MorpheusVisualisation + PRIVATE + ftxui::ftxui +) diff --git a/libraries/visualisation/src/morpheus/vis/render_system_factory.cpp b/libraries/visualisation/src/morpheus/vis/render_system_factory.cpp index a0ee4e004..050f2504c 100644 --- a/libraries/visualisation/src/morpheus/vis/render_system_factory.cpp +++ b/libraries/visualisation/src/morpheus/vis/render_system_factory.cpp @@ -1,10 +1,79 @@ +#include #include +#include + +#include +#include + +namespace hana = boost::hana; + namespace morpheus::vis { //--------------------------------------------------------------------------------------------------------------------- +void RenderSystemFactory::addOptions(boost::program_options::options_description& options) +{ + namespace po = boost::program_options; + options.add_options()("render-system", po::value(&mActiveApi)->default_value(mActiveApi), "The rendering system to instantiate."); +} + + +//boost::program_options::options_description& RenderSystemFactory::runTuiConfiguration() +void RenderSystemFactory::runTuiConfiguration() +{ + const auto renderSystems = [](){ + std::vector results; + boost::hana::for_each(availableAPIs(), [&](const auto& pair) + { + //constexpr auto key = hana::first(pair); + auto value = hana::second(pair); + using RenderSystem = typename decltype(value)::type; + results.push_back(std::string(RenderSystem::getGraphicsApi())); + } + ); + return results; + }(); + + using namespace ftxui; + + enum class Pages + { + SelectRenderSystem, + RenderSystemSettings, + }; + + Pages current = Pages::SelectRenderSystem; + auto screen = ftxui::ScreenInteractive::Fullscreen(); + + // -- 1. Render System selection + + int selectedRenders = 0; + auto renderSystemRadioBox = ftxui::Radiobox(&renderSystems, &selectedRenders); + //auto nextButton = ftxui::Button("Next", [&] { current = Pages::SelectRenderSystem; screen.PostEvent(ftxui::Event::Custom); }); + auto nextButton = ftxui::Button("Next", [&] { current = Pages::SelectRenderSystem; screen.Exit(); }); + auto selectRenderSystemPage = ftxui::Container::Vertical({renderSystemRadioBox, nextButton}); + auto selectRSRenderer = Renderer(selectRenderSystemPage, [&] { + return vbox({ + text("Select Render System:") | bold, + renderSystemRadioBox->Render(), + separator(), + nextButton->Render(), + }) | border | center; + }); + + // -- 2. Render System Settings selection + screen.Loop(selectRSRenderer); + + //auto testComponent = ftxui::Renderer(selectRSRenderer, + // [&]() + // { + // auto rendererWin = ftxui::window(ftxui::text("Render System"), render->Render() | ftxui::vscroll_indicator | ftxui::frame); + // return rendererWin; + // }); + //screen.Loop(testComponent); +} //--------------------------------------------------------------------------------------------------------------------- diff --git a/libraries/visualisation/src/morpheus/vis/render_system_factory.hpp b/libraries/visualisation/src/morpheus/vis/render_system_factory.hpp index 1a09a3ecd..8e55b7c64 100644 --- a/libraries/visualisation/src/morpheus/vis/render_system_factory.hpp +++ b/libraries/visualisation/src/morpheus/vis/render_system_factory.hpp @@ -1,11 +1,10 @@ #pragma once -#include "morpheus/application/po/adapters/enum.hpp" #include #if (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_APPLE) #include -#elif (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_WINDOWS) +#elif (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_PC_WINDOWS) #include #endif // #if (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_APPLE) @@ -18,11 +17,14 @@ #include #include -#include - #include #include +namespace boost::program_options +{ + class options_description; +} + namespace morpheus::vis { @@ -54,15 +56,14 @@ class RenderSystemFactory /*! */ - RenderSystemFactory(); + RenderSystemFactory() = default; ///@} /// Register program options - void addOptions(boost::program_options::options_description& options) - { - namespace po = boost::program_options; - options.add_options()("render-system", po::value(&mActiveApi)->default_value(mActiveApi), "The rendering system to instantiate."); - } + void addOptions(boost::program_options::options_description& options); + + //boost::program_options::options_description& runTuiConfiguration(); + void runTuiConfiguration(); private: @@ -74,7 +75,7 @@ class RenderSystemFactory return hana::make_map( #if (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_APPLE) hana::make_pair(RenderSystemType, hana::type_c), -#elif (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_WINDOWS) +#elif (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_PC_WINDOWS) hana::make_pair(RenderSystemType, hana::type_c), #endif // #if (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_APPLE) hana::make_pair(RenderSystemType, hana::type_c>), diff --git a/libraries/visualisation/src/morpheus/vis/visualisation.hpp b/libraries/visualisation/src/morpheus/vis/visualisation.hpp index 4a03c16e3..f34f87397 100644 --- a/libraries/visualisation/src/morpheus/vis/visualisation.hpp +++ b/libraries/visualisation/src/morpheus/vis/visualisation.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -18,15 +19,34 @@ class Visualisation { Visualisation(Visualisation const&) = delete; Visualisation& operator=(Visualisation const&) = delete; + Visualisation(Visualisation&&) = default; + Visualisation& operator=(Visualisation&&) = default; + + exp_ns::expected create(R&& renderSystem); + /// Register program options void addOptions(boost::program_options::options_description& ) { } private: - R mRenderSystem; + Visualisation(R&& renderSystem, typename R::Window&& window); - // N windows + R mRenderSystem; + typename R::Window mWindow; }; +template +Visualisation::Visualisation(R&& renderSystem, typename R::Window&& window) +: mRenderSystem(std::move(renderSystem)) +, mWindow(std::move(window)) +{ +} + +template +exp_ns::expected, std::string> Visualisation::create(R&& renderSystem) +{ + +} + } // namespace morpheus::vis From 9425897e7e2e5d04481e0b756e662530b6062f60 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 13:02:02 +0100 Subject: [PATCH 04/29] Correct no discard usage on statics --- libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp | 4 ++-- libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp | 4 ++-- .../gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp index ace55f142..e61392099 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp @@ -24,9 +24,9 @@ class RenderSystem : public gfx::RenderSystem RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - static [[nodiscard]] std::string_view getGraphicsApi() noexcept { return "Direct X 12"; } + [[nodiscard]] static std::string_view getGraphicsApi() noexcept { return "Direct X 12"; } - static [[nodiscard]] auto create() -> exp_ns::expected; + [[nodiscard]] static auto create() -> exp_ns::expected; private: RenderSystem() = default; diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp index 77ccf30df..0d147df70 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp @@ -27,9 +27,9 @@ class RenderSystem : public gfx::RenderSystem RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - static [[nodiscard]] std::string_view getGraphicsApi() noexcept { return "Open GL 4"; } + [[nodiscard]] static std::string_view getGraphicsApi() noexcept { return "Open GL 4"; } - static [[nodiscard]] auto create() -> exp_ns::expected; + [[nodiscard]] static auto create() -> exp_ns::expected; private: }; diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp index 1b7862def..1c6825dae 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp @@ -28,9 +28,9 @@ class RenderSystem : public gfx::RenderSystem { RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - static [[nodiscard]] auto getGraphicsApi() noexcept -> std::string_view { return "Vulkan"; } + [[nodiscard]] static auto getGraphicsApi() noexcept -> std::string_view { return "Vulkan"; } - static [[nodiscard]] auto create() -> exp_ns::expected; + [[nodiscard]] static auto create() -> exp_ns::expected; auto const& adapters() const { return mAdapters; } From b8da081fbc007ee7c0bc036e98ba00f647d58588 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 13:19:48 +0100 Subject: [PATCH 05/29] Enforce getGraphicsApi across render systems --- libraries/gfx/gl4/tests/concept_checks.tests.cpp | 2 +- .../metal/src/morpheus/gfx/metal/render_system.hpp | 11 +++++++++++ .../morpheus/gfx/platform/concepts/render_system.hpp | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/libraries/gfx/gl4/tests/concept_checks.tests.cpp b/libraries/gfx/gl4/tests/concept_checks.tests.cpp index f7d46f970..8bb987fe2 100644 --- a/libraries/gfx/gl4/tests/concept_checks.tests.cpp +++ b/libraries/gfx/gl4/tests/concept_checks.tests.cpp @@ -8,7 +8,7 @@ namespace morpheus::gfx::gl4 TEST_CASE("Test the GL render system adheres to GFX concepts", "[morpheus.gfx.gl4.concept_checks]") { - STATIC_REQUIRE(concepts::RenderSystem); + STATIC_REQUIRE(concepts::RenderSystem>); } } // namespace morpheus::gfx::gl4 diff --git a/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp b/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp index c3a582572..4d838aa17 100644 --- a/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp +++ b/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp @@ -1,5 +1,7 @@ #pragma once +#include + namespace morpheus::gfx::metal { @@ -8,7 +10,16 @@ namespace morpheus::gfx::metal */ class RenderSystem { public: + using Window = typename void; + + RenderSystem(RenderSystem const&) = delete; + RenderSystem& operator=(RenderSystem const&) = delete; + + RenderSystem(RenderSystem&&) = default; + RenderSystem& operator=(RenderSystem&&) = default; + /// Get the name of the underlying graphic API. + [[nodiscard]] static std::string_view getGraphicsApi() noexcept { return "Metal"; } private: class Implementation; diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_system.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_system.hpp index 07535dce7..7e18619fd 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_system.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_system.hpp @@ -18,6 +18,8 @@ concept RenderSystem = requires(T t) { typename T::Window; + { T::getGraphicsApi() } -> std::same_as; + // requires !meta::Copyable; // { t.adapters() } -> AdapterRange; From 3506265d99d283c4d019409f6c065b6c62c6c362 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 13:55:35 +0100 Subject: [PATCH 06/29] Update context tests for monadic interface --- libraries/gfx/gl4/tests/wgl/context.tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gfx/gl4/tests/wgl/context.tests.cpp b/libraries/gfx/gl4/tests/wgl/context.tests.cpp index 2476c70cd..6da0dc1ca 100644 --- a/libraries/gfx/gl4/tests/wgl/context.tests.cpp +++ b/libraries/gfx/gl4/tests/wgl/context.tests.cpp @@ -20,8 +20,8 @@ TEST_CASE("Create a WGL Context", "[morpheus.gfx.gl4.wgl.context]") .cDepthBits = 24, .cStencilBits = 8, .iLayerType = PFD_MAIN_PLANE}; - win32::RenderWindow window; - auto context = Context::create(window.getHandle(), pxlFmtDescriptor); + auto window = win32::RenderWindow::create(); + auto context = Context::create(window.value().getHandle(), pxlFmtDescriptor); REQUIRE(context); wglMakeCurrent(nullptr, nullptr); From 88d8792e9a8ba5f5521226544f9364fff57c96bf Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 14:08:22 +0100 Subject: [PATCH 07/29] Access the visualisation layer --- examples/gfx/render_triangle/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/gfx/render_triangle/CMakeLists.txt b/examples/gfx/render_triangle/CMakeLists.txt index 629ba15d6..d18b109d2 100644 --- a/examples/gfx/render_triangle/CMakeLists.txt +++ b/examples/gfx/render_triangle/CMakeLists.txt @@ -1,10 +1,13 @@ add_executable(RenderTriangle main.cpp) +find_package(ftxui) target_link_libraries(RenderTriangle PRIVATE + ftxui::ftxui morpheus::application morpheus::gfx::platform morpheus::gfx::gl4 + morpheus::vis ) set_target_properties(RenderTriangle From e2007764143eb96f25a7566e2e1da4e7f7333f0f Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 14:30:16 +0100 Subject: [PATCH 08/29] Mac os compile fix --- libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp b/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp index 4d838aa17..77e9a4317 100644 --- a/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp +++ b/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp @@ -10,7 +10,7 @@ namespace morpheus::gfx::metal */ class RenderSystem { public: - using Window = typename void; + using Window = void; RenderSystem(RenderSystem const&) = delete; RenderSystem& operator=(RenderSystem const&) = delete; From c9be97be274c877c1b3be21bef97ca52a7d9003d Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Sat, 19 Jul 2025 17:34:56 +0100 Subject: [PATCH 09/29] Correct program args --- libraries/gfx/platform/apps/detect_monitors/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gfx/platform/apps/detect_monitors/main.cpp b/libraries/gfx/platform/apps/detect_monitors/main.cpp index 55c4495a4..4d342e022 100644 --- a/libraries/gfx/platform/apps/detect_monitors/main.cpp +++ b/libraries/gfx/platform/apps/detect_monitors/main.cpp @@ -6,7 +6,7 @@ using namespace morpheus; using namespace morpheus::application::po; // LCOV_EXCL_START -int main(int /*argc*/, char* /*argv[]*/) +int main(int /*argc*/, char*[] /*argv[]*/) { for (auto const& monitor : morpheus::gfx::os::enumerateMonitors()) { From 56c18467b50bfe94e869aded4965be3a2a5db675 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Mon, 21 Jul 2025 10:35:20 +0100 Subject: [PATCH 10/29] Ensure coverage for graphic API name --- .../src/morpheus/application/version.hpp | 2 +- .../src/morpheus/gfx/d3d12/render_system.cpp | 9 +++++++-- .../src/morpheus/gfx/d3d12/render_system.hpp | 9 +++++++-- libraries/gfx/d3d12/tests/CMakeLists.txt | 1 + .../gfx/d3d12/tests/render_system.tests.cpp | 14 ++++++++++++++ .../gfx/d3d12/tests/video_mode_list.tests.cpp | 4 +++- .../gl4/src/morpheus/gfx/gl4/render_system.hpp | 2 +- .../gfx/gl4/tests/render_system.tests.cpp | 16 +++++++++++++++- .../src/morpheus/gfx/metal/render_system.hpp | 2 +- libraries/gfx/metal/tests/CMakeLists.txt | 1 + .../gfx/metal/tests/render_system.tests.cpp | 13 +++++++++++++ .../src/morpheus/gfx/vulkan/render_system.hpp | 2 +- libraries/gfx/vulkan/tests/CMakeLists.txt | 2 +- .../gfx/vulkan/tests/render_system.tests.cpp | 18 ++++++++++++++++-- 14 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 libraries/gfx/d3d12/tests/render_system.tests.cpp create mode 100644 libraries/gfx/metal/tests/render_system.tests.cpp diff --git a/libraries/application/src/morpheus/application/version.hpp b/libraries/application/src/morpheus/application/version.hpp index ae6cb1e9d..38f80db4d 100644 --- a/libraries/application/src/morpheus/application/version.hpp +++ b/libraries/application/src/morpheus/application/version.hpp @@ -54,7 +54,7 @@ struct morpheus::scan_ns::scanner : morpheus::sc /// \param ctx The scan context. /// \return An expected iterator pointing to the end of the scanned version, or the scan error if it failed. template - auto scan(morpheus::application::Version& val, Context& ctx) const -> morpheus::scan_ns::scan_expected + constexpr auto scan(morpheus::application::Version& val, Context& ctx) const -> morpheus::scan_ns::scan_expected { return morpheus::scan_ns::scan(ctx.range(), "{{major={},minor={},patch={}}}") .transform( diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp index b42998bcc..be17629fd 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.cpp @@ -37,9 +37,14 @@ DXGIExpected createDevice(Adapter const& adapter) return toDXGIExpected(hr, std::move(device)); } -auto RenderSystem::create() -> exp_ns::expected +auto RenderSystem::create(Adapter const& adapter) -> exp_ns::expected { - //createDGXIFactory().and_then(); + //auto device = createDevice(adapter).and_then([](auto&& /*device*/) + // { + // return exp_ns::expected{RenderSystem{}}; + // } + //); + //return device; return exp_ns::expected{RenderSystem{}}; } diff --git a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp index e61392099..a9732a670 100644 --- a/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp +++ b/libraries/gfx/d3d12/src/morpheus/gfx/d3d12/render_system.hpp @@ -10,6 +10,8 @@ namespace morpheus::gfx::d3d12 { +class Adapter; + /// \class Rrender_system /// Rendering system abstraction based upon the Microsoft DirectX 12 API. /// @@ -24,9 +26,12 @@ class RenderSystem : public gfx::RenderSystem RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - [[nodiscard]] static std::string_view getGraphicsApi() noexcept { return "Direct X 12"; } + [[nodiscard]] static constexpr auto getGraphicsApi() noexcept -> std::string_view { return "Direct X 12"; } - [[nodiscard]] static auto create() -> exp_ns::expected; + /// Creates the D3D12 render system on the specified graphics adapter. + /// \param[in] adapter + /// The graphics adapter to create the device on. + [[nodiscard]] static auto create(Adapter const& adapter) -> exp_ns::expected; private: RenderSystem() = default; diff --git a/libraries/gfx/d3d12/tests/CMakeLists.txt b/libraries/gfx/d3d12/tests/CMakeLists.txt index 1c2709fb1..22649bec1 100644 --- a/libraries/gfx/d3d12/tests/CMakeLists.txt +++ b/libraries/gfx/d3d12/tests/CMakeLists.txt @@ -12,5 +12,6 @@ target_link_libraries(MorpheusGfxD3D12Tests target_sources(MorpheusGfxD3D12Tests PRIVATE adapter.tests.cpp + render_system.tests.cpp video_mode_list.tests.cpp ) diff --git a/libraries/gfx/d3d12/tests/render_system.tests.cpp b/libraries/gfx/d3d12/tests/render_system.tests.cpp new file mode 100644 index 000000000..ad1424fc6 --- /dev/null +++ b/libraries/gfx/d3d12/tests/render_system.tests.cpp @@ -0,0 +1,14 @@ +#include + +#include + +namespace morpheus::gfx::d3d12::test +{ +// using namespace morpheus::gfx; + +TEST_CASE("Verify the Graphics API", "[morpheus.gfx.d3d12.render_system.api]") +{ + STATIC_REQUIRE(RenderSystem::getGraphicsApi() == "Direct X 12"); +} + +} // namespace morpheus::gfx::d3d12::test diff --git a/libraries/gfx/d3d12/tests/video_mode_list.tests.cpp b/libraries/gfx/d3d12/tests/video_mode_list.tests.cpp index 8722e0f3a..34d5b5c68 100644 --- a/libraries/gfx/d3d12/tests/video_mode_list.tests.cpp +++ b/libraries/gfx/d3d12/tests/video_mode_list.tests.cpp @@ -1,6 +1,8 @@ -#include +#include #include +#include + namespace morpheus::gfx::d3d12 { diff --git a/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp b/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp index 0d147df70..fb000d655 100644 --- a/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp +++ b/libraries/gfx/gl4/src/morpheus/gfx/gl4/render_system.hpp @@ -27,7 +27,7 @@ class RenderSystem : public gfx::RenderSystem RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - [[nodiscard]] static std::string_view getGraphicsApi() noexcept { return "Open GL 4"; } + [[nodiscard]] static constexpr auto getGraphicsApi() noexcept -> std::string_view { return "Open GL 4"; } [[nodiscard]] static auto create() -> exp_ns::expected; diff --git a/libraries/gfx/gl4/tests/render_system.tests.cpp b/libraries/gfx/gl4/tests/render_system.tests.cpp index 4ed2732bc..f81e780d9 100644 --- a/libraries/gfx/gl4/tests/render_system.tests.cpp +++ b/libraries/gfx/gl4/tests/render_system.tests.cpp @@ -1,5 +1,19 @@ +#include +#include + #include -TEST_CASE("Test the GL render system", "[morpheus.core.gfx.gl4.render_system]") +namespace morpheus::gfx::gl4::test +{ +// using namespace morpheus::gfx; + +TEST_CASE("Verify the Graphics API", "[morpheus.gfx.gl4.render_system.api]") { + STATIC_REQUIRE(RenderSystem::getGraphicsApi() == "Open GL 4"); } + +TEST_CASE("Test the GL render system", "[morpheus.gfx.gl4.render_system]") +{ +} + +} // namespace morpheus::gfx::gl4::test diff --git a/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp b/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp index 77e9a4317..b914ae3c9 100644 --- a/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp +++ b/libraries/gfx/metal/src/morpheus/gfx/metal/render_system.hpp @@ -19,7 +19,7 @@ class RenderSystem { RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - [[nodiscard]] static std::string_view getGraphicsApi() noexcept { return "Metal"; } + [[nodiscard]] static constexpr auto getGraphicsApi() noexcept -> std::string_view { return "Metal"; } private: class Implementation; diff --git a/libraries/gfx/metal/tests/CMakeLists.txt b/libraries/gfx/metal/tests/CMakeLists.txt index a799960d2..c3e21d4ec 100644 --- a/libraries/gfx/metal/tests/CMakeLists.txt +++ b/libraries/gfx/metal/tests/CMakeLists.txt @@ -11,6 +11,7 @@ target_link_libraries(MorpheusGfxMetalTests target_sources(MorpheusGfxMetalTests PRIVATE adapter.tests.cpp + render_system.tests.cpp video_mode.tests.cpp ) diff --git a/libraries/gfx/metal/tests/render_system.tests.cpp b/libraries/gfx/metal/tests/render_system.tests.cpp new file mode 100644 index 000000000..f4d6cbbd8 --- /dev/null +++ b/libraries/gfx/metal/tests/render_system.tests.cpp @@ -0,0 +1,13 @@ +#include + +#include + +namespace morpheus::gfx::metal +{ + +TEST_CASE("Verify the Graphics API", "[morpheus.gfx.metal.render_system.api]") +{ + STATIC_REQUIRE(RenderSystem::getGraphicsApi() == "Metal"); +} + +} // namespace morpheus::gfx::metal diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp index 1c6825dae..1c073827a 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp @@ -28,7 +28,7 @@ class RenderSystem : public gfx::RenderSystem { RenderSystem& operator=(RenderSystem&&) = default; /// Get the name of the underlying graphic API. - [[nodiscard]] static auto getGraphicsApi() noexcept -> std::string_view { return "Vulkan"; } + [[nodiscard]] static constexpr auto getGraphicsApi() noexcept -> std::string_view { return "Vulkan"; } [[nodiscard]] static auto create() -> exp_ns::expected; diff --git a/libraries/gfx/vulkan/tests/CMakeLists.txt b/libraries/gfx/vulkan/tests/CMakeLists.txt index 0f19fcf3a..a123e356e 100644 --- a/libraries/gfx/vulkan/tests/CMakeLists.txt +++ b/libraries/gfx/vulkan/tests/CMakeLists.txt @@ -7,7 +7,7 @@ target_sources(MorpheusGfxVulkanTests PRIVATE adapter.tests.cpp error_codes.tests.cpp - #render_system.tests.cpp + render_system.tests.cpp version.tests.cpp video_mode.tests.cpp ) diff --git a/libraries/gfx/vulkan/tests/render_system.tests.cpp b/libraries/gfx/vulkan/tests/render_system.tests.cpp index 32d6da161..d47b1aa10 100644 --- a/libraries/gfx/vulkan/tests/render_system.tests.cpp +++ b/libraries/gfx/vulkan/tests/render_system.tests.cpp @@ -1,14 +1,27 @@ +#include #include + #include #include #include #include +namespace morpheus::gfx::vulkan +{ + +TEST_CASE("Verify the Graphics API", "[morpheus.gfx.vulkan.render_system.api]") +{ + STATIC_REQUIRE(RenderSystem::getGraphicsApi() == "Vulkan"); +} + +} // namespace morpheus::gfx::vulkan + +/* TEST_CASE("Create a vulkan render system", "[morpheus.gfx.vulkan.render_system]") { -/* uint32_t version = 0; + uint32_t version = 0; VkResult res = vkEnumerateInstanceVersion(&version); INFO("The Vulkan version is " << VK_VERSION_MAJOR(version) <<"."<< VK_VERSION_MINOR(version) <<"."<< VK_VERSION_PATCH(version)); @@ -22,7 +35,7 @@ TEST_CASE("Create a vulkan render system", "[morpheus.gfx.vulkan.render_system]" std::vector layer_names(instance_layer_count); std::transform(layers.begin(), layers.end(), layer_names.begin(), [](const auto& element) { return element.layerName;}); std::for_each(layers.begin(), layers.end(), [](const auto& element) { INFO("Layer: " << element.layerName);}); -*/ + // for (const auto& element : layers) // { // res = vkEnumerateInstanceExtensionProperties(layer_name, &instance_extension_count, NULL); @@ -60,3 +73,4 @@ TEST_CASE("Create a vulkan render system", "[morpheus.gfx.vulkan.render_system]" // CHECK(!res); // CHECK(gpu_count > 0); } +*/ From 6a60194d05c72c0ab193617c3eb58d7cff54d823 Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Fri, 8 Aug 2025 15:34:36 +0100 Subject: [PATCH 11/29] Further formatting applied (#402) * Further formatting applied * Further formatting * Further formmatting changes * And more * Add missing coverage * Further formatting * Add test for missed deallocation after construction * Fix spelling * Add missing test coverage * Add missing functions --- .../po/adapters/std/filesystem.hpp | 2 +- .../src/morpheus/core/base/assert_handler.cpp | 12 +- .../conversion/adapters/std/filesystem.hpp | 2 +- .../morpheus/core/memory/indirect_value.hpp | 18 +- .../core/memory/polymorphic_value.hpp | 27 +- .../morpheus/core/meta/concepts/scannable.hpp | 2 +- .../morpheus/core/network/named_endpoint.hpp | 2 +- .../core/serialisation/adapters/aggregate.hpp | 2 +- .../core/serialisation/binary_writer.hpp | 6 +- .../core/serialisation/json_writer.hpp | 2 +- .../morpheus/core/serialisation/serialise.hpp | 4 +- .../morpheus/catch2/adapters/assert.hpp | 2 +- .../concepts/archetypes/associative.hpp | 15 +- .../concepts/archetypes/container.hpp | 8 +- .../concepts/archetypes/unordered.hpp | 19 +- libraries/core/tests/base/assert.tests.cpp | 2 +- libraries/core/tests/cpu.test.cpp | 5 +- libraries/core/tests/generator.tests.cpp | 17 +- .../tests/memory/indirect_value.tests.cpp | 273 ++++++++------ .../tests/memory/polymorphic_value.tests.cpp | 341 +++++++++++++----- libraries/core/tests/meta/complete.tests.cpp | 3 +- libraries/gfx/metal/examples/window/main.cpp | 4 +- .../src/morpheus/gfx/nvidia/adapter.cpp | 3 +- .../src/morpheus/gfx/platform/adapter.cpp | 2 - .../src/morpheus/gfx/platform/adapter.hpp | 6 +- .../gfx/platform/concepts/adapter.hpp | 9 +- .../gfx/platform/concepts/render_target.hpp | 3 +- .../gfx/platform/concepts/render_window.hpp | 3 +- .../gfx/platform/concepts/video_mode.hpp | 3 +- .../src/morpheus/gfx/platform/image.hpp | 11 +- .../src/morpheus/gfx/platform/monitor.hpp | 19 +- .../morpheus/gfx/platform/render_system.cpp | 1 - .../morpheus/gfx/platform/render_system.hpp | 5 +- .../morpheus/gfx/platform/render_target.hpp | 6 +- .../morpheus/gfx/platform/render_window.cpp | 14 +- .../morpheus/gfx/platform/render_window.hpp | 58 +-- .../src/morpheus/gfx/platform/video_mode.hpp | 5 +- .../morpheus/gfx/platform/x11/primitives.cpp | 16 +- .../morpheus/gfx/platform/x11/primitives.hpp | 5 +- .../platform/tests/render_window.tests.cpp | 18 +- libraries/gfx/platform/tests/vendor.tests.cpp | 2 +- .../src/morpheus/gfx/vulkan/adapter.cpp | 5 +- .../src/morpheus/gfx/vulkan/error_codes.cpp | 35 +- .../src/morpheus/gfx/vulkan/error_codes.hpp | 9 +- .../src/morpheus/gfx/vulkan/render_system.hpp | 12 +- .../src/morpheus/gfx/vulkan/version.hpp | 6 +- libraries/gfx/vulkan/tests/adapter.tests.cpp | 4 +- .../gfx/vulkan/tests/error_codes.tests.cpp | 2 +- 48 files changed, 628 insertions(+), 402 deletions(-) diff --git a/libraries/application/src/morpheus/application/po/adapters/std/filesystem.hpp b/libraries/application/src/morpheus/application/po/adapters/std/filesystem.hpp index 7302a45aa..5834e70a6 100644 --- a/libraries/application/src/morpheus/application/po/adapters/std/filesystem.hpp +++ b/libraries/application/src/morpheus/application/po/adapters/std/filesystem.hpp @@ -16,7 +16,7 @@ namespace boost /// @note /// https://github.com/boostorg/program_options/issues/69 template <> -inline std::filesystem::path lexical_cast>(const std::basic_string& arg) +inline std::filesystem::path lexical_cast>(std::basic_string const& arg) { return std::filesystem::path(arg); } diff --git a/libraries/core/src/morpheus/core/base/assert_handler.cpp b/libraries/core/src/morpheus/core/base/assert_handler.cpp index b4d0bcecd..493b5a263 100644 --- a/libraries/core/src/morpheus/core/base/assert_handler.cpp +++ b/libraries/core/src/morpheus/core/base/assert_handler.cpp @@ -31,10 +31,7 @@ AssertHandler setAssertHandler(AssertHandler handler) return gAssertHandler; } -AssertHaltHandler gAssertHaltHandler = []() -{ - breakpoint(); -}; +AssertHaltHandler gAssertHaltHandler = []() { breakpoint(); }; // LCOV_EXCL_LINE AssertHaltHandler setAssertHaltHandler(AssertHaltHandler handler) { @@ -43,7 +40,10 @@ AssertHaltHandler setAssertHaltHandler(AssertHaltHandler handler) return previousHaltHandler; } -[[nodiscard]] AssertHaltHandler const& getAssertHaltHandler() { return gAssertHaltHandler; } +[[nodiscard]] AssertHaltHandler const& getAssertHaltHandler() +{ + return gAssertHaltHandler; +} void assertHandler(AssertType type, sl_ns::source_location const location, std::string_view const expr, std::string_view message) { @@ -54,7 +54,7 @@ void assertHandler(AssertType type, sl_ns::source_location const location, std:: } else { - getAssertHandler()(Assertion{ location, expr, message }); + getAssertHandler()(Assertion{location, expr, message}); getAssertHaltHandler()(); } } diff --git a/libraries/core/src/morpheus/core/conversion/adapters/std/filesystem.hpp b/libraries/core/src/morpheus/core/conversion/adapters/std/filesystem.hpp index 25c0e0251..4b8c7add1 100644 --- a/libraries/core/src/morpheus/core/conversion/adapters/std/filesystem.hpp +++ b/libraries/core/src/morpheus/core/conversion/adapters/std/filesystem.hpp @@ -10,7 +10,7 @@ namespace boost { template <> -inline std::filesystem::path lexical_cast>(const std::basic_string& arg) +inline std::filesystem::path lexical_cast>(std::basic_string const& arg) { return std::filesystem::path(arg); } diff --git a/libraries/core/src/morpheus/core/memory/indirect_value.hpp b/libraries/core/src/morpheus/core/memory/indirect_value.hpp index eb7b57e92..13e7e485e 100644 --- a/libraries/core/src/morpheus/core/memory/indirect_value.hpp +++ b/libraries/core/src/morpheus/core/memory/indirect_value.hpp @@ -24,7 +24,7 @@ class bad_indirect_value_access : public std::exception { public: /// Message describing the error. - const char* what() const noexcept override { return "bad_indirect_value_access"; } + char const* what() const noexcept override { return "bad_indirect_value_access"; } }; namespace detail @@ -440,19 +440,19 @@ class indirect_value : public detail::indirect_value_base [[nodiscard]] constexpr T* operator->() noexcept { return this->mValue; } /// Accesses the contained value. - [[nodiscard]] constexpr const T* operator->() const noexcept { return this->mValue; } + [[nodiscard]] constexpr T const* operator->() const noexcept { return this->mValue; } /// Dereferences pointer to the managed object. [[nodiscard]] constexpr T& operator*() & noexcept { return *(this->mValue); } /// Dereferences pointer to the managed object. - [[nodiscard]] constexpr const T& operator*() const& noexcept { return *(this->mValue); } + [[nodiscard]] constexpr T const& operator*() const& noexcept { return *(this->mValue); } /// Dereferences pointer to the managed object. [[nodiscard]] constexpr T&& operator*() && noexcept { return std::move(*(this->mValue)); } /// Dereferences pointer to the managed object. - [[nodiscard]] constexpr const T&& operator*() const&& noexcept { return std::move(*(this->mValue)); } + [[nodiscard]] constexpr T const&& operator*() const&& noexcept { return std::move(*(this->mValue)); } /// If *this contains a value, returns a reference to the contained value. Otherwise, throws a bad_indirect_value_access exception. [[nodiscard]] constexpr T& value() & @@ -471,7 +471,7 @@ class indirect_value : public detail::indirect_value_base } /// If *this contains a value, returns a reference to the contained value. Otherwise, throws a bad_indirect_value_access exception. - [[nodiscard]] constexpr const T& value() const& + [[nodiscard]] constexpr T const& value() const& { if (!this->mValue) throw bad_indirect_value_access(); @@ -479,7 +479,7 @@ class indirect_value : public detail::indirect_value_base } /// If *this contains a value, returns a reference to the contained value. Otherwise, throws a bad_indirect_value_access exception. - [[nodiscard]] constexpr const T&& value() const&& + [[nodiscard]] constexpr T const&& value() const&& { if (!this->mValue) throw bad_indirect_value_access(); @@ -497,13 +497,13 @@ class indirect_value : public detail::indirect_value_base constexpr copier_type& get_copier() noexcept { return this->getC(); } /// Access the copier. - constexpr const copier_type& get_copier() const noexcept { return this->getC(); } + constexpr copier_type const& get_copier() const noexcept { return this->getC(); } /// Access the deleter. constexpr deleter_type& get_deleter() noexcept { return this->getD(); } /// Access the deleter. - constexpr const deleter_type& get_deleter() const noexcept { return this->getD(); } + constexpr deleter_type const& get_deleter() const noexcept { return this->getD(); } /// Swaps the indirectly owned objects. constexpr void swap(indirect_value& rhs) noexcept(std::is_nothrow_swappable_v) { this->base_type::swap(static_cast(rhs)); } @@ -562,7 +562,7 @@ struct std::hash<::morpheus::memory::indirect_value> /// \param key The indirect_value to compute the hash for. /// \return The hash of the underlying value, or 0 if the indirect_value is empty. /// \note noexcept if the underlying value type is noexcept hashable. - constexpr std::size_t operator()(const ::morpheus::memory::indirect_value& key) const + constexpr std::size_t operator()(::morpheus::memory::indirect_value const& key) const noexcept(noexcept(std::hash::value_type>{}(*key))) { return key ? std::hash::value_type>{}(*key) : 0; diff --git a/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp b/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp index 66695f171..8814251db 100644 --- a/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp +++ b/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp @@ -24,7 +24,7 @@ class bad_polymorphic_value_construction : public std::exception /// Ruturns an explanatory string. /// \return Return an implementation defined null terminated byte string. - constexpr const char* what() const noexcept override { return "Dynamic and static type mismatch in polymorphic_value construction"; } + constexpr char const* what() const noexcept override { return "Dynamic and static type mismatch in polymorphic_value construction"; } }; namespace detail @@ -165,7 +165,7 @@ struct allocator_wrapper : A : A(a) {} - constexpr const A& get_allocator() const { return static_cast(*this); } + constexpr A const& get_allocator() const { return static_cast(*this); } }; template @@ -190,7 +190,8 @@ class allocated_pointer_control_block : public control_block, allocator_wrapp { return detail::allocate_object(this->get_allocator(), cloned_ptr, this->get_allocator()); } - catch (...) { + catch (...) + { detail::deallocate_object(this->get_allocator(), cloned_ptr); throw; } @@ -241,7 +242,7 @@ class polymorphic_value constexpr polymorphic_value(nullptr_t) noexcept {} /// Copy construction. - constexpr polymorphic_value(const polymorphic_value& p) + constexpr polymorphic_value(polymorphic_value const& p) : mControlBlock(p.mControlBlock) , mValue((mControlBlock) ? mControlBlock->ptr() : nullptr) {} @@ -277,9 +278,10 @@ class polymorphic_value template requires std::is_convertible_v - constexpr polymorphic_value(U* u, std::allocator_arg_t, const A& alloc) + constexpr polymorphic_value(U* u, std::allocator_arg_t, A const& alloc) { - if (!u){ + if (!u) + { return; } @@ -292,14 +294,14 @@ class polymorphic_value template requires(!std::is_same_v and std::is_convertible_v) - constexpr explicit polymorphic_value(const polymorphic_value& rhs) + constexpr explicit polymorphic_value(polymorphic_value const& rhs) : mControlBlock(new detail::delegating_control_block(rhs.mControlBlock)) , mValue(mControlBlock->ptr()) {} template requires(!std::is_same_v and std::is_convertible_v) - constexpr explicit polymorphic_value(const polymorphic_value&& rhs) + constexpr explicit polymorphic_value(polymorphic_value const&& rhs) : mControlBlock(new detail::delegating_control_block(std::move(rhs.mControlBlock))) , mValue(std::move(rhs.mValue)) {} @@ -363,19 +365,19 @@ class polymorphic_value [[nodiscard]] constexpr T* operator->() noexcept { return this->mValue; } /// Accesses the contained value. - [[nodiscard]] constexpr const T* operator->() const noexcept { return this->mValue; } + [[nodiscard]] constexpr T const* operator->() const noexcept { return this->mValue; } /// Dereferences pointer to the managed object. [[nodiscard]] constexpr T& operator*() & noexcept { return *(this->mValue); } /// Dereferences pointer to the managed object. - [[nodiscard]] constexpr const T& operator*() const& noexcept { return *(this->mValue); } + [[nodiscard]] constexpr T const& operator*() const& noexcept { return *(this->mValue); } /// Dereferences pointer to the managed object. [[nodiscard]] constexpr T&& operator*() && noexcept { return std::move(*(this->mValue)); } /// Dereferences pointer to the managed object. - [[nodiscard]] constexpr const T&& operator*() const&& noexcept { return std::move(*(this->mValue)); } + [[nodiscard]] constexpr T const&& operator*() const&& noexcept { return std::move(*(this->mValue)); } #endif // (__cpp_explicit_this_parameter >= 202110) @@ -424,7 +426,8 @@ constexpr polymorphic_value allocate_polymorphic_value(std::allocator_arg_t, { p.mControlBlock = typename polymorphic_value::ControlBlock(detail::allocate_object>(a, u, a)); } - catch (...) { + catch (...) + { detail::deallocate_object(a, u); throw; } diff --git a/libraries/core/src/morpheus/core/meta/concepts/scannable.hpp b/libraries/core/src/morpheus/core/meta/concepts/scannable.hpp index 14d269a09..40c0db6f4 100644 --- a/libraries/core/src/morpheus/core/meta/concepts/scannable.hpp +++ b/libraries/core/src/morpheus/core/meta/concepts/scannable.hpp @@ -13,6 +13,6 @@ namespace morpheus::meta::concepts /// Verifies a given T is a scannable type. template concept Scannable = - detail::ScannableWith, scan_ns::basic_scan_context, CharT>>; + detail::ScannableWith, scan_ns::basic_scan_context, CharT>>; } // namespace morpheus::meta::concepts diff --git a/libraries/core/src/morpheus/core/network/named_endpoint.hpp b/libraries/core/src/morpheus/core/network/named_endpoint.hpp index 792a2431b..db3455b03 100644 --- a/libraries/core/src/morpheus/core/network/named_endpoint.hpp +++ b/libraries/core/src/morpheus/core/network/named_endpoint.hpp @@ -39,7 +39,7 @@ class NamedEndpoint /// Equality operator for NamedEndpoint. /// \param rhs The NamedEndpoint to compare against. /// \return True if the NamedEndpoint objects are equal, false otherwise. - [[nodiscard]] bool operator==(const NamedEndpoint& rhs) const noexcept { return std::tie(mName, mPort) == std::tie(rhs.mName, rhs.mPort); } + [[nodiscard]] bool operator==(NamedEndpoint const& rhs) const noexcept { return std::tie(mName, mPort) == std::tie(rhs.mName, rhs.mPort); } #endif private: diff --git a/libraries/core/src/morpheus/core/serialisation/adapters/aggregate.hpp b/libraries/core/src/morpheus/core/serialisation/adapters/aggregate.hpp index 9e712a3e0..da26b9cc4 100644 --- a/libraries/core/src/morpheus/core/serialisation/adapters/aggregate.hpp +++ b/libraries/core/src/morpheus/core/serialisation/adapters/aggregate.hpp @@ -36,7 +36,7 @@ template ::value); - boost::pfr::for_each_field(value, [&](const auto& field) { s.serialise(field); }); + boost::pfr::for_each_field(value, [&](auto const& field) { s.serialise(field); }); s.writer().endSequence(); } diff --git a/libraries/core/src/morpheus/core/serialisation/binary_writer.hpp b/libraries/core/src/morpheus/core/serialisation/binary_writer.hpp index c65828134..ff9eefc9a 100644 --- a/libraries/core/src/morpheus/core/serialisation/binary_writer.hpp +++ b/libraries/core/src/morpheus/core/serialisation/binary_writer.hpp @@ -70,7 +70,7 @@ class BinaryWriter void write(T const value) { // https://stackoverflow.com/questions/24482028/why-is-stdstreamsize-defined-as-signed-rather-than-unsigned - auto const writtenSize = static_cast(mOutStream.rdbuf()->sputn(reinterpret_cast(&value), sizeof(value))); + auto const writtenSize = static_cast(mOutStream.rdbuf()->sputn(reinterpret_cast(&value), sizeof(value))); if (writtenSize != sizeof(value)) throwBinaryException( fmt_ns::format("Error writing data to stream. Attempted to write {} bytes, but only {} bytes were written.", sizeof(value), writtenSize)); @@ -94,7 +94,7 @@ class BinaryWriter auto const length = value.size(); write(length); - auto const writtenSize = static_cast(mOutStream.rdbuf()->sputn(reinterpret_cast(value.data()), value.size())); + auto const writtenSize = static_cast(mOutStream.rdbuf()->sputn(reinterpret_cast(value.data()), value.size())); if (writtenSize != value.size()) throwBinaryException( fmt_ns::format("Error writing data to stream. Attempted to write {} bytes, but only {} bytes were written.", value.size(), writtenSize)); @@ -102,7 +102,7 @@ class BinaryWriter /// Write a string literal to the serialisation. template - void write(const char (&str)[N]) + void write(char const (&str)[N]) { write(std::string_view(str, N - 1)); } diff --git a/libraries/core/src/morpheus/core/serialisation/json_writer.hpp b/libraries/core/src/morpheus/core/serialisation/json_writer.hpp index 93beb3354..aa61745bb 100644 --- a/libraries/core/src/morpheus/core/serialisation/json_writer.hpp +++ b/libraries/core/src/morpheus/core/serialisation/json_writer.hpp @@ -86,7 +86,7 @@ class MORPHEUSCORE_EXPORT JsonWriter void write(std::span const value); /// Write a string literal to the serialisation. template - void write(const char (&str)[N]) + void write(char const (&str)[N]) { write(std::string_view(str, N - 1)); } diff --git a/libraries/core/src/morpheus/core/serialisation/serialise.hpp b/libraries/core/src/morpheus/core/serialisation/serialise.hpp index 84790038b..5c4538001 100644 --- a/libraries/core/src/morpheus/core/serialisation/serialise.hpp +++ b/libraries/core/src/morpheus/core/serialisation/serialise.hpp @@ -72,6 +72,6 @@ struct deserialise_fn namespace defaults = detail::defaults; // global customisation point objects serialisation::serialise() and serialisation::deserialise() -inline detail::serialise_fn constexpr serialise{}; -inline detail::deserialise_fn constexpr deserialise{}; +inline constexpr detail::serialise_fn serialise{}; +inline constexpr detail::deserialise_fn deserialise{}; } // namespace morpheus::serialisation diff --git a/libraries/core/testing/morpheus/catch2/adapters/assert.hpp b/libraries/core/testing/morpheus/catch2/adapters/assert.hpp index 53f98fd8b..ce980cfe4 100644 --- a/libraries/core/testing/morpheus/catch2/adapters/assert.hpp +++ b/libraries/core/testing/morpheus/catch2/adapters/assert.hpp @@ -5,7 +5,7 @@ namespace morpheus { -const AssertHandler& getPreviousHandler(); +AssertHandler const& getPreviousHandler(); /// Ensure that asserts fired in morpheus code is captured and reported through Catch2's error reporting. void enableCatch2AssertHooks(); diff --git a/libraries/core/testing/morpheus/containers/concepts/archetypes/associative.hpp b/libraries/core/testing/morpheus/containers/concepts/archetypes/associative.hpp index 10ab473ff..21fca3595 100644 --- a/libraries/core/testing/morpheus/containers/concepts/archetypes/associative.hpp +++ b/libraries/core/testing/morpheus/containers/concepts/archetypes/associative.hpp @@ -14,7 +14,7 @@ namespace morpheus::containers::concepts::archetypes namespace detail { -template +template struct Multi { struct insert_return_type {}; @@ -22,14 +22,13 @@ struct Multi constexpr auto operator<=>(Multi const&) const = default; }; -template<> +template <> struct Multi { constexpr auto operator<=>(Multi const&) const = default; }; - -template +template struct Mapped { /// The value type of the container. @@ -43,13 +42,13 @@ struct Mapped constexpr auto operator<=>(Mapped const&) const = default; }; -template<> +template <> struct Mapped { /// The mapped type of the container. using mapped_type = int; /// The value type of the container. - using value_type = std::pair; + using value_type = std::pair; /// The key type of the container. using key_type = typename value_type::first_type; /// The allocator type of the container. @@ -59,9 +58,9 @@ struct Mapped constexpr auto operator<=>(Mapped const&) const = default; }; -} // namespace morpheus::containers::concepts::archetypes::detail +} // namespace detail -template +template struct Associative : AllocatorAware, detail::Multi, detail::Mapped { /// The value type of the container. diff --git a/libraries/core/testing/morpheus/containers/concepts/archetypes/container.hpp b/libraries/core/testing/morpheus/containers/concepts/archetypes/container.hpp index ae7bf5505..bbbaf7105 100644 --- a/libraries/core/testing/morpheus/containers/concepts/archetypes/container.hpp +++ b/libraries/core/testing/morpheus/containers/concepts/archetypes/container.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include namespace morpheus::containers::concepts::archetypes @@ -9,11 +9,11 @@ namespace morpheus::containers::concepts::archetypes // Pull range access functions into scope. using std::begin; -using std::end; using std::cbegin; using std::cend; -using std::size; using std::empty; +using std::end; +using std::size; struct Container { @@ -26,7 +26,7 @@ struct Container /// The iterator type of the container. using iterator = int*; /// The const iterator type of the container. - using const_iterator = int const *; + using const_iterator = int const*; /// The difference type of the container. using difference_type = std::ptrdiff_t; /// The size type of the container. diff --git a/libraries/core/testing/morpheus/containers/concepts/archetypes/unordered.hpp b/libraries/core/testing/morpheus/containers/concepts/archetypes/unordered.hpp index 03daa9d4d..b0c1339e6 100644 --- a/libraries/core/testing/morpheus/containers/concepts/archetypes/unordered.hpp +++ b/libraries/core/testing/morpheus/containers/concepts/archetypes/unordered.hpp @@ -13,7 +13,7 @@ namespace morpheus::containers::concepts::archetypes namespace detail { -template +template struct Multi { struct insert_return_type {}; @@ -21,14 +21,13 @@ struct Multi constexpr auto operator<=>(Multi const&) const = default; }; -template<> +template <> struct Multi { constexpr auto operator<=>(Multi const&) const = default; }; - -template +template struct Mapped { /// The value type of the container. @@ -41,13 +40,13 @@ struct Mapped constexpr auto operator<=>(Mapped const&) const = default; }; -template<> +template <> struct Mapped { /// The mapped type of the container. using mapped_type = int; /// The value type of the container. - using value_type = std::pair; + using value_type = std::pair; /// The key type of the container. using key_type = typename value_type::first_type; /// The allocator type of the container. @@ -55,9 +54,9 @@ struct Mapped constexpr auto operator<=>(Mapped const&) const = default; }; -} // namespace morpheus::containers::concepts::archetypes::detail +} // namespace detail -template +template struct Unordered : public AllocatorAware, detail::Multi, detail::Mapped { /// The value type of the container. @@ -102,7 +101,7 @@ struct Unordered : public AllocatorAware, detail::Multi, detail::Mapped= 202202L) constexpr Unordered(std::from_range_t, ranges::range auto, size_type, hasher const&, key_equal const&); constexpr Unordered(std::from_range_t, ranges::range auto, size_type, hasher const&); @@ -176,8 +175,6 @@ struct Unordered : public AllocatorAware, detail::Multi, detail::Mapped(Unordered const&) const = default; - - }; } // namespace morpheus::containers::concepts::archetypes diff --git a/libraries/core/tests/base/assert.tests.cpp b/libraries/core/tests/base/assert.tests.cpp index 643c7937f..cc4212125 100644 --- a/libraries/core/tests/base/assert.tests.cpp +++ b/libraries/core/tests/base/assert.tests.cpp @@ -29,7 +29,7 @@ TEST_CASE("Ensure assert functionality works and is hooked into by the test fram }); }; - auto const onExit = [&](){ setAssertHandler(currentHandler); }; + auto const onExit = [&]() { setAssertHandler(currentHandler); }; ScopedAction const restoreAssertHandler(onEntry, onExit); RedirectStream captureOutStream(std::cout); diff --git a/libraries/core/tests/cpu.test.cpp b/libraries/core/tests/cpu.test.cpp index cacef78eb..a240d3e5f 100644 --- a/libraries/core/tests/cpu.test.cpp +++ b/libraries/core/tests/cpu.test.cpp @@ -2,13 +2,16 @@ #if (MORPHEUS_PLATFORM_ARCHITECTURE == MORPHEUS_TARGET_ARCHITECTURE_X86) || (MORPHEUS_PLATFORM_ARCHITECTURE == MORPHEUS_TARGET_ARCHITECTURE_X64) +// clang-format off #include "morpheus/core/conformance/ranges.hpp" #include "morpheus/core/cpu.hpp" -#include +#include + #include #include #include +// clang-format on namespace morpheus::test { diff --git a/libraries/core/tests/generator.tests.cpp b/libraries/core/tests/generator.tests.cpp index 5af429782..24c020963 100644 --- a/libraries/core/tests/generator.tests.cpp +++ b/libraries/core/tests/generator.tests.cpp @@ -1,6 +1,6 @@ +#include "morpheus/core/concurrency/generator.hpp" #include "morpheus/core/conformance/coro.hpp" #include "morpheus/core/conformance/ranges.hpp" -#include "morpheus/core/concurrency/generator.hpp" #include @@ -24,22 +24,23 @@ TEST_CASE("Ensure generator iterators meet required concepts", "[morpheus.concur { STATIC_REQUIRE(std::indirectly_readable::iterator>); - STATIC_REQUIRE(std::weakly_incrementable::iterator> ); - STATIC_REQUIRE(std::semiregular::iterator> ); + STATIC_REQUIRE(std::weakly_incrementable::iterator>); + STATIC_REQUIRE(std::semiregular::iterator>); STATIC_REQUIRE(ranges::range>); } - TEST_CASE("Test a simple integrer based coroutine", "[morpheus.concurrency.generator]") { - auto generateSequence = [](int start = 0, int stop = 5, int step = 1) noexcept -> Generator { - for (int i = start; i < stop; i+=step) { + auto generateSequence = [](int start = 0, int stop = 5, int step = 1) noexcept -> Generator + { + for (int i = start; i < stop; i += step) + { co_yield i; } }; - auto const expectedRange = ranges::views::iota(0, 5) | ranges::views::transform([](auto x) { return x*5; }); + auto const expectedRange = ranges::views::iota(0, 5) | ranges::views::transform([](auto x) { return x * 5; }); REQUIRE(ranges::equal(generateSequence(0, 25, 5), expectedRange)); } -} +} // namespace morpheus::concurrency diff --git a/libraries/core/tests/memory/indirect_value.tests.cpp b/libraries/core/tests/memory/indirect_value.tests.cpp index a7b536351..e8001849e 100644 --- a/libraries/core/tests/memory/indirect_value.tests.cpp +++ b/libraries/core/tests/memory/indirect_value.tests.cpp @@ -26,30 +26,30 @@ struct ProvidesThrowingHash template <> struct std::hash { - size_t operator()(const ProvidesThrowingHash&) const { return 0; } + size_t operator()(ProvidesThrowingHash const&) const { return 0; } }; namespace morpheus::memory { - - TEST_CASE("Ensure that indirect_value uses the minimum space requirements", "[morpheus.memory.indirect_value.sizeof]") { STATIC_REQUIRE(sizeof(indirect_value) == sizeof(int*)); - struct CopyDeleteHybrid { // Same type for copy and delete + struct CopyDeleteHybrid + { // Same type for copy and delete void operator()(int* p) { delete p; } - int* operator()(const int& s) { return new int(s); } + int* operator()(int const& s) { return new int(s); } }; - STATIC_REQUIRE( sizeof(indirect_value) == sizeof(int*)); + STATIC_REQUIRE(sizeof(indirect_value) == sizeof(int*)); } template -class copy_counter { +class copy_counter +{ public: - T* operator()(const T& rhs) const + T* operator()(T const& rhs) const { ++call_count; return default_copy().operator()(rhs); @@ -58,7 +58,8 @@ class copy_counter { }; template -class delete_counter { +class delete_counter +{ public: void operator()(T* rhs) const { @@ -70,7 +71,7 @@ class delete_counter { TEST_CASE("Default construction for indirect_value", "[morpheus.memory.indirect_value.constructor.default]") { - GIVEN("An indirect_value value") // The ability to track internal copies and deletes of the default constructor") + GIVEN("An indirect_value value") // The ability to track internal copies and deletes of the default constructor") { WHEN("Default-constructed") { @@ -94,17 +95,21 @@ TEST_CASE("Default construction for indirect_value", "[morpheus.memory.indirect_ } } } - GIVEN("An indirect_value value") //"The ability to track internal copies and deletes of the default constructor") + GIVEN("An indirect_value value") //"The ability to track internal copies and deletes of the default constructor") { WHEN("We create a default constructed indirect_value then copy assign it to an in-place-constructed indirect_value") { indirect_value, delete_counter> a{}; constexpr int b_value = 10; - indirect_value, delete_counter> b{std::in_place, b_value }; + indirect_value, delete_counter> b{std::in_place, b_value}; REQUIRE(a.operator->() == nullptr); REQUIRE(b.operator->() != nullptr); REQUIRE(*b == b_value); + auto const& constant_b = b; + REQUIRE(constant_b.operator->() != nullptr); + REQUIRE(*constant_b == b_value); + THEN("Ensure a copy occurs but no delete occurs") { a = b; @@ -124,18 +129,18 @@ TEST_CASE("Default construction for indirect_value", "[morpheus.memory.indirect_ } } -TEST_CASE("Element wise initialisation construction for indirect_value","[morpheus.memory.indirect_value.constructor.element_wise]") +TEST_CASE("Element wise initialisation construction for indirect_value", "[morpheus.memory.indirect_value.constructor.element_wise]") { GIVEN("The ability to track internal copies and deletes") { size_t copy_count = 0, delete_count = 0; - const auto copy_counter = [©_count](const auto& rhs) + auto const copy_counter = [©_count](auto const& rhs) { ++copy_count; return default_copy>>().operator()(rhs); }; - const auto delete_counter = [&delete_count](auto* rhs) + auto const delete_counter = [&delete_count](auto* rhs) { ++delete_count; std::default_delete>>().operator()(rhs); @@ -143,7 +148,7 @@ TEST_CASE("Element wise initialisation construction for indirect_value","[morphe WHEN("Constructing objects of indirect_value") { - indirect_value a{new int(0), copy_counter, delete_counter }; + indirect_value a{new int(0), copy_counter, delete_counter}; REQUIRE(a.operator->() != nullptr); THEN("Ensure that no copies or deleted happen in the basic construction of a value") @@ -159,7 +164,7 @@ TEST_CASE("Element wise initialisation construction for indirect_value","[morphe } } -TEST_CASE("Copy construction for indirect_value of a primitive type","[morpheus.memory.indirect_value.constructor.copy.primitive]") +TEST_CASE("Copy construction for indirect_value of a primitive type", "[morpheus.memory.indirect_value.constructor.copy.primitive]") { GIVEN("A value-initialised indirect_value value") { @@ -169,7 +174,7 @@ TEST_CASE("Copy construction for indirect_value of a primitive type","[morpheus. WHEN("Taking a copy of the value-initialised indirect_value value") { - indirect_value copy_of_a{ a }; + indirect_value copy_of_a{a}; THEN("The copy is a deep copy of the original value") { REQUIRE(*copy_of_a == a_value); @@ -236,7 +241,7 @@ TEST_CASE("Copy assignment for indirect_value of a primitive type", "[morpheus.m } } -TEST_CASE("Move construction for indirect_value of a primitive type","[morpheus.memory.indirect_value.constructor.move.primitive]") +TEST_CASE("Move construction for indirect_value of a primitive type", "[morpheus.memory.indirect_value.constructor.move.primitive]") { GIVEN("A value-initalised indirect_value value") { @@ -246,7 +251,7 @@ TEST_CASE("Move construction for indirect_value of a primitive type","[morpheus. WHEN("Constructing a new object via moving the original value") { int const* const location_of_a = a.operator->(); - indirect_value b{ std::move(a) }; + indirect_value b{std::move(a)}; THEN("The constructed object steals the contents of original value leaving it in a null state") { @@ -258,7 +263,7 @@ TEST_CASE("Move construction for indirect_value of a primitive type","[morpheus. } } -TEST_CASE("Move assignment for indirect_value of a primitive type","[morpheus.memory.indirect_value.assignment.move.primitive]") +TEST_CASE("Move assignment for indirect_value of a primitive type", "[morpheus.memory.indirect_value.assignment.move.primitive]") { GIVEN("A two value-initialised indirect_value values") { @@ -296,7 +301,7 @@ TEST_CASE("Operator bool for indirect_value", "[operator.bool]") THEN("Then when it is assigned a valid value for operator bool should return true") { constexpr int b_value = 10; - a = indirect_value{ std::in_place, b_value }; + a = indirect_value{std::in_place, b_value}; REQUIRE(a.operator->() != nullptr); REQUIRE(*a == b_value); REQUIRE(a); @@ -306,7 +311,7 @@ TEST_CASE("Operator bool for indirect_value", "[operator.bool]") GIVEN("A pointer-initialised indirect_value value") { constexpr int value_a = 7; - indirect_value a{ new int(value_a) }; + indirect_value a{new int(value_a)}; WHEN("We expect the operator bool to return true as the internal pointer owns an instance") { @@ -329,8 +334,8 @@ TEST_CASE("Swap overload for indirect_value", "[morpheus.memory.indirect_value.s { constexpr int a_value = 5; constexpr int b_value = 10; - indirect_value a{ std::in_place, a_value }; - indirect_value b{ std::in_place, b_value }; + indirect_value a{std::in_place, a_value}; + indirect_value b{std::in_place, b_value}; WHEN("The contents are swap") { @@ -350,8 +355,8 @@ TEST_CASE("Swap overload for indirect_value", "[morpheus.memory.indirect_value.s constexpr int a_value = 5; constexpr int b_value = 10; - indirect_value> a{ new int(a_value), default_copy_lambda_a }; - indirect_value> b{ new int(b_value), default_copy_lambda_b }; + indirect_value> a{new int(a_value), default_copy_lambda_a}; + indirect_value> b{new int(b_value), default_copy_lambda_b}; THEN("Confirm sized base class is used and its size requirements meet our expectations") { @@ -387,8 +392,8 @@ TEST_CASE("Swap overload for indirect_value", "[morpheus.memory.indirect_value.s } } -TEMPLATE_TEST_CASE("Noexcept of observers", "[morpheus.memory.indirect_value.noexcept]", indirect_value&, const indirect_value&, - indirect_value&&, const indirect_value&&) +TEMPLATE_TEST_CASE("Noexcept of observers", "[morpheus.memory.indirect_value.noexcept]", indirect_value&, indirect_value const&, + indirect_value&&, indirect_value const&&) { using T = TestType; STATIC_REQUIRE(noexcept(std::declval().operator->())); @@ -415,13 +420,12 @@ inline constexpr bool same_ref_qualifiers = true; template inline constexpr bool same_const_and_ref_qualifiers = same_ref_qualifiers && same_const_qualifiers; -TEMPLATE_TEST_CASE("Ref- and const-qualifier of observers", "[morpheus.memory.indirect_value.ref_constness]", - indirect_value&, const indirect_value&, - indirect_value&&, const indirect_value&&) +TEMPLATE_TEST_CASE("Ref- and const-qualifier of observers", "[morpheus.memory.indirect_value.ref_constness]", indirect_value&, indirect_value const&, + indirect_value&&, indirect_value const&&) { using T = TestType; - STATIC_REQUIRE(same_const_and_ref_qualifiers().operator*())>); + STATIC_REQUIRE(same_const_and_ref_qualifiers().operator*())>); STATIC_REQUIRE(same_const_and_ref_qualifiers().value())>); STATIC_REQUIRE(std::is_same_v().operator bool())>); STATIC_REQUIRE(std::is_same_v().has_value())>); @@ -434,10 +438,12 @@ TEST_CASE("Test properties of bad_indirect_value_access", "[morpheus.memory.indi bad_indirect_value_access ex; // check that we can throw a bad_indirect_value_access and catch // it as const std::exception&. - try { + try + { throw ex; } - catch (const std::exception& e) { + catch (std::exception const& e) + { // Use std::string_view to get the correct behavior of operator==. std::string_view what = e.what(); REQUIRE(what == ex.what()); @@ -450,9 +456,8 @@ TEST_CASE("Test properties of bad_indirect_value_access", "[morpheus.memory.indi STATIC_REQUIRE(noexcept(ex.what())); } -TEMPLATE_TEST_CASE("Calling value on empty indirect_value will throw", "[morpheus.memory.indirect_value.access]", - indirect_value&, const indirect_value&, - indirect_value&&, const indirect_value&&) +TEMPLATE_TEST_CASE("Calling value on empty indirect_value will throw", "[morpheus.memory.indirect_value.access]", indirect_value&, + indirect_value const&, indirect_value&&, indirect_value const&&) { GIVEN("An empty indirect_value") { @@ -465,9 +470,8 @@ TEMPLATE_TEST_CASE("Calling value on empty indirect_value will throw", "[morpheu } } -TEMPLATE_TEST_CASE("Calling value on an enganged indirect_value will not throw", "[morpheus.memory.indirect_value.access.no_exceptions]", - indirect_value&, const indirect_value&, - indirect_value&&, const indirect_value&&) +TEMPLATE_TEST_CASE("Calling value on an enganged indirect_value will not throw", "[morpheus.memory.indirect_value.access.no_exceptions]", indirect_value&, + indirect_value const&, indirect_value&&, indirect_value const&&) { GIVEN("An enganged indirect_value") { @@ -500,7 +504,7 @@ TEST_CASE("get_copier returns modifiable lvalue reference", "[morpheus.memory.in { iv.get_copier().name = "Modified"; REQUIRE(iv.get_copier().name == "Modified"); - SelfAssign(iv, iv); // Force invocation of copier + SelfAssign(iv, iv); // Force invocation of copier } } } @@ -528,7 +532,8 @@ TEST_CASE("get_deleter returns modifiable lvalue reference", "[morpheus.memory.i } } -struct stats { +struct stats +{ inline static int default_ctor_count = 0; inline static int copy_ctor_count = 0; inline static int move_ctor_count = 0; @@ -538,30 +543,35 @@ struct stats { inline static int delete_operator_count = 0; stats() { ++default_ctor_count; } - stats(const stats&) { ++copy_ctor_count; } + stats(stats const&) { ++copy_ctor_count; } stats(stats&&) noexcept { ++move_ctor_count; } - stats& operator=(const stats&) { + stats& operator=(stats const&) + { ++copy_assign_count; return *this; } - stats& operator=(stats&&) noexcept { + stats& operator=(stats&&) noexcept + { ++move_assign_count; return *this; } template - T* operator()(const T& t) const { + T* operator()(T const& t) const + { ++copy_operator_count; return new T(t); } template - void operator()(T* p) const { + void operator()(T* p) const + { delete p; ++delete_operator_count; } - static void reset() { + static void reset() + { default_ctor_count = 0; copy_ctor_count = 0; move_ctor_count = 0; @@ -572,17 +582,20 @@ struct stats { } }; -struct EmptyNo_FinalNo : stats { +struct EmptyNo_FinalNo : stats +{ char data{}; }; -struct EmptyNo_FinalYes final : stats { +struct EmptyNo_FinalYes final : stats +{ char data{}; }; struct EmptyYes_FinalNo : stats {}; struct EmptyYes_FinalYes final : stats {}; template -void TestCopyAndDeleteStats() { +void TestCopyAndDeleteStats() +{ using IV = indirect_value; // Tests with an empty IV @@ -592,8 +605,8 @@ void TestCopyAndDeleteStats() { IV empty; auto copyConstructFromEmpty = empty; } - REQUIRE(stats::default_ctor_count == (IsCombinedCopierAndDeleter ? 1: 2)); // Combined copier and deleters should only initialise once. - REQUIRE(stats::copy_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // Combined copier and deleters should only require one copy. + REQUIRE(stats::default_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // Combined copier and deleters should only initialise once. + REQUIRE(stats::copy_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // Combined copier and deleters should only require one copy. REQUIRE(stats::move_ctor_count == 0); REQUIRE(stats::copy_assign_count == 0); REQUIRE(stats::move_assign_count == 0); @@ -718,8 +731,8 @@ void TestCopyAndDeleteStats() { auto copyConstructFromEngaged = engaged; } REQUIRE(stats::default_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // Combined copier and deleters should only initialise once. - REQUIRE(stats::copy_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // Combined copier and deleters should only initialise once. - REQUIRE(stats::move_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // One during initial construction. + REQUIRE(stats::copy_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // Combined copier and deleters should only initialise once. + REQUIRE(stats::move_ctor_count == (IsCombinedCopierAndDeleter ? 1 : 2)); // One during initial construction. REQUIRE(stats::copy_assign_count == 0); REQUIRE(stats::move_assign_count == 0); REQUIRE(stats::copy_operator_count == 1); @@ -902,7 +915,8 @@ TEST_CASE("Protection against reentrancy", "[TODO]") { } }*/ -TEST_CASE("Self assign an indirect_value", "[TODO]") { +TEST_CASE("Self assign an indirect_value", "[TODO]") +{ { stats::reset(); indirect_value empty; @@ -929,35 +943,39 @@ TEST_CASE("Self assign an indirect_value", "[TODO]") { REQUIRE(stats::delete_operator_count == stats::copy_operator_count + 1); } -struct CopyConstructorThrows { +struct CopyConstructorThrows +{ CopyConstructorThrows() = default; - CopyConstructorThrows(const CopyConstructorThrows&) { throw 0; } + CopyConstructorThrows(CopyConstructorThrows const&) { throw 0; } int id{}; }; -struct CopyWithID : default_copy { +struct CopyWithID : default_copy +{ int id{}; }; -struct DeleteWithID : std::default_delete { +struct DeleteWithID : std::default_delete +{ int id{}; }; -TEST_CASE("Throwing copy constructor", "[TODO]") { - GIVEN("Two engaged indirect_value values") { - indirect_value iv( - std::in_place); +TEST_CASE("Throwing copy constructor", "[TODO]") +{ + GIVEN("Two engaged indirect_value values") + { + indirect_value iv(std::in_place); iv->id = 1; iv.get_copier().id = 10; iv.get_deleter().id = 100; - indirect_value other( - std::in_place); + indirect_value other(std::in_place); other->id = 2; other.get_copier().id = 20; other.get_deleter().id = 200; - THEN("A throwing copy constructor should not change the objects") { + THEN("A throwing copy constructor should not change the objects") + { REQUIRE_THROWS_AS(iv = other, int); REQUIRE(iv->id == 1); @@ -970,34 +988,38 @@ TEST_CASE("Throwing copy constructor", "[TODO]") { } } -struct CopierWithCallback { +struct CopierWithCallback +{ std::function callback; CopierWithCallback() = default; // Intentionally don't copy callback - CopierWithCallback(const CopierWithCallback&) {} - CopierWithCallback& operator=(const CopierWithCallback&) { return *this; } + CopierWithCallback(CopierWithCallback const&) {} + CopierWithCallback& operator=(CopierWithCallback const&) { return *this; } template - T* operator()(const T& t) const { + T* operator()(T const& t) const + { REQUIRE(callback); callback(); return new T(t); } }; template <> -struct copier_traits { +struct copier_traits +{ using deleter_type = std::default_delete; }; -TEST_CASE("Use source copier when copying", "[TODO]") { - GIVEN("An engaged indirect_value with CopierWithCallback") { +TEST_CASE("Use source copier when copying", "[TODO]") +{ + GIVEN("An engaged indirect_value with CopierWithCallback") + { indirect_value engagedSource(std::in_place); int copyCounter = 0; - engagedSource.get_copier().callback = [©Counter]() mutable { - ++copyCounter; - }; - THEN("Coping will call engagedSources copier") { + engagedSource.get_copier().callback = [©Counter]() mutable { ++copyCounter; }; + THEN("Coping will call engagedSources copier") + { REQUIRE(copyCounter == 0); indirect_value copy(engagedSource); REQUIRE(copyCounter == 1); @@ -1043,52 +1065,65 @@ TEST_CASE("Working with an incomplete type", "[morpheus.memory.indirect_value.co } } +namespace +{ +template +struct tracking_allocator +{ + unsigned* alloc_counter; + unsigned* dealloc_counter; -namespace { - template - struct tracking_allocator { - unsigned* alloc_counter; - unsigned* dealloc_counter; - - explicit tracking_allocator(unsigned* a, unsigned* d) noexcept - : alloc_counter(a), dealloc_counter(d) {} - - template - explicit tracking_allocator(tracking_allocator const& other) noexcept - : alloc_counter(other.alloc_counter), - dealloc_counter(other.dealloc_counter) {} + explicit tracking_allocator(unsigned* a, unsigned* d) noexcept + : alloc_counter(a) + , dealloc_counter(d) + {} - using value_type = T; + template + explicit tracking_allocator(tracking_allocator const& other) noexcept + : alloc_counter(other.alloc_counter) + , dealloc_counter(other.dealloc_counter) + {} - template - struct rebind { - using other = tracking_allocator; - }; + using value_type = T; - constexpr T* allocate(std::size_t n) { - ++* alloc_counter; - std::allocator default_allocator{}; // LCOV_EXCL_LINE - return default_allocator.allocate(n); - } - constexpr void deallocate(T* p, std::size_t n) { - ++* dealloc_counter; - std::allocator default_allocator{}; - default_allocator.deallocate(p, n); - } + template + struct rebind + { + using other = tracking_allocator; }; -} // namespace -struct CompositeType { + constexpr T* allocate(std::size_t n) + { + ++*alloc_counter; + std::allocator default_allocator{}; // LCOV_EXCL_LINE + return default_allocator.allocate(n); + } + constexpr void deallocate(T* p, std::size_t n) + { + ++*dealloc_counter; + std::allocator default_allocator{}; + default_allocator.deallocate(p, n); + } +}; +} // namespace + +struct CompositeType +{ int value_ = 0; CompositeType() { ++object_count; } - CompositeType(const CompositeType& d) { + CompositeType(CompositeType const& d) + { value_ = d.value_; ++object_count; } - CompositeType(int v) : value_(v) { ++object_count; } + CompositeType(int v) + : value_(v) + { + ++object_count; + } ~CompositeType() { --object_count; } @@ -1156,18 +1191,16 @@ struct IsHashable : std::false_type {}; template -struct IsHashable{}(std::declval()))>> : std::true_type +struct IsHashable{}(std::declval()))>> : std::true_type { - static constexpr bool IsNoexcept = noexcept(std::hash{}(std::declval())); + static constexpr bool IsNoexcept = noexcept(std::hash{}(std::declval())); }; - - TEST_CASE("std::hash customisation for indirect_value", "[morpheus.memory.indirect_value.std_hash]") { GIVEN("An empty indirect") { - const indirect_value empty; + indirect_value const empty; THEN("The hash should be zero") { @@ -1178,12 +1211,12 @@ TEST_CASE("std::hash customisation for indirect_value", "[morpheus.memory.indire GIVEN("A non-empty indirect") { - const indirect_value nonEmpty(std::in_place, 55); + indirect_value const nonEmpty(std::in_place, 55); THEN("The hash values should be equal") { - const std::size_t intHash = std::hash{}(*nonEmpty); - const std::size_t indirectValueHash = std::hash>{}(nonEmpty); + std::size_t const intHash = std::hash{}(*nonEmpty); + std::size_t const indirectValueHash = std::hash>{}(nonEmpty); REQUIRE(intHash == indirectValueHash); } } @@ -1203,4 +1236,4 @@ TEST_CASE("std::hash customisation for indirect_value", "[morpheus.memory.indire } } -} // morpheus::memory +} // namespace morpheus::memory diff --git a/libraries/core/tests/memory/polymorphic_value.tests.cpp b/libraries/core/tests/memory/polymorphic_value.tests.cpp index c7d07dcbc..3f2d7440b 100644 --- a/libraries/core/tests/memory/polymorphic_value.tests.cpp +++ b/libraries/core/tests/memory/polymorphic_value.tests.cpp @@ -21,14 +21,14 @@ struct DerivedType : BaseType DerivedType() { ++object_count; } - DerivedType(const DerivedType& d) + DerivedType(DerivedType const& d) { value_ = d.value_; ++object_count; } DerivedType(int v) - : value_(v) + : value_(v) { ++object_count; } @@ -60,14 +60,20 @@ TEST_CASE("Default constructor", "[morpheus.memory.polymorphic_value.constructor { polymorphic_value cptr; - THEN("operator bool returns false") { REQUIRE((bool)cptr == false); } + THEN("operator bool returns false") + { + REQUIRE((bool)cptr == false); + } } GIVEN("A default constructed const polymorphic_value to BaseType") { - const polymorphic_value ccptr; + polymorphic_value const ccptr; - THEN("operator bool returns false") { REQUIRE((bool)ccptr == false); } + THEN("operator bool returns false") + { + REQUIRE((bool)ccptr == false); + } } } @@ -103,32 +109,53 @@ TEST_CASE("Pointer constructor", "[polymorphic_value.constructors]") int v = 7; polymorphic_value cptr(new DerivedType(v)); - THEN("Operator-> calls the pointee method") { REQUIRE(cptr->value() == v); } + THEN("Operator-> calls the pointee method") + { + REQUIRE(cptr->value() == v); + } - THEN("operator bool returns true") { REQUIRE((bool)cptr == true); } + THEN("operator bool returns true") + { + REQUIRE((bool)cptr == true); + } } GIVEN("A pointer-constructed const polymorphic_value") { int v = 7; - const polymorphic_value ccptr(new DerivedType(v)); + polymorphic_value const ccptr(new DerivedType(v)); - THEN("Operator-> calls the pointee method") { REQUIRE(ccptr->value() == v); } + THEN("Operator-> calls the pointee method") + { + REQUIRE(ccptr->value() == v); + } - THEN("operator bool returns true") { REQUIRE((bool)ccptr == true); } + THEN("operator bool returns true") + { + REQUIRE((bool)ccptr == true); + } } GIVEN("Ensure nullptr pointer-constructed const polymorphic_value construct to be default initialised") { DerivedType* null_derived_ptr = nullptr; - const polymorphic_value ccptr(null_derived_ptr); + polymorphic_value const ccptr(null_derived_ptr); - THEN("operator bool returns true") { REQUIRE((bool)ccptr == false); } + THEN("operator bool returns true") + { + REQUIRE((bool)ccptr == false); + } } GIVEN("Ensure polymorphic supports construction from nullptr") { - const polymorphic_value ccptr(nullptr); + polymorphic_value const ccptr(nullptr); - THEN("operator bool returns true") { REQUIRE((bool)ccptr == false); } - THEN("operator bool returns true") { REQUIRE(ccptr.has_value() == false); } + THEN("operator bool returns true") + { + REQUIRE((bool)ccptr == false); + } + THEN("operator bool returns true") + { + REQUIRE(ccptr.has_value() == false); + } } } @@ -136,7 +163,7 @@ struct BaseCloneSelf { BaseCloneSelf() = default; virtual ~BaseCloneSelf() = default; - BaseCloneSelf(const BaseCloneSelf&) = delete; + BaseCloneSelf(BaseCloneSelf const&) = delete; virtual std::unique_ptr clone() const = 0; }; @@ -156,7 +183,7 @@ size_t DerivedCloneSelf::object_count = 0; struct invoke_clone_member { template - T* operator()(const T& t) const + T* operator()(T const& t) const { return static_cast(t.clone().release()); } @@ -168,12 +195,12 @@ TEST_CASE("polymorphic_value constructed with copier and deleter", "[polymorphic size_t deletion_count = 0; auto cp = polymorphic_value( new DerivedType(), - [&](const DerivedType& d) + [&](DerivedType const& d) { ++copy_count; return new DerivedType(d); }, - [&](const DerivedType* d) + [&](DerivedType const* d) { ++deletion_count; delete d; @@ -212,7 +239,10 @@ TEST_CASE("polymorphic_value copy constructor", "[polymorphic_value.constructors polymorphic_value original_cptr; polymorphic_value cptr(original_cptr); - THEN("operator bool returns false") { REQUIRE((bool)cptr == false); } + THEN("operator bool returns false") + { + REQUIRE((bool)cptr == false); + } } GIVEN("A polymorphic_value copied from a in-place-constructed " @@ -224,13 +254,25 @@ TEST_CASE("polymorphic_value copy constructor", "[polymorphic_value.constructors polymorphic_value original_cptr(std::in_place_type, v); polymorphic_value cptr(original_cptr); - THEN("values are distinct") { REQUIRE(cptr.operator->() != original_cptr.operator->()); } + THEN("values are distinct") + { + REQUIRE(cptr.operator->() != original_cptr.operator->()); + } - THEN("Operator-> calls the pointee method") { REQUIRE(cptr->value() == v); } + THEN("Operator-> calls the pointee method") + { + REQUIRE(cptr->value() == v); + } - THEN("operator bool returns true") { REQUIRE((bool)cptr == true); } + THEN("operator bool returns true") + { + REQUIRE((bool)cptr == true); + } - THEN("object count is two") { REQUIRE(DerivedType::object_count == 2); } + THEN("object count is two") + { + REQUIRE(DerivedType::object_count == 2); + } WHEN("Changes are made to the original cloning pointer after copying") { @@ -254,9 +296,15 @@ TEST_CASE("polymorphic_value move constructor", "[polymorphic_value.constructors polymorphic_value original_cptr; polymorphic_value cptr(std::move(original_cptr)); - THEN("The original polymorphic_value is empty") { REQUIRE(!(bool)original_cptr); } + THEN("The original polymorphic_value is empty") + { + REQUIRE(!(bool)original_cptr); + } - THEN("The move-constructed polymorphic_value is empty") { REQUIRE(!(bool)cptr); } + THEN("The move-constructed polymorphic_value is empty") + { + REQUIRE(!(bool)cptr); + } } GIVEN("A polymorphic_value move-constructed from a default-constructed " @@ -270,7 +318,10 @@ TEST_CASE("polymorphic_value move constructor", "[polymorphic_value.constructors polymorphic_value cptr(std::move(original_cptr)); CHECK(DerivedType::object_count == 1); - THEN("The original polymorphic_value is empty") { REQUIRE(!(bool)original_cptr); } + THEN("The original polymorphic_value is empty") + { + REQUIRE(!(bool)original_cptr); + } THEN("The move-constructed pointer is the original pointer") { @@ -279,7 +330,10 @@ TEST_CASE("polymorphic_value move constructor", "[polymorphic_value.constructors REQUIRE((bool)cptr); } - THEN("The move-constructed pointer value is the constructed value") { REQUIRE(cptr->value() == v); } + THEN("The move-constructed pointer value is the constructed value") + { + REQUIRE(cptr->value() == v); + } } } @@ -289,7 +343,7 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") "default-constructed polymorphic_value") { polymorphic_value cptr1; - const polymorphic_value cptr2; + polymorphic_value const cptr2; REQUIRE(DerivedType::object_count == 0); @@ -297,7 +351,10 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 0); - THEN("The assigned-to object is empty") { REQUIRE(!cptr1); } + THEN("The assigned-to object is empty") + { + REQUIRE(!cptr1); + } } GIVEN("A default-constructed polymorphic_value assigned to a " @@ -306,7 +363,7 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") int v1 = 7; polymorphic_value cptr1(std::in_place_type, v1); - const polymorphic_value cptr2; + polymorphic_value const cptr2; REQUIRE(DerivedType::object_count == 1); @@ -314,7 +371,10 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 0); - THEN("The assigned-to object is empty") { REQUIRE(!cptr1); } + THEN("The assigned-to object is empty") + { + REQUIRE(!cptr1); + } } GIVEN("A default-constructed polymorphic_value assigned to an " @@ -323,8 +383,8 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") int v1 = 7; polymorphic_value cptr1; - const polymorphic_value cptr2(std::in_place_type, v1); - const auto p = cptr2.operator->(); + polymorphic_value const cptr2(std::in_place_type, v1); + auto const p = cptr2.operator->(); REQUIRE(DerivedType::object_count == 1); @@ -332,11 +392,20 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 2); - THEN("The assigned-from object is unchanged") { REQUIRE(cptr2.operator->() == p); } + THEN("The assigned-from object is unchanged") + { + REQUIRE(cptr2.operator->() == p); + } - THEN("The assigned-to object is non-empty") { REQUIRE((bool)cptr1); } + THEN("The assigned-to object is non-empty") + { + REQUIRE((bool)cptr1); + } - THEN("The assigned-from object 'value' is the assigned-to object value") { REQUIRE(cptr1->value() == cptr2->value()); } + THEN("The assigned-from object 'value' is the assigned-to object value") + { + REQUIRE(cptr1->value() == cptr2->value()); + } THEN("The assigned-from object pointer and the assigned-to object pointer " "are distinct") @@ -352,8 +421,8 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") int v2 = 87; polymorphic_value cptr1(std::in_place_type, v1); - const polymorphic_value cptr2(std::in_place_type, v2); - const auto p = cptr2.operator->(); + polymorphic_value const cptr2(std::in_place_type, v2); + auto const p = cptr2.operator->(); REQUIRE(DerivedType::object_count == 2); @@ -361,11 +430,20 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 2); - THEN("The assigned-from object is unchanged") { REQUIRE(cptr2.operator->() == p); } + THEN("The assigned-from object is unchanged") + { + REQUIRE(cptr2.operator->() == p); + } - THEN("The assigned-to object is non-empty") { REQUIRE((bool)cptr1); } + THEN("The assigned-to object is non-empty") + { + REQUIRE((bool)cptr1); + } - THEN("The assigned-from object 'value' is the assigned-to object value") { REQUIRE(cptr1->value() == cptr2->value()); } + THEN("The assigned-from object 'value' is the assigned-to object value") + { + REQUIRE(cptr1->value() == cptr2->value()); + } THEN("The assigned-from object pointer and the assigned-to object pointer " "are distinct") @@ -379,7 +457,7 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") int v1 = 7; polymorphic_value cptr1(std::in_place_type, v1); - const auto p = cptr1.operator->(); + auto const p = cptr1.operator->(); REQUIRE(DerivedType::object_count == 1); @@ -396,7 +474,10 @@ TEST_CASE("polymorphic_value assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 1); - THEN("The assigned-from object is unchanged") { REQUIRE(cptr1.operator->() == p); } + THEN("The assigned-from object is unchanged") + { + REQUIRE(cptr1.operator->() == p); + } } } @@ -414,9 +495,15 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 0); - THEN("The move-assigned-from object is empty") { REQUIRE(!cptr2); } + THEN("The move-assigned-from object is empty") + { + REQUIRE(!cptr2); + } - THEN("The move-assigned-to object is empty") { REQUIRE(!cptr1); } + THEN("The move-assigned-to object is empty") + { + REQUIRE(!cptr1); + } } GIVEN("A default-constructed polymorphic_value move-assigned to a " @@ -433,9 +520,15 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 0); - THEN("The move-assigned-from object is empty") { REQUIRE(!cptr2); } + THEN("The move-assigned-from object is empty") + { + REQUIRE(!cptr2); + } - THEN("The move-assigned-to object is empty") { REQUIRE(!cptr1); } + THEN("The move-assigned-to object is empty") + { + REQUIRE(!cptr1); + } } GIVEN("A default-constructed polymorphic_value move-assigned to an " @@ -445,7 +538,7 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") polymorphic_value cptr1; polymorphic_value cptr2(std::in_place_type, v1); - const auto p = cptr2.operator->(); + auto const p = cptr2.operator->(); REQUIRE(DerivedType::object_count == 1); @@ -453,7 +546,10 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 1); - THEN("The move-assigned-from object is empty") { REQUIRE(!cptr2); } + THEN("The move-assigned-from object is empty") + { + REQUIRE(!cptr2); + } THEN("The move-assigned-to object pointer is the move-assigned-from " "pointer") @@ -470,7 +566,7 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") polymorphic_value cptr1(std::in_place_type, v1); polymorphic_value cptr2(std::in_place_type, v2); - const auto p = cptr2.operator->(); + auto const p = cptr2.operator->(); REQUIRE(DerivedType::object_count == 2); @@ -478,7 +574,10 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 1); - THEN("The move-assigned-from object is empty") { REQUIRE(!cptr2); } + THEN("The move-assigned-from object is empty") + { + REQUIRE(!cptr2); + } THEN("The move-assigned-to object pointer is the move-assigned-from " "pointer") @@ -503,7 +602,10 @@ TEST_CASE("polymorphic_value move-assignment", "[polymorphic_value.assignment]") REQUIRE(DerivedType::object_count == 1); - THEN("The move-assigned-to object is valid") { REQUIRE((bool)cptr1); } + THEN("The move-assigned-to object is valid") + { + REQUIRE((bool)cptr1); + } } } @@ -551,18 +653,30 @@ TEST_CASE("Derived types", "[polymorphic_value.derived_types]") { polymorphic_value bptr(cptr); - THEN("Operator-> calls the pointee method") { REQUIRE(bptr->value() == v); } + THEN("Operator-> calls the pointee method") + { + REQUIRE(bptr->value() == v); + } - THEN("operator bool returns true") { REQUIRE((bool)bptr == true); } + THEN("operator bool returns true") + { + REQUIRE((bool)bptr == true); + } } WHEN("A polymorphic_value is move-constructed") { polymorphic_value bptr(std::move(cptr)); - THEN("Operator-> calls the pointee method") { REQUIRE(bptr->value() == v); } + THEN("Operator-> calls the pointee method") + { + REQUIRE(bptr->value() == v); + } - THEN("operator bool returns true") { REQUIRE((bool)bptr == true); } + THEN("operator bool returns true") + { + REQUIRE((bool)bptr == true); + } } } } @@ -588,7 +702,7 @@ struct MultiplyDerived : IntermediateBaseA, IntermediateBaseB int value_ = 0; MultiplyDerived(int value) - : value_(value) + : value_(value) {} }; @@ -634,11 +748,11 @@ struct Tracked ~Tracked() { ++dtor_count_; } - Tracked(const Tracked&) { ++ctor_count_; } + Tracked(Tracked const&) { ++ctor_count_; } Tracked(Tracked&&) { ++ctor_count_; } - Tracked& operator=(const Tracked&) + Tracked& operator=(Tracked const&) { ++assignment_count_; return *this; @@ -661,25 +775,25 @@ struct ThrowsOnCopy : Tracked ThrowsOnCopy() = default; - explicit ThrowsOnCopy(const int v) - : Tracked() - , value_(v) + explicit ThrowsOnCopy(int const v) + : Tracked() + , value_(v) {} - ThrowsOnCopy(const ThrowsOnCopy& rhs) - : Tracked(rhs) + ThrowsOnCopy(ThrowsOnCopy const& rhs) + : Tracked(rhs) { throw std::runtime_error("something went wrong during copy"); } - ThrowsOnCopy& operator=(const ThrowsOnCopy& rhs) = default; + ThrowsOnCopy& operator=(ThrowsOnCopy const& rhs) = default; }; TEST_CASE("Exception safety: throw in copy constructor", "[polymorphic_value.exception_safety.copy]") { GIVEN("A value-constructed polymorphic_value to a ThrowsOnCopy") { - const int v = 7; + int const v = 7; polymorphic_value cptr(std::in_place_type, v); THEN("When copying to another polymorphic_value, after an exception, the " @@ -695,7 +809,7 @@ TEST_CASE("Exception safety: throw in copy constructor", "[polymorphic_value.exc THEN("When copying to another polymorphic_value, after an exception, the " "destination is not changed") { - const int v2 = 5; + int const v2 = 5; polymorphic_value another(std::in_place_type, v2); Tracked::reset_counts(); REQUIRE_THROWS_AS(another = cptr, std::runtime_error); @@ -710,16 +824,16 @@ struct throwing_copier { using deleter_type = std::default_delete; - T* operator()(const T&) const { throw std::bad_alloc{}; } + T* operator()(T const&) const { throw std::bad_alloc{}; } }; struct TrackedValue : Tracked { int value_ = 0; - explicit TrackedValue(const int v) - : Tracked() - , value_(v) + explicit TrackedValue(int const v) + : Tracked() + , value_(v) {} }; @@ -727,7 +841,7 @@ TEST_CASE("Exception safety: throw in copier", "[polymorphic_value.exception_saf { GIVEN("A pointer-constructed polymorphic_value") { - const int v = 7; + int const v = 7; polymorphic_value cptr(new TrackedValue(v), throwing_copier{}); THEN("When an exception occurs in the copier, the source is unchanged") @@ -742,7 +856,7 @@ TEST_CASE("Exception safety: throw in copier", "[polymorphic_value.exception_saf THEN("When an exception occurs in the copier, the destination is " "unchanged") { - const int v2 = 5; + int const v2 = 5; polymorphic_value another(std::in_place_type, v2); Tracked::reset_counts(); REQUIRE_THROWS_AS(another = cptr, std::bad_alloc); @@ -754,7 +868,7 @@ TEST_CASE("Exception safety: throw in copier", "[polymorphic_value.exception_saf TEST_CASE("polymorphic_value", "[polymorphic_value.compatible_types]") { - polymorphic_value p(std::in_place_type, 7); + polymorphic_value p(std::in_place_type, 7); REQUIRE(p->value() == 7); // Will not compile as p is polymorphic_value not // polymorphic_value @@ -772,7 +886,7 @@ class DeeplyDerivedType : public DerivedType { public: DeeplyDerivedType() - : DerivedType(0) + : DerivedType(0) {} }; @@ -789,7 +903,7 @@ TEST_CASE("polymorphic_value dynamic and static type mismatch", "[polymorphic_va struct fake_copy { template - DerivedType* operator()(const T&) const // LCOV_EXCL_LINE + DerivedType* operator()(T const&) const // LCOV_EXCL_LINE { return nullptr; } @@ -797,7 +911,7 @@ struct fake_copy struct no_deletion { - void operator()(const void*) const {} + void operator()(void const*) const {} }; TEST_CASE("polymorphic_value dynamic and static type mismatch is not a problem " @@ -831,14 +945,14 @@ struct tracking_allocator unsigned* dealloc_counter; explicit tracking_allocator(unsigned* a, unsigned* d) noexcept - : alloc_counter(a) - , dealloc_counter(d) + : alloc_counter(a) + , dealloc_counter(d) {} template - tracking_allocator(const tracking_allocator& other) - : alloc_counter(other.alloc_counter) - , dealloc_counter(other.dealloc_counter) + tracking_allocator(tracking_allocator const& other) + : alloc_counter(other.alloc_counter) + , dealloc_counter(other.dealloc_counter) {} using value_type = T; @@ -865,24 +979,57 @@ struct tracking_allocator }; } // namespace +struct UnconstructableDerivedType : DerivedType +{ + UnconstructableDerivedType() { throw std::runtime_error("Construction failed"); } + UnconstructableDerivedType(UnconstructableDerivedType const&) { throw std::runtime_error("Construction failed"); } + UnconstructableDerivedType(int value) + : DerivedType(value) + {} +}; + TEST_CASE("Allocator used to construct control block") { - unsigned allocs = 0; - unsigned deallocs = 0; + SECTION("When construction is successful") + { + unsigned allocs = 0; + unsigned deallocs = 0; - tracking_allocator alloc(&allocs, &deallocs); - std::allocator default_allocator{}; - auto mem = default_allocator.allocate(1); - const unsigned value = 42; - new (mem) DerivedType(value); + tracking_allocator alloc(&allocs, &deallocs); + std::allocator default_allocator{}; + auto mem = default_allocator.allocate(1); + unsigned const value = 42; + new (mem) DerivedType(value); - { - polymorphic_value p(mem, std::allocator_arg_t{}, alloc); + { + polymorphic_value p(mem, std::allocator_arg_t{}, alloc); + CHECK(allocs == 1); + CHECK(deallocs == 0); + } CHECK(allocs == 1); - CHECK(deallocs == 0); + CHECK(deallocs == 2); + } + SECTION("When construction fails") + { + unsigned allocs = 0; + unsigned deallocs = 0; + + tracking_allocator alloc(&allocs, &deallocs); + std::allocator default_allocator{}; + auto mem = default_allocator.allocate(1); + unsigned const value = 42; + new (mem) UnconstructableDerivedType(value); + + { + polymorphic_value p1(mem, std::allocator_arg_t{}, alloc); + CHECK(allocs == 1); + CHECK(deallocs == 0); + + REQUIRE_THROWS_AS([&p1] { auto p2(p1); }(), std::runtime_error); + } + CHECK(allocs == 2); + CHECK(deallocs == 3); } - CHECK(allocs == 1); - CHECK(deallocs == 2); } TEST_CASE("Copying object with allocator allocates") @@ -893,7 +1040,7 @@ TEST_CASE("Copying object with allocator allocates") tracking_allocator alloc(&allocs, &deallocs); std::allocator default_allocator{}; auto mem = default_allocator.allocate(1); - const unsigned value = 42; + unsigned const value = 42; new (mem) DerivedType(value); { @@ -923,4 +1070,4 @@ TEST_CASE("Allocator used to construct with allocate_polymorphic_value") CHECK(deallocs == 2); } -} // morpheus::memory +} // namespace morpheus::memory diff --git a/libraries/core/tests/meta/complete.tests.cpp b/libraries/core/tests/meta/complete.tests.cpp index d2da380dd..70bc60949 100644 --- a/libraries/core/tests/meta/complete.tests.cpp +++ b/libraries/core/tests/meta/complete.tests.cpp @@ -8,7 +8,8 @@ namespace morpheus::meta class IncompleteType; -class CompleteEmptyType {}; +class CompleteEmptyType +{}; struct CompleteType { diff --git a/libraries/gfx/metal/examples/window/main.cpp b/libraries/gfx/metal/examples/window/main.cpp index f74f8ffbb..ba4ec01e6 100644 --- a/libraries/gfx/metal/examples/window/main.cpp +++ b/libraries/gfx/metal/examples/window/main.cpp @@ -7,13 +7,13 @@ using namespace morpheus; using namespace morpheus::gfx::macos; -int main(int argc, const char * argv[]) +int main(int argc, const char* argv[]) { // NSLog (@"Window name: %@\nWidth: %ld\nHeight: %ld\nColour Depth: %ld\n", windowName, static_cast(width), static_cast(height), static_cast(colourDepth)); for (const auto& monitors : enumerateMonitors()) { fmt_ns::print("Monitor: {}\n", monitors); - std::cout.flush(); // Ensure it's not buffered + std::cout.flush(); // Ensure it's not buffered } RenderWindow::Config config; diff --git a/libraries/gfx/nvidia/src/morpheus/gfx/nvidia/adapter.cpp b/libraries/gfx/nvidia/src/morpheus/gfx/nvidia/adapter.cpp index 15b6cb81a..c2ee78d31 100644 --- a/libraries/gfx/nvidia/src/morpheus/gfx/nvidia/adapter.cpp +++ b/libraries/gfx/nvidia/src/morpheus/gfx/nvidia/adapter.cpp @@ -1,9 +1,10 @@ +#include #include #include #include -#include #include + #include namespace morpheus::gfx::nvidia::nvapi diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.cpp index 6faf05a5e..6166ff1a4 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.cpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.cpp @@ -5,8 +5,6 @@ namespace morpheus::gfx //--------------------------------------------------------------------------------------------------------------------- - - //--------------------------------------------------------------------------------------------------------------------- } // namespace morpheus::gfx diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.hpp index 1c837df2e..b34dfd1cb 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/adapter.hpp @@ -14,8 +14,9 @@ namespace morpheus::gfx /// \class Adapter /// Describes an available graphic adapter on the target platform. /// -template -class Adapter { +template +class Adapter +{ public: /// \name Life cycle ///@{ @@ -46,6 +47,7 @@ class Adapter { /// Compare two adapter objects. [[nodiscard]] constexpr auto operator<=>(Adapter const& rhs) const noexcept -> std::strong_ordering = default; + private: /// \name Data Members ///@{ diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/adapter.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/adapter.hpp index bd416cbe4..a8ac46f4a 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/adapter.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/adapter.hpp @@ -1,9 +1,9 @@ #pragma once -#include "morpheus/gfx/platform/concepts/video_mode.hpp" -#include "morpheus/gfx/platform/vendor.hpp" #include "morpheus/core/conformance/ranges.hpp" #include "morpheus/core/meta/concepts/string.hpp" +#include "morpheus/gfx/platform/concepts/video_mode.hpp" +#include "morpheus/gfx/platform/vendor.hpp" #include #include @@ -13,12 +13,11 @@ namespace morpheus::gfx::concepts /// \concept Adapter /// Adapters define the underlying graphics API abstraction of the underlying graphic hardware device. template -concept Adapter = requires(T t) -{ +concept Adapter = requires(T t) { { t.id() } -> std::equality_comparable; { t.name() } -> meta::ConvertableToStringView; { t.vendor() } -> std::same_as; -// { t.getVideoModes() } -> VideoModeRange; + // { t.getVideoModes() } -> VideoModeRange; }; template diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_target.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_target.hpp index 45254f1e4..835705a87 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_target.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_target.hpp @@ -6,8 +6,7 @@ namespace morpheus::gfx::concepts { template -concept RenderTarget = requires(T t) -{ +concept RenderTarget = requires(T t) { { t.refreshRate() } -> std::convertible_to; }; diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_window.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_window.hpp index 2508cf081..4ececb38e 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_window.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/render_window.hpp @@ -9,8 +9,7 @@ namespace morpheus::gfx::concepts /// \concept RenderWindow /// template -concept RenderWindow = requires(T t) -{ +concept RenderWindow = requires(T t) { typename T::WindowHandle; { t.width() } -> std::convertible_to; { t.height() } -> std::convertible_to; diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/video_mode.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/video_mode.hpp index e7c65d390..ef257be78 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/video_mode.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/concepts/video_mode.hpp @@ -7,8 +7,7 @@ namespace morpheus::gfx::concepts { template -concept VideoMode = requires(T t) -{ +concept VideoMode = requires(T t) { { t.width() } -> std::convertible_to; { t.height() } -> std::convertible_to; { t.colourDepth() } -> std::convertible_to; diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/image.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/image.hpp index 009670424..10d747826 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/image.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/image.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include namespace morpheus::gfx @@ -9,7 +9,8 @@ namespace morpheus::gfx /// \class Image /// The image abstracts the loading and saving of image files in CPU space. -class Image { +class Image +{ public: /// \name Life cycle ///@{ @@ -43,10 +44,10 @@ class Image { /// \name Data Members ///@{ - std::uint32_t mWidth = 0; ///< The width in pixels of the render target. - std::uint32_t mHeight = 0; ///< The height in pixels of the render target. + std::uint32_t mWidth = 0; ///< The width in pixels of the render target. + std::uint32_t mHeight = 0; ///< The height in pixels of the render target. std::uint32_t mColourDepth = 0; ///< The colour depth of the pixels of the render target. - ImageData mData; /// Buffer of raw image data. + ImageData mData; /// Buffer of raw image data. ///@} }; diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/monitor.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/monitor.hpp index e3c285918..81bd142df 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/monitor.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/monitor.hpp @@ -13,7 +13,8 @@ namespace morpheus::gfx /// \class Monitor /// Describes an available monitor on the system. /// -class Monitor { +class Monitor +{ public: using Pixels = std::uint32_t; using PixelDiff = std::int32_t; @@ -70,7 +71,7 @@ class Monitor { return std::tie(mName, mX, mY, mWidth, mHeight, mPrimary) <=> std::tie(rhs.mName, rhs.mX, rhs.mY, rhs.mWidth, rhs.mHeight, rhs.mPrimary); } - [[nodiscard]] bool operator==(const Monitor& rhs) const noexcept + [[nodiscard]] bool operator==(Monitor const& rhs) const noexcept { return std::tie(mName, mX, mY, mWidth, mHeight, mPrimary) == std::tie(rhs.mName, rhs.mX, rhs.mY, rhs.mWidth, rhs.mHeight, rhs.mPrimary); } @@ -79,11 +80,11 @@ class Monitor { private: /// \name Data Members ///@{ - std::string mName; //!< The name of the monitor - PixelDiff mX = 0; //!< Left origin of the monitor in pixels, relative to the global virtual screen coordinate space. - PixelDiff mY = 0; //!< Top origin of the monitor in pixels, relative to the global virtual screen coordinate space. - Pixels mWidth = 0; //!< The width in pixels of the screen - Pixels mHeight = 0; //!< The height in pixels of the screen + std::string mName; //!< The name of the monitor + PixelDiff mX = 0; //!< Left origin of the monitor in pixels, relative to the global virtual screen coordinate space. + PixelDiff mY = 0; //!< Top origin of the monitor in pixels, relative to the global virtual screen coordinate space. + Pixels mWidth = 0; //!< The width in pixels of the screen + Pixels mHeight = 0; //!< The height in pixels of the screen bool mPrimary = false; //!< Is this the primary monitor? ///@} }; @@ -102,7 +103,7 @@ struct morpheus::fmt_ns::formatter : morpheus::fmt_ns::f template constexpr auto format(morpheus::gfx::Monitor const& value, Context& context) const { - return morpheus::fmt_ns::format_to(context.out(), "{{name={},{{x={},y={}}},{{width={},height={}}},primary={}}}", - value.name(), value.startX(), value.startY(), value.width(), value.height(), value.primary()); + return morpheus::fmt_ns::format_to(context.out(), "{{name={},{{x={},y={}}},{{width={},height={}}},primary={}}}", value.name(), value.startX(), + value.startY(), value.width(), value.height(), value.primary()); } }; diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.cpp index a7a932bb1..ea99fad2d 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.cpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.cpp @@ -5,7 +5,6 @@ namespace morpheus::gfx //--------------------------------------------------------------------------------------------------------------------- - //--------------------------------------------------------------------------------------------------------------------- } // namespace morpheus::gfx diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.hpp index 55b34ff25..be6adb078 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/render_system.hpp @@ -10,10 +10,9 @@ namespace morpheus::gfx API and supports the creation of all graphics primitives needed to access the functionality of the hardware. */ -class RenderSystem { +class RenderSystem +{ public: - - /// \name Life cycle ///@{ /*! diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/render_target.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/render_target.hpp index 224ff5f00..45feef93c 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/render_target.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/render_target.hpp @@ -8,9 +8,9 @@ namespace morpheus::gfx /// \class RenderTarget /// A render target defined a canvas onto which a render system can draw to. /// -class RenderTarget { +class RenderTarget +{ public: - /// \name Life cycle ///@{ /*! Constructs a render target with the specified parameters. @@ -28,8 +28,6 @@ class RenderTarget { ); ///@} - - //! The width in pixels of the render target. [[nodiscard]] std::uint16_t width() const noexcept { return mWidth; } diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.cpp index 99f48a8e0..d71ef45cd 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.cpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.cpp @@ -24,17 +24,15 @@ void WindowConfig::addOptions(boost::program_options::options_description& optio // clang-format on } - //--------------------------------------------------------------------------------------------------------------------- RenderWindow::RenderWindow(Config const& config) -: RenderTarget(config.width, config.height, config.colourDepth) -, mStartX(config.startX) -, mStartY(config.startY) -, mWindowName(config.windowName) -, mFullScreen(config.fullScreen) -{ -} + : RenderTarget(config.width, config.height, config.colourDepth) + , mStartX(config.startX) + , mStartY(config.startY) + , mWindowName(config.windowName) + , mFullScreen(config.fullScreen) +{} //--------------------------------------------------------------------------------------------------------------------- diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.hpp index 513549a41..65c502bc7 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/render_window.hpp @@ -6,7 +6,10 @@ #include #include -namespace boost::program_options { class options_description; } +namespace boost::program_options +{ +class options_description; +} namespace morpheus::gfx { @@ -16,13 +19,13 @@ namespace morpheus::gfx struct WindowConfig { std::string windowName = "MorpheusWindow"; /// The name of the window. - std::uint16_t width = 800; /// The width in pixels of the render target. - std::uint16_t height = 600; /// The height in pixels of the render target. - std::uint16_t colourDepth = 32; /// The colour depth of the pixels of the render target. - std::uint16_t startX = 0; /// The starting X position in pixels of the render window. - std::uint16_t startY = 0; /// The starting Y position in pixels of the render window. - bool fullScreen = false; /// Start the window in full screen mode. - bool visible = true; /// Should the window initially be visible. + std::uint16_t width = 800; /// The width in pixels of the render target. + std::uint16_t height = 600; /// The height in pixels of the render target. + std::uint16_t colourDepth = 32; /// The colour depth of the pixels of the render target. + std::uint16_t startX = 0; /// The starting X position in pixels of the render window. + std::uint16_t startY = 0; /// The starting Y position in pixels of the render window. + bool fullScreen = false; /// Start the window in full screen mode. + bool visible = true; /// Should the window initially be visible. void addOptions(boost::program_options::options_description& options); }; @@ -31,11 +34,11 @@ struct WindowConfig /// A render window is a specialisation of a render target within the native windowing system /// of the target platform. /// -class RenderWindow : protected RenderTarget { +class RenderWindow : protected RenderTarget +{ public: using Config = WindowConfig; - /// \name Life cycle ///@{ /// Constructs a render window with the specified parameters. @@ -44,11 +47,25 @@ class RenderWindow : protected RenderTarget { explicit RenderWindow(Config const& config = Config{}); ///@} - [[nodiscard]] auto const& name() const noexcept { return mWindowName; } -// bool isHidden() const noexcept -// bool isFocus() const noexcept + //! The width in pixels of the render window. + [[nodiscard]] std::uint16_t width() const noexcept { return RenderTarget::width(); } + + //! The height in pixels of the render window. + [[nodiscard]] std::uint16_t height() const noexcept { return RenderTarget::height(); } + + //! The colour depth of the pixels of the render window. + [[nodiscard]] std::uint16_t colourDepth() const noexcept { return RenderTarget::colourDepth(); } + + //! The location of the start pixel in the X-coordinate screen space of the render window. + [[nodiscard]] std::uint16_t startX() const noexcept { return mStartX; } + + //! The location of the start pixel in the Y-coordinate screen space of the render window. + [[nodiscard]] std::uint16_t startY() const noexcept { return mStartY; } + + // bool isHidden() const noexcept + // bool isFocus() const noexcept /// Query if the window full screen. [[nodiscard]] bool fullScreen() const noexcept { return mFullScreen; } @@ -59,17 +76,16 @@ class RenderWindow : protected RenderTarget { /// Queries if the window is visible; // bool isVisible() const noexcept -// void isHidden(bool const hidden) const noexcept -// void isFocus(bool const focus) const noexcept -// void isVisible(bool const visible) const noexcept + // void isHidden(bool const hidden) const noexcept + // void isFocus(bool const focus) const noexcept + // void isVisible(bool const visible) const noexcept protected: - - std::uint16_t mStartX = 0; ///< The starting X position in pixels of the render window. - std::uint16_t mStartY = 0; ///< The starting Y position in pixels of the render window. + std::uint16_t mStartX = 0; ///< The starting X position in pixels of the render window. + std::uint16_t mStartY = 0; ///< The starting Y position in pixels of the render window. std::uint16_t mRefreshRate = 0; ///< The refresh rate of the render window. - std::string mWindowName; ///< The name of the window. - bool mFullScreen; ///< Start the window in full screen mode. + std::string mWindowName; ///< The name of the window. + bool mFullScreen; ///< Start the window in full screen mode. }; } // namespace morpheus::gfx diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/video_mode.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/video_mode.hpp index 62b90e4e0..72ce2f037 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/video_mode.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/video_mode.hpp @@ -9,7 +9,8 @@ namespace morpheus::gfx /// \class VideoMode /// A video mode describes a mode of available settings for an graphics adapter. /// -class VideoMode { +class VideoMode +{ public: /// \name Life cycle ///@{ @@ -39,7 +40,6 @@ class VideoMode { } ///@} - /// The width in pixels of the render target. [[nodiscard]] constexpr auto width() const noexcept { return mWidth; } @@ -54,6 +54,7 @@ class VideoMode { /// The three-way operator provides strong ordering of types. [[nodiscard]] constexpr auto operator<=>(VideoMode const& rhs) const noexcept -> std::strong_ordering = default; + private: /// \name Data Members ///@{ diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.cpp b/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.cpp index e1e39e997..8430ec0ad 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.cpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.cpp @@ -19,7 +19,7 @@ void XCloseDisplayDispatch::operator()(::Display* display) } XDestroyWindowDispatch::XDestroyWindowDispatch(::Display* display) noexcept -: mDisplay(display) + : mDisplay(display) {} void XDestroyWindowDispatch::operator()(typename XDestroyWindowDispatch::pointer window) @@ -41,13 +41,12 @@ void XDestroyScreenResource::operator()(typename XDestroyScreenResource::pointer } // namespace detail - - // LCOV_EXCL_START exp_ns::expected makeDisplay() { ::Display* display = XOpenDisplay(nullptr); - if (!display) { + if (!display) + { return exp_ns::unexpected("Failed to create display!"s); } return DisplayPtr(display); @@ -55,7 +54,8 @@ exp_ns::expected makeDisplay() exp_ns::expected, std::string> makeWindow(DisplayPtr&& display, WindowConfig const& config) { - if (!display) { + if (!display) + { return exp_ns::unexpected("Display pointer is null!"s); } @@ -66,7 +66,8 @@ exp_ns::expected, std::string> makeWindow(Disp 1, BlackPixel(display.get(), 0), WhitePixel(display.get(), 0) ); - if (!window) { + if (!window) + { return exp_ns::unexpected("Failed to create window!"s); } @@ -78,7 +79,8 @@ exp_ns::expected, std::string> makeWindow(Disp exp_ns::expected makeScreenResource(::Display* display, ::Window window) { ::XRRScreenResources* resources = XRRGetScreenResources(display, window); - if (!resources) { + if (!resources) + { return exp_ns::unexpected("Failed to get screen resources!"s); } diff --git a/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.hpp b/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.hpp index 5009c2179..8d779ff9e 100644 --- a/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.hpp +++ b/libraries/gfx/platform/src/morpheus/gfx/platform/x11/primitives.hpp @@ -14,7 +14,8 @@ namespace morpheus::gfx::x11 { -namespace detail { +namespace detail +{ /// \struct XCloseDisplayDispatch /// A functor to close an X11 display. @@ -32,6 +33,7 @@ struct XDestroyWindowDispatch using pointer = ::Window; void operator()(pointer window); + private: ::Display* mDisplay = nullptr; }; @@ -43,7 +45,6 @@ struct XDestroyScreenResource void operator()(pointer screenResource); }; - } // namespace detail using DisplayPtr = std::unique_ptr<::Display, detail::XCloseDisplayDispatch>; diff --git a/libraries/gfx/platform/tests/render_window.tests.cpp b/libraries/gfx/platform/tests/render_window.tests.cpp index 09b79483e..b645217ee 100644 --- a/libraries/gfx/platform/tests/render_window.tests.cpp +++ b/libraries/gfx/platform/tests/render_window.tests.cpp @@ -1,6 +1,6 @@ +#include "morpheus/gfx/platform/render_window.hpp" #include "morpheus/application/po/options.hpp" #include "morpheus/application/version.hpp" -#include "morpheus/gfx/platform/render_window.hpp" #include "morpheus/logging.hpp" #include @@ -40,4 +40,20 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of WindowConfig options", "[morph REQUIRE(config.visible == true); } +TEST_CASE_METHOD(LoggingFixture, "Test construction of a render window via a config", "[morpheus.gfx.window_config.add_options]") +{ + WindowConfig config; + RenderWindow window(config); + + REQUIRE(window.name() == "MorpheusWindow"); + REQUIRE(window.width() == 800); + REQUIRE(window.height() == 600); + REQUIRE(window.colourDepth() == 32); + REQUIRE(window.startX() == 0); + REQUIRE(window.startY() == 0); + REQUIRE(window.fullScreen() == false); +} + + + } // namespace morpheus::gfx diff --git a/libraries/gfx/platform/tests/vendor.tests.cpp b/libraries/gfx/platform/tests/vendor.tests.cpp index dacdb0365..a153d627d 100644 --- a/libraries/gfx/platform/tests/vendor.tests.cpp +++ b/libraries/gfx/platform/tests/vendor.tests.cpp @@ -21,4 +21,4 @@ TEST_CASE("Ensure image accessors", "[morpheus.gfx.vendor.vendorFromPciId]") } } -} +} // namespace morpheus::gfx diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/adapter.cpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/adapter.cpp index 8ebc8dc01..5544c314d 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/adapter.cpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/adapter.cpp @@ -6,9 +6,8 @@ namespace morpheus::gfx::vulkan { Adapter::Adapter(vk::raii::PhysicalDevice&& physicalDevice) -: mPhysicalDevice(std::move(physicalDevice)) -{ -} + : mPhysicalDevice(std::move(physicalDevice)) +{} [[nodiscard]] Vendor Adapter::vendor() const noexcept { diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.cpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.cpp index 8c968d30c..0d8c7f12c 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.cpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.cpp @@ -1,6 +1,5 @@ #include - namespace morpheus::gfx::vulkan { @@ -9,12 +8,13 @@ namespace details /*! \class vulkan_error_category Defines an error code category for Vulkan return codes to plug them into the std::error_code framework. */ -class vulkan_error_category : public std::error_category { +class vulkan_error_category : public std::error_category +{ public: /*! Queries a short form descriptive name for the category. \return Short form name of the category. */ - const char* name() const noexcept override final { return "vulkan_error_category"; } + char const* name() const noexcept override final { return "vulkan_error_category"; } /*! Queries an error string describing the error. \return The error message. @@ -66,42 +66,51 @@ class vulkan_error_category : public std::error_category { case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "The requested window is already in use by Vulkan or another API in a manner which prevents it from being used again."; case VK_ERROR_OUT_OF_DATE_KHR: - return "A surface has changed in such a way that it is no longer compatible with the swapchain, and further presentation requests using the swapchain will fail. Applications must query the new surface properties and recreate their swapchain if they wish to continue presenting to the surface."; + return "A surface has changed in such a way that it is no longer compatible with the swapchain, and further presentation requests using the " + "swapchain will fail. Applications must query the new surface properties and recreate their swapchain if they wish to continue presenting " + "to the surface."; case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "The display used by a swapchain does not use the same presentable image layout, or is incompatible in a way that prevents sharing an image"; case VK_ERROR_VALIDATION_FAILED_EXT: - return "The primary expected use of VK_ERROR_VALIDATION_FAILED_EXT is for validation layer testing. It's not expected that an application would see this this error code during normal use of the validation layers."; + return "The primary expected use of VK_ERROR_VALIDATION_FAILED_EXT is for validation layer testing. It's not expected that an application would " + "see this this error code during normal use of the validation layers."; case VK_ERROR_INVALID_SHADER_NV: return "One or more shaders failed to compile or link. More details are reported back to the application via VK_EXT_debug_report if enabled."; case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: - return "When creating an image with VkImageDrmFormatModifierExplicitCreateInfoEXT, it is the application’s responsibility to satisfy all valid usage requirements. However, the implementation must validate that the provided pPlaneLayouts, when combined with the provided drmFormatModifier and other creation parameters in VkImageCreateInfo and its pNext chain, produce a valid image."; + return "When creating an image with VkImageDrmFormatModifierExplicitCreateInfoEXT, it is the application’s responsibility to satisfy all valid " + "usage requirements. However, the implementation must validate that the provided pPlaneLayouts, when combined with the provided " + "drmFormatModifier and other creation parameters in VkImageCreateInfo and its pNext chain, produce a valid image."; case VK_ERROR_OUT_OF_POOL_MEMORY: - return "A pool memory allocation has failed. This must only be returned if no attempt to allocate host or device memory was made to accommodate the new allocation. If the failure was definitely due to fragmentation of the pool, VK_ERROR_FRAGMENTED_POOL should be returned instead."; + return "A pool memory allocation has failed. This must only be returned if no attempt to allocate host or device memory was made to accommodate " + "the new allocation. If the failure was definitely due to fragmentation of the pool, VK_ERROR_FRAGMENTED_POOL should be returned instead."; case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "An external handle is not a valid handle of the specified type."; case VK_ERROR_FRAGMENTATION_EXT: return "A descriptor pool creation has failed due to fragmentation."; case VK_ERROR_NOT_PERMITTED_EXT: - return "the driver implementation may deny requests to acquire a priority above the default priority (VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) if the caller does not have sufficient privileges. In this scenario VK_ERROR_NOT_PERMITTED_EXT is returned."; + return "the driver implementation may deny requests to acquire a priority above the default priority (VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT) if the " + "caller does not have sufficient privileges. In this scenario VK_ERROR_NOT_PERMITTED_EXT is returned."; case VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: return "A buffer creation failed because the requested address is not available."; case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: - return "An operation on a swapchain created with VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT failed as it did not have exclusive full-screen access. This may occur due to implementation-dependent reasons, outside of the application’s control."; + return "An operation on a swapchain created with VK_FULL_SCREEN_EXCLUSIVE_APPLICATION_CONTROLLED_EXT failed as it did not have exclusive " + "full-screen access. This may occur due to implementation-dependent reasons, outside of the application’s control."; default: return "unknown"; - } + } } - static const vulkan_error_category& getSingleInstance() noexcept { return mSingleInstance; } + static vulkan_error_category const& getSingleInstance() noexcept { return mSingleInstance; } + private: static vulkan_error_category mSingleInstance; }; vulkan_error_category vulkan_error_category::mSingleInstance; -} // namespace morpheus::gfx::vulkan::details +} // namespace details -const details::vulkan_error_category& vulkan_error_category() noexcept +details::vulkan_error_category const& vulkan_error_category() noexcept { return details::vulkan_error_category::getSingleInstance(); } diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp index 58e9e4b02..4de0f707a 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/error_codes.hpp @@ -6,20 +6,21 @@ namespace std { - template <> struct is_error_code_enum : true_type {}; -} +template <> +struct is_error_code_enum : true_type{}; +} // namespace std namespace morpheus::gfx::vulkan { namespace details { - class vulkan_error_category; +class vulkan_error_category; } /// Retrieve the one instance of the Vulkan error category /// \return The one instance of the Vulkan error category. -const details::vulkan_error_category& vulkan_error_category() noexcept; +details::vulkan_error_category const& vulkan_error_category() noexcept; } // namespace morpheus::gfx::vulkan diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp index 1c073827a..03c8fda7b 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/render_system.hpp @@ -17,7 +17,8 @@ namespace morpheus::gfx::vulkan /// \class RenderSystem /// Rendering system abstraction based upon the Vulkan graphics API. -class RenderSystem : public gfx::RenderSystem { +class RenderSystem : public gfx::RenderSystem +{ public: RenderSystem(std::string_view const appName, std::string_view const engineName); @@ -34,12 +35,13 @@ class RenderSystem : public gfx::RenderSystem { auto const& adapters() const { return mAdapters; } + private: - vk::raii::Context mContext; /// Vulkan context including loader. - vk::raii::Instance mInstance; /// Vulkan instance stores all per instance state. - Version mVulkanVersion; /// The instance version of Vulkan available. + vk::raii::Context mContext; /// Vulkan context including loader. + vk::raii::Instance mInstance; /// Vulkan instance stores all per instance state. + Version mVulkanVersion; /// The instance version of Vulkan available. std::vector mAvailableExtensions; /// The available Vulkan extension properties. - std::vector mAvailableLayers; /// The available Vulkan layer properties. + std::vector mAvailableLayers; /// The available Vulkan layer properties. AdapterList mAdapters; }; diff --git a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/version.hpp b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/version.hpp index 6914a1c87..dd3e11770 100644 --- a/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/version.hpp +++ b/libraries/gfx/vulkan/src/morpheus/gfx/vulkan/version.hpp @@ -3,6 +3,7 @@ #include #include + #include namespace morpheus::gfx::vulkan @@ -14,7 +15,9 @@ class Version { public: /// Construct a Vulkan version from the packed version number: - constexpr explicit Version(std::uint32_t const version) noexcept : mVersion(version) {} + constexpr explicit Version(std::uint32_t const version) noexcept + : mVersion(version) + {} /// The Vulkan API variant number. constexpr std::uint32_t variant() const noexcept { return VK_API_VERSION_VARIANT(mVersion); } @@ -34,7 +37,6 @@ class Version } // namespace morpheus::gfx::vulkan - template <> struct morpheus::fmt_ns::formatter { diff --git a/libraries/gfx/vulkan/tests/adapter.tests.cpp b/libraries/gfx/vulkan/tests/adapter.tests.cpp index 72a4147f7..ca84bf4eb 100644 --- a/libraries/gfx/vulkan/tests/adapter.tests.cpp +++ b/libraries/gfx/vulkan/tests/adapter.tests.cpp @@ -1,7 +1,7 @@ -#include -#include #include #include +#include +#include #include diff --git a/libraries/gfx/vulkan/tests/error_codes.tests.cpp b/libraries/gfx/vulkan/tests/error_codes.tests.cpp index ae379ed48..9dd06e027 100644 --- a/libraries/gfx/vulkan/tests/error_codes.tests.cpp +++ b/libraries/gfx/vulkan/tests/error_codes.tests.cpp @@ -44,7 +44,7 @@ TEST_CASE("Test construction of std::error_code object via make_error_code", "[v VK_ERROR_INVALID_DEVICE_ADDRESS_EXT, VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT, }; - for (const auto result_code : vkUniqueResults) + for (auto const result_code : vkUniqueResults) { std::error_code error_code = make_error_code(result_code); REQUIRE(error_code.value() == result_code); From 66bd30a90f48f7d949c7d6f59ca5253e2905f9cf Mon Sep 17 00:00:00 2001 From: Antony Peacock Date: Tue, 12 Aug 2025 19:19:41 +0100 Subject: [PATCH 12/29] Twon/20250808/further formatting alignment (#403) * Futher formatting * Left align macro continuations * Current formatting and clang format version * Inconsequential formatting * Further accepted formattings * Accept further formattings * Improved command line usage * Exclude clang format from yaml verification * Review fomattings * Fix include sorting * Empty struct bodies on next line * Objective C declartion formatting * No way to control the extra space clang format put in empty lambdas * One argument per line in function declartions * All args on one line else one per line * Accept formattings * Bin pack args off * Use streamlines command args interface * Accept formattings * Further formatting accepted * Objective C formatting * Update inheritance list style * Disable false positives in coverage caused by formatting * Enable clang format as a pre-commit hook --- .clang-format | 270 +++++++++++++++--- .pre-commit-config.yaml | 12 +- examples/gfx/render_triangle/main.cpp | 46 ++- .../src/morpheus/application/application.cpp | 8 +- .../src/morpheus/application/po/config.cpp | 8 +- .../src/morpheus/application/po/config.hpp | 10 +- .../tests/po/adapters/boost/asio.tests.cpp | 4 +- .../tests/po/adapters/boost/log.tests.cpp | 4 +- .../tests/po/adapters/enum.tests.cpp | 4 +- .../tests/po/adapters/scannable.tests.cpp | 4 +- .../tests/po/adapters/std/chrono.tests.cpp | 8 +- .../po/adapters/std/filesystem.tests.cpp | 5 +- .../tests/po/adapters/std/optional.tests.cpp | 4 +- .../application/tests/po/config.tests.cpp | 5 +- .../application/tests/po/options.tests.cpp | 19 +- .../src/morpheus/core/base/assert_handler.cpp | 10 +- .../src/morpheus/core/base/assert_handler.hpp | 4 +- .../core/src/morpheus/core/base/verify.hpp | 12 +- .../morpheus/core/concurrency/generator.hpp | 6 +- .../src/morpheus/core/conformance/print.hpp | 2 +- .../src/morpheus/core/conformance/version.hpp | 10 +- .../core/containers/concepts/associative.hpp | 10 +- .../core/containers/concepts/container.hpp | 4 +- .../concepts/detail/return_types.hpp | 22 +- .../core/containers/concepts/sequence.hpp | 51 ++-- .../core/containers/concepts/unordered.hpp | 19 +- .../core/conversion/adapters/std/chrono.hpp | 13 +- libraries/core/src/morpheus/core/cpu.cpp | 6 +- .../core/memory/polymorphic_value.hpp | 4 +- .../src/morpheus/core/meta/binary_search.hpp | 53 ++-- .../morpheus/core/meta/detail/scannable.hpp | 11 +- .../morpheus/core/meta/is_specialisation.hpp | 6 +- .../core/serialisation/adapters/std/tuple.hpp | 5 +- .../core/serialisation/json_reader.cpp | 6 +- .../core/serialisation/json_writer.cpp | 2 +- .../core/serialisation/json_writer.hpp | 2 + .../morpheus/catch2/adapters/assert.cpp | 11 +- .../morpheus/catch2/adapters/gmock.cpp | 23 +- .../concepts/archetypes/associative.hpp | 11 +- .../concepts/archetypes/unordered.hpp | 14 +- libraries/core/tests/base/compiler.tests.cpp | 2 +- libraries/core/tests/base/verify.tests.cpp | 13 +- .../tests/conformance/stacktrace.tests.cpp | 2 +- .../concepts/allocator_aware.tests.cpp | 15 +- .../containers/concepts/associative.tests.cpp | 15 +- .../containers/concepts/container.tests.cpp | 15 +- .../containers/concepts/contiguous.tests.cpp | 15 +- .../containers/concepts/reversible.tests.cpp | 15 +- .../containers/concepts/sequence.tests.cpp | 15 +- .../containers/concepts/unordered.tests.cpp | 15 +- .../conversion/adapters/std/chrono.tests.cpp | 2 +- libraries/core/tests/cpu.test.cpp | 22 +- .../tests/memory/indirect_value.tests.cpp | 66 +++-- .../tests/memory/polymorphic_value.tests.cpp | 4 +- libraries/core/tests/meta/aggregate.tests.cpp | 9 +- .../core/tests/meta/binary_search.tests.cpp | 141 ++++----- .../tests/meta/concepts/scannable.tests.cpp | 1 - .../tests/meta/invocable_traits.tests.cpp | 2 +- .../tests/meta/is_specialisation.tests.cpp | 7 +- libraries/core/tests/meta/is_string.tests.cpp | 2 +- libraries/core/tests/meta/satisfies.tests.cpp | 38 +-- libraries/core/tests/meta/trait.tests.cpp | 13 +- .../adapters/std/chrono.tests.cpp | 2 +- .../adapters/std/ranges.tests.cpp | 10 +- .../adapters/std/tuple.tests.cpp | 5 +- .../serialisation/binary_reader.tests.cpp | 4 +- .../serialisation/binary_roundtrip.tests.cpp | 4 +- .../serialisation/binary_writer.tests.cpp | 16 +- .../tests/serialisation/json_reader.tests.cpp | 40 ++- .../tests/serialisation/json_writer.tests.cpp | 23 +- .../serialisation/write_serialiser.tests.cpp | 2 +- .../d3d12/src/morpheus/gfx/d3d12/adapter.cpp | 40 ++- .../d3d12/src/morpheus/gfx/d3d12/adapter.hpp | 1 - .../src/morpheus/gfx/d3d12/exceptions.hpp | 2 +- .../src/morpheus/gfx/d3d12/render_system.cpp | 18 +- .../src/morpheus/gfx/d3d12/render_system.hpp | 5 +- .../src/morpheus/gfx/d3d12/type_mapping.cpp | 142 +++++---- .../src/morpheus/gfx/d3d12/type_mapping.hpp | 20 +- .../d3d12/src/morpheus/gfx/d3d12/verify.hpp | 12 +- .../src/morpheus/gfx/d3d12/video_mode.cpp | 9 +- .../src/morpheus/gfx/d3d12/video_mode.hpp | 27 +- .../morpheus/gfx/d3d12/video_mode_list.cpp | 11 +- .../morpheus/gfx/d3d12/video_mode_list.hpp | 23 +- libraries/gfx/d3d12/tests/adapter.tests.cpp | 16 +- .../gfx/d3d12/tests/video_mode_list.tests.cpp | 4 +- .../gfx/gl4/src/morpheus/gfx/gl4/platform.hpp | 8 +- .../src/morpheus/gfx/gl4/render_system.cpp | 6 +- .../src/morpheus/gfx/gl4/render_system.hpp | 4 +- .../gl4/src/morpheus/gfx/gl4/type_mapping.cpp | 13 +- .../gl4/src/morpheus/gfx/gl4/type_mapping.hpp | 12 +- .../gl4/src/morpheus/gfx/gl4/wgl/adapter.cpp | 39 +-- .../gl4/src/morpheus/gfx/gl4/wgl/context.cpp | 5 +- .../src/morpheus/gfx/gl4/wgl/video_mode.cpp | 15 +- .../gl4/src/morpheus/gfx/gl4/wgl/window.cpp | 3 +- .../gfx/gl4/tests/render_system.tests.cpp | 4 +- libraries/gfx/gl4/tests/wgl/adapter.tests.cpp | 88 +++--- .../gfx/gl4/tests/wgl/video_mode.tests.cpp | 2 +- libraries/gfx/gl4/tests/xgl/context.tests.cpp | 73 +++-- .../intel/src/morpheus/gfx/intel/adapter.cpp | 29 +- libraries/gfx/intel/tests/adapter.tests.cpp | 125 ++++---- libraries/gfx/metal/examples/window/main.cpp | 5 +- .../metal/src/morpheus/gfx/metal/adapter.cpp | 10 +- .../metal/src/morpheus/gfx/metal/adapter.hpp | 10 +- .../src/morpheus/gfx/metal/render_system.mm | 4 +- .../src/morpheus/gfx/metal/video_mode.cpp | 15 +- .../src/morpheus/gfx/metal/video_mode.hpp | 20 +- libraries/gfx/metal/tests/adapter.tests.cpp | 16 +- .../gfx/metal/tests/video_mode.tests.cpp | 6 +- .../nvidia/src/morpheus/gfx/nvidia/driver.cpp | 30 +- .../nvidia/src/morpheus/gfx/nvidia/driver.hpp | 7 +- .../src/morpheus/gfx/nvidia/functions.hpp | 264 ++++++++--------- libraries/gfx/nvidia/tests/driver.tests.cpp | 12 +- .../src/morpheus/gfx/platform/adapter.hpp | 15 +- .../gfx/platform/concepts/render_system.hpp | 11 +- .../src/morpheus/gfx/platform/image.cpp | 15 +- .../src/morpheus/gfx/platform/image.hpp | 6 +- .../gfx/platform/macos/application_delegate.h | 4 +- .../platform/macos/application_delegate.mm | 26 +- .../morpheus/gfx/platform/macos/monitor.mm | 22 +- .../gfx/platform/macos/render_window.mm | 68 +++-- .../gfx/platform/macos/window_delegate.h | 4 +- .../gfx/platform/macos/window_delegate.mm | 12 +- .../src/morpheus/gfx/platform/monitor.hpp | 33 ++- .../platform/src/morpheus/gfx/platform/os.hpp | 6 + .../src/morpheus/gfx/platform/pixel.hpp | 12 +- .../morpheus/gfx/platform/render_system.hpp | 4 +- .../morpheus/gfx/platform/render_target.cpp | 16 +- .../morpheus/gfx/platform/render_target.hpp | 6 +- .../src/morpheus/gfx/platform/video_mode.hpp | 18 +- .../src/morpheus/gfx/platform/win32/error.cpp | 46 +-- .../gfx/platform/win32/error_codes.cpp | 14 +- .../gfx/platform/win32/error_codes.hpp | 16 +- .../morpheus/gfx/platform/win32/monitor.cpp | 23 +- .../gfx/platform/win32/render_window.cpp | 239 ++++++++-------- .../gfx/platform/win32/render_window.hpp | 6 +- .../src/morpheus/gfx/platform/x11/monitor.cpp | 66 +++-- .../morpheus/gfx/platform/x11/primitives.cpp | 15 +- .../gfx/platform/x11/render_window.cpp | 25 +- .../platform/tests/render_window.tests.cpp | 8 +- .../tests/win32/render_window.tests.cpp | 52 ++-- .../src/morpheus/gfx/vulkan/adapter.cpp | 2 +- .../src/morpheus/gfx/vulkan/error_codes.hpp | 3 +- .../src/morpheus/gfx/vulkan/render_system.cpp | 35 ++- .../src/morpheus/gfx/vulkan/render_system.hpp | 1 - .../src/morpheus/gfx/vulkan/version.hpp | 4 +- libraries/gfx/vulkan/tests/adapter.tests.cpp | 6 +- .../gfx/vulkan/tests/render_system.tests.cpp | 28 +- .../morpheus/vis/render_system_factory.cpp | 64 +++-- .../morpheus/vis/render_system_factory.hpp | 7 +- .../src/morpheus/vis/visualisation.hpp | 11 +- .../tests/render_system_factory.tests.cpp | 6 +- requirements.txt | 1 + 152 files changed, 1846 insertions(+), 1528 deletions(-) diff --git a/.clang-format b/.clang-format index db78a62f4..2db6378eb 100644 --- a/.clang-format +++ b/.clang-format @@ -1,73 +1,261 @@ -# Currently configured for clang-format-15. Disabled options require a newer version. --- +Language: Cpp +BasedOnStyle: none AccessModifierOffset: -4 -#AlignConsecutiveMacros: -# Enabled: true -# AcrossEmptyLines: true -# AcrossComments: true -# AlignCompound: true -# PadOperators: true -AlignEscapedNewlines: Right -AlignOperands: Align -AlignTrailingComments: true +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +# AlignConsecutiveAssignments: +# Enabled: true +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: true +# AlignConsecutiveBitFields: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: false +# AlignConsecutiveDeclarations: +# Enabled: true +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: true +# AlignConsecutiveMacros: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCompound: false +# PadOperators: false +# AlignConsecutiveShortCaseStatements: +# Enabled: false +# AcrossEmptyLines: false +# AcrossComments: false +# AlignCaseColons: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Empty AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: false AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes +# AttributeMacros: +# - __capability +BinPackArguments: false +BinPackParameters: OnePerLine BitFieldColonSpacing: Both -BreakBeforeBraces: Custom -BreakBeforeConceptDeclarations: true BraceWrapping: - AfterEnum: true - AfterExternBlock: true - AfterClass: true - AfterFunction: true - AfterNamespace: true - AfterStruct: true - AfterUnion: true - BeforeCatch: true - BeforeElse: true + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterExternBlock: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true BeforeLambdaBody: true - BeforeWhile: true - IndentBraces: false + BeforeWhile: true + IndentBraces: false SplitEmptyFunction: false - SplitEmptyNamespace: false SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakAfterAttributes: Never +BreakAfterReturnType: Automatic +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Custom +BreakBeforeInlineASMColon: OnlyMultiline +# BreakBeforeTemplateCloser: true # Clang-21 +BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeComma -ColumnLimit: 160 -ConstructorInitializerIndentWidth: 0 +BreakInheritanceList: BeforeComma +BreakStringLiterals: true +ColumnLimit: 160 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true +# ForEachMacros: +# - foreach +# - Q_FOREACH +# - BOOST_FOREACH +# IfMacros: +# - KJ_IF_MAYBE IncludeBlocks: Preserve +IncludeCategories: + - Regex: '.*' + Priority: 0 + CaseSensitive: true +IncludeIsMainRegex: '$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: false +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true IndentPPDirectives: BeforeHash -#IndentRequiresClause: false -IndentWidth: 4 -Language: Cpp -PackConstructorInitializers: Never +IndentRequiresClause: false +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: true +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left -#RequiresClausePosition: OwnLine -SeparateDefinitionBlocks: Always +PPIndentWidth: -1 +QualifierAlignment: Custom +QualifierOrder: + - inline + - static + - constexpr + - type + - const + - volatile +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: true +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 SortIncludes: CaseSensitive +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false +# SpaceAfterOperatorKeyword: false # Clang-21 SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false SpaceBeforeParens: Custom SpaceBeforeParensOptions: AfterControlStatements: true - AfterFunctionDeclarationName: false + AfterForeachMacros: true AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true AfterOverloadedOperator: false -# AfterRequiresInClause: false -# AfterRequiresInExpression: false + AfterRequiresInClause: false + AfterRequiresInExpression: false BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: true SpaceBeforeSquareBrackets: false -SpaceBeforeCtorInitializerColon: true SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -Standard: c++20 -TabWidth: 4 -UseTab: Never +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +# SpacesInLineCommentPrefix: +# Minimum: 1 +# Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +# Standard: Auto +# StatementAttributeLikeMacros: +# - Q_EMIT +# StatementMacros: +# - Q_UNUSED +# - QT_REQUIRE_VERSION +TabWidth: 4 +UseTab: Never +# WhitespaceSensitiveMacros: +# - STRINGIZE +# - PP_STRINGIZE +# - BOOST_PP_STRINGIZE +# - NS_SWIFT_NAME +# - CF_SWIFT_NAME +#WrapNamespaceBodyWithEmptyLinesStyle: Always # Clang-20 +--- +Language: ObjC +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterExternBlock: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: true + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false +BreakBeforeBraces: Custom +IndentWidth: 4 +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 4 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PointerAlignment: Left +QualifierAlignment: Custom +QualifierOrder: + - inline + - static + - constexpr + - type + - const + - volatile ... diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 71b036528..4ee1526c5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,14 +2,22 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-yaml + exclude: ^\.clang-format$ - id: end-of-file-fixer - id: forbid-submodules - id: requirements-txt-fixer - id: trailing-whitespace + - repo: https://github.com/codespell-project/codespell - rev: v2.3.0 + rev: v2.4.1 hooks: - id: codespell + +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: v20.1.8 + hooks: + - id: clang-format + types_or: [c++, c] diff --git a/examples/gfx/render_triangle/main.cpp b/examples/gfx/render_triangle/main.cpp index 0634b01f9..d62eb9abb 100644 --- a/examples/gfx/render_triangle/main.cpp +++ b/examples/gfx/render_triangle/main.cpp @@ -16,11 +16,9 @@ class RenderTriange : public Application using Application::Application; RenderTriange(int argc, char const* const* argv) - : Application(argc, argv) - , window(std::move(win32::RenderWindow::create(win32::RenderWindow::Config{})).value()) - { - - } + : Application(argc, argv) + , window(std::move(win32::RenderWindow::create(win32::RenderWindow::Config{})).value()) + {} void Run() { @@ -50,32 +48,32 @@ class RenderTriange : public Application int main(int argc, char* argv[]) { - //const std::vector renders = { - // "Direct X 12", - // "OpenGL 4", - // "Vulkan" - //}; + // const std::vector renders = { + // "Direct X 12", + // "OpenGL 4", + // "Vulkan" + // }; - //int selectedRenders = 0; - //ftxui::Component compiler = ftxui::Radiobox(&renders, &selectedRenders); + // int selectedRenders = 0; + // ftxui::Component compiler = ftxui::Radiobox(&renders, &selectedRenders); - //auto screen = ftxui::ScreenInteractive::Fullscreen(); + // auto screen = ftxui::ScreenInteractive::Fullscreen(); ////auto testComponent = ftxui::Renderer([]() { return ftxui::text("test Component"); }); - //auto testComponent = ftxui::Renderer(compiler, [&]() { - // auto rendererWin = ftxui::window(ftxui::text("Renderer"), compiler->Render() | ftxui::vscroll_indicator | ftxui::frame); - // return rendererWin; - //}); - //screen.Loop(testComponent); + // auto testComponent = ftxui::Renderer(compiler, [&]() { + // auto rendererWin = ftxui::window(ftxui::text("Renderer"), compiler->Render() | ftxui::vscroll_indicator | ftxui::frame); + // return rendererWin; + // }); + // screen.Loop(testComponent); morpheus::vis::RenderSystemFactory factory; factory.runTuiConfiguration(); - //tryCatch( - // [&] - // { - // RenderTriange example(argc, argv); - // example.Run(); - // }); + // tryCatch( + // [&] + // { + // RenderTriange example(argc, argv); + // example.Run(); + // }); // render_system_factory renderer_factory; } diff --git a/libraries/application/src/morpheus/application/application.cpp b/libraries/application/src/morpheus/application/application.cpp index 91024c7cc..0fe1a9977 100644 --- a/libraries/application/src/morpheus/application/application.cpp +++ b/libraries/application/src/morpheus/application/application.cpp @@ -23,14 +23,15 @@ namespace /// \brief Override the default termination handler to print the call stack before exiting the program to aid debugging. void terminationHandler() { + // LCOV_EXCL_START try { debugPrint(fmt_ns::format("{}", MORPHEUS_CURRENT_STACKTRACE)); } catch (...) - { - } + {} std::abort(); + // LCOV_EXCL_STOP } /// Standardises all application logs to common log name format of --.log @@ -54,8 +55,7 @@ Application::Application(int argc, char const* const* argv) { po::Config config; if (auto invalid = parseProgramOptions(argc, argv, po::HelpDocumentation{}, config)) - { - } + {} return config; }()) //`: mLogName(getDefaultApplicationLogName()) diff --git a/libraries/application/src/morpheus/application/po/config.cpp b/libraries/application/src/morpheus/application/po/config.cpp index 91821b60e..291cde130 100644 --- a/libraries/application/src/morpheus/application/po/config.cpp +++ b/libraries/application/src/morpheus/application/po/config.cpp @@ -1,4 +1,4 @@ -#include "morpheus/application/po/adapters/boost/log.hpp" // IWYU pragma: keep +#include "morpheus/application/po/adapters/boost/log.hpp" // IWYU pragma: keep #include "morpheus/application/po/adapters/std/filesystem.hpp" // IWYU pragma: keep #include "morpheus/application/po/config.hpp" @@ -20,10 +20,8 @@ void Config::addOptions(boost::program_options::options_description& options) // ("logfile-timezone", po::value(&logFileTimeZone)->required(), "Width in pixels of the window."); // clang-format on - -// std::filesystem::path logFilePath; -// date_ns::time_zone logFileTimeZone; - + // std::filesystem::path logFilePath; + // date_ns::time_zone logFileTimeZone; } } // namespace morpheus::application::po diff --git a/libraries/application/src/morpheus/application/po/config.hpp b/libraries/application/src/morpheus/application/po/config.hpp index 8450474d7..93bc166b7 100644 --- a/libraries/application/src/morpheus/application/po/config.hpp +++ b/libraries/application/src/morpheus/application/po/config.hpp @@ -1,6 +1,6 @@ #pragma once -//#include "morpheus/core/conformance/date.hpp" +// #include "morpheus/core/conformance/date.hpp" #include @@ -8,7 +8,7 @@ namespace boost::program_options { - class options_description; +class options_description; } namespace morpheus::application::po @@ -19,12 +19,12 @@ namespace morpheus::application::po struct Config { bool loggingEnabled = true; ///< Logging is enabled. - bool logAppend = true; ///< Logging is appended if an existing file is found, otherwise it is created. + bool logAppend = true; ///< Logging is appended if an existing file is found, otherwise it is created. boost::log::trivial::severity_level logLevel = boost::log::trivial::severity_level::info; ///< The default level of log messages to allow into the log. std::filesystem::path logFilePath; ///< Name auto generated as "__".log if only a folder is given -// date_ns::time_zone loggingTimeZone; -// std::uint32_t logFileRollOverSize; // Maximum size at which the log file roles over to a new logfile. + // date_ns::time_zone loggingTimeZone; + // std::uint32_t logFileRollOverSize; // Maximum size at which the log file roles over to a new logfile. // Logfile name // Logfile timezone diff --git a/libraries/application/tests/po/adapters/boost/asio.tests.cpp b/libraries/application/tests/po/adapters/boost/asio.tests.cpp index f03fc1427..fb9f8f99a 100644 --- a/libraries/application/tests/po/adapters/boost/asio.tests.cpp +++ b/libraries/application/tests/po/adapters/boost/asio.tests.cpp @@ -49,7 +49,7 @@ TEST_CASE_METHOD(BoostLogFixture, "Test parsing of boost asio address as program { Address address{}; std::array cliOptions = {"dummyProgram.exe", "--address", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, address); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, address); REQUIRE(!result); return address.ipAddress; }; @@ -64,7 +64,7 @@ TEST_CASE_METHOD(BoostLogFixture, "Test parsing of boost asio address as program { std::array cliOptions = {"dummyProgram.exe", "--address", "invalid"}; Address address; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, address); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, address); REQUIRE(result); } } diff --git a/libraries/application/tests/po/adapters/boost/log.tests.cpp b/libraries/application/tests/po/adapters/boost/log.tests.cpp index af2ec1d0a..1ef17510d 100644 --- a/libraries/application/tests/po/adapters/boost/log.tests.cpp +++ b/libraries/application/tests/po/adapters/boost/log.tests.cpp @@ -47,7 +47,7 @@ TEST_CASE_METHOD(BoostLogFixture, "Test parsing of boost log types as program op { Logging logging{}; std::array cliOptions = {"dummyProgram.exe", "--log-level", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, logging); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, logging); REQUIRE(!result); return logging.logLevel; }; @@ -75,7 +75,7 @@ TEST_CASE_METHOD(BoostLogFixture, "Test parsing of boost log types as program op { std::array cliOptions = {"dummyProgram.exe", "--log-level", "invalid"}; Logging logging; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, logging); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, logging); REQUIRE(result); } } diff --git a/libraries/application/tests/po/adapters/enum.tests.cpp b/libraries/application/tests/po/adapters/enum.tests.cpp index e083c5efa..3547df118 100644 --- a/libraries/application/tests/po/adapters/enum.tests.cpp +++ b/libraries/application/tests/po/adapters/enum.tests.cpp @@ -45,7 +45,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of enums as options", "[morpheus. { Preferences preferences{}; std::array cliOptions = {"dummyProgram.exe", "--drink", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, preferences); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, preferences); REQUIRE(!result); return preferences.drink; }; @@ -59,7 +59,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of enums as options", "[morpheus. { std::array cliOptions = {"dummyProgram.exe", "--drink", "invalid"}; Preferences preferences{}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, preferences); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, preferences); REQUIRE(result); } } diff --git a/libraries/application/tests/po/adapters/scannable.tests.cpp b/libraries/application/tests/po/adapters/scannable.tests.cpp index 01fa73c73..b544c21a9 100644 --- a/libraries/application/tests/po/adapters/scannable.tests.cpp +++ b/libraries/application/tests/po/adapters/scannable.tests.cpp @@ -65,7 +65,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of scannable as options", "[morph { Location location{}; std::array cliOptions = {"dummyProgram.exe", "--coordinates", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, location); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, location); REQUIRE(!result); return location.coordinates; }; @@ -76,7 +76,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of scannable as options", "[morph { std::array cliOptions = {"dummyProgram.exe", "--coordinates", "invalid"}; Location location{}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, location); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, location); REQUIRE(result); } } diff --git a/libraries/application/tests/po/adapters/std/chrono.tests.cpp b/libraries/application/tests/po/adapters/std/chrono.tests.cpp index 2ccd7b367..fa35d1122 100644 --- a/libraries/application/tests/po/adapters/std/chrono.tests.cpp +++ b/libraries/application/tests/po/adapters/std/chrono.tests.cpp @@ -43,7 +43,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std chrono duration", "[morphe { ChronoDuration durationOptions{}; std::array cliOptions = {"dummyProgram.exe", "--duration", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, durationOptions); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, durationOptions); REQUIRE(!result); return durationOptions.duration; }; @@ -62,7 +62,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std chrono duration", "[morphe { std::array cliOptions = {"dummyProgram.exe", "--duration", "invalid"}; ChronoDuration durationOptions{}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, durationOptions); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, durationOptions); REQUIRE(result); } } @@ -89,7 +89,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std chrono time_zone", "[morph { TimeZone timezoneOptions{}; std::array cliOptions = {"dummyProgram.exe", "--timezone", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, timezoneOptions); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, timezoneOptions); REQUIRE(!result); return timezoneOptions.timezone; }; @@ -103,7 +103,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std chrono time_zone", "[morph { std::array cliOptions = {"dummyProgram.exe", "--timezone", "invalid"}; TimeZone timezoneOptions{}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, timezoneOptions); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, timezoneOptions); REQUIRE(result); } } diff --git a/libraries/application/tests/po/adapters/std/filesystem.tests.cpp b/libraries/application/tests/po/adapters/std/filesystem.tests.cpp index cb32a87cc..45a5c7d10 100644 --- a/libraries/application/tests/po/adapters/std/filesystem.tests.cpp +++ b/libraries/application/tests/po/adapters/std/filesystem.tests.cpp @@ -40,7 +40,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std filesystem path as options { Filesystem filesystem{}; std::array cliOptions = {"dummyProgram.exe", "--path", param.data()}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, filesystem); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, filesystem); REQUIRE(!result); return filesystem.path; }; @@ -49,7 +49,8 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std filesystem path as options REQUIRE(getPath(".") == std::filesystem::path(".")); REQUIRE(getPath("..") == std::filesystem::path("..")); REQUIRE(getPath(exeLocation.string()) == exeLocation); - REQUIRE(getPath((exeLocation / ".").lexically_normal().string()) != exeLocation); // Not the same, depends on context: https://stackoverflow.com/questions/42952605/boostfilesystempathlexically-normal-is-this-incorrect-behavior + // Not the same, depends on context: https://stackoverflow.com/questions/42952605/boostfilesystempathlexically-normal-is-this-incorrect-behavior + REQUIRE(getPath((exeLocation / ".").lexically_normal().string()) != exeLocation); if (exeLocation.has_parent_path()) REQUIRE(getPath((exeLocation / "..").lexically_normal().string()) == exeLocation.parent_path()); diff --git a/libraries/application/tests/po/adapters/std/optional.tests.cpp b/libraries/application/tests/po/adapters/std/optional.tests.cpp index 633ef3e3b..a1884e7b8 100644 --- a/libraries/application/tests/po/adapters/std/optional.tests.cpp +++ b/libraries/application/tests/po/adapters/std/optional.tests.cpp @@ -35,7 +35,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std optional wrapped type", "[ { std::array cliOptions = {"dummyProgram.exe", "--text"}; OptionalConfig options{}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, options); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, options); REQUIRE(result); REQUIRE(!options.text); } @@ -43,7 +43,7 @@ TEST_CASE_METHOD(LoggingFixture, "Test parsing of std optional wrapped type", "[ { std::array cliOptions = {"dummyProgram.exe", "--text", "valid"}; OptionalConfig options{}; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, options); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, options); REQUIRE(!result); REQUIRE(*options.text == "valid"); } diff --git a/libraries/application/tests/po/config.tests.cpp b/libraries/application/tests/po/config.tests.cpp index 08f48bad9..4c439d1e7 100644 --- a/libraries/application/tests/po/config.tests.cpp +++ b/libraries/application/tests/po/config.tests.cpp @@ -21,8 +21,9 @@ TEST_CASE("Ensure options parsing of standard application config", "[morpheus.ap WHEN("Parsing valid parameters") { - std::array const cliOptions = { "dummyProgram.exe", "--logging-enabled", "true", "--log-append", "false", "--log-level", "debug", "--logfile-path", "." }; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, config); + std::array const cliOptions = { + "dummyProgram.exe", "--logging-enabled", "true", "--log-append", "false", "--log-level", "debug", "--logfile-path", "."}; + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, config); THEN("Expect no error results and valid values extracted") { diff --git a/libraries/application/tests/po/options.tests.cpp b/libraries/application/tests/po/options.tests.cpp index eee0bbbc4..3d57eb5fd 100644 --- a/libraries/application/tests/po/options.tests.cpp +++ b/libraries/application/tests/po/options.tests.cpp @@ -50,16 +50,10 @@ auto captureOutput(ranges::contiguous_range auto const& cliOptions, HelpDocument auto const findOption = [stdOut = std::move(output)](std::string const optionText) { - auto linesView = stdOut | ranges::views::split('\n') | ranges::views::transform([](auto&& rng) { - return std::string_view(&*rng.begin(), ranges::distance(rng)); - }); + auto linesView = + stdOut | ranges::views::split('\n') | ranges::views::transform([](auto&& rng) { return std::string_view(&*rng.begin(), ranges::distance(rng)); }); - return ranges::find_if(linesView, - [optionText](auto const line) - { - return line.contains(optionText); - } - ) != linesView.end(); + return ranges::find_if(linesView, [optionText](auto const line) { return line.contains(optionText); }) != linesView.end(); }; return findOption; } @@ -72,8 +66,9 @@ TEST_CASE_METHOD(LoggingFixture, "Ensure options parsing of native types works", WHEN("Parsing valid parameters") { - std::array const cliOptions = { "dummyProgram.exe", "--first-name", "John", "--surname", "Doe", "--age", "42", "--year-of-birth", "1980", "--alive", "true" }; - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, person); + std::array const cliOptions = { + "dummyProgram.exe", "--first-name", "John", "--surname", "Doe", "--age", "42", "--year-of-birth", "1980", "--alive", "true"}; + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, person); THEN("Expect no error results and valid values extracted") { @@ -89,7 +84,7 @@ TEST_CASE_METHOD(LoggingFixture, "Ensure options parsing of native types works", { std::array const cliOptions = {"--first-name", "John", "--surname", "Doe", "--age", "42", "--year-of-birth", "1980", "--alive", "true"}; // RedirectStream captureErrors(std::cerr); Capture error logging - auto const result = parseProgramOptions(static_cast(cliOptions.size()), cliOptions.data(), HelpDocumentation{}, person); + auto const result = parseProgramOptions(cliOptions, HelpDocumentation{}, person); THEN("Expect no error results and valid values extracted") { REQUIRE(result); diff --git a/libraries/core/src/morpheus/core/base/assert_handler.cpp b/libraries/core/src/morpheus/core/base/assert_handler.cpp index 493b5a263..d206897fd 100644 --- a/libraries/core/src/morpheus/core/base/assert_handler.cpp +++ b/libraries/core/src/morpheus/core/base/assert_handler.cpp @@ -13,10 +13,16 @@ namespace morpheus AssertHandler gAssertHandler = [](Assertion assertion) { - auto const debugMessage = fmt_ns::format("{}({}): assertion[{}]: {}\nBacktrace:{}\n", assertion.location.file_name(), assertion.location.line(), - assertion.expression, assertion.message, MORPHEUS_CURRENT_STACKTRACE); + // LCOV_EXCL_START + auto const debugMessage = fmt_ns::format("{}({}): assertion[{}]: {}\nBacktrace:{}\n", + assertion.location.file_name(), + assertion.location.line(), + assertion.expression, + assertion.message, + MORPHEUS_CURRENT_STACKTRACE); debugPrint(debugMessage); return true; + // LCOV_EXCL_STOP }; AssertHandler setAssertHandler(AssertHandler handler) diff --git a/libraries/core/src/morpheus/core/base/assert_handler.hpp b/libraries/core/src/morpheus/core/base/assert_handler.hpp index 505978b43..b0a7ddb42 100644 --- a/libraries/core/src/morpheus/core/base/assert_handler.hpp +++ b/libraries/core/src/morpheus/core/base/assert_handler.hpp @@ -57,7 +57,7 @@ enum class MORPHEUSCORE_EXPORT AssertType /// \param[in] location The source file location where the assert originated. /// \param[in] expr String representation of the condition. /// \param[in] message An optional message describing the assert. -MORPHEUSCORE_EXPORT void assertHandler(AssertType type, sl_ns::source_location const location, std::string_view const expr, - std::string_view message = std::string_view()); +MORPHEUSCORE_EXPORT void +assertHandler(AssertType type, sl_ns::source_location const location, std::string_view const expr, std::string_view message = std::string_view()); } // namespace morpheus diff --git a/libraries/core/src/morpheus/core/base/verify.hpp b/libraries/core/src/morpheus/core/base/verify.hpp index 8123c7a80..81e3a6e42 100644 --- a/libraries/core/src/morpheus/core/base/verify.hpp +++ b/libraries/core/src/morpheus/core/base/verify.hpp @@ -2,12 +2,12 @@ #include -#define MORPHEUS_VERIFY_HANDLER(type, expr, msg) \ - do \ - { \ - if ((!static_cast(expr))) [[unlikely]] \ - assertHandler(type, MORPHEUS_CURRENT_LOCATION, #expr, msg); \ - } \ +#define MORPHEUS_VERIFY_HANDLER(type, expr, msg) \ + do \ + { \ + if ((!static_cast(expr))) [[unlikely]] \ + assertHandler(type, MORPHEUS_CURRENT_LOCATION, #expr, msg); \ + } \ while (0) /// \def MORPHEUS_VERIFY diff --git a/libraries/core/src/morpheus/core/concurrency/generator.hpp b/libraries/core/src/morpheus/core/concurrency/generator.hpp index cf717681c..d96f3e48c 100644 --- a/libraries/core/src/morpheus/core/concurrency/generator.hpp +++ b/libraries/core/src/morpheus/core/concurrency/generator.hpp @@ -24,7 +24,7 @@ struct Generator struct promise_type; using handle_type = coro_ns::coroutine_handle; ///< Handle to generator coroutines. using value_type = T; ///< Value type from resulting generation. - using reference = std::conditional_t, T, const value_type&>; ///< Reference type to the value type. + using reference = std::conditional_t, T, value_type const&>; ///< Reference type to the value type. using pointer = std::add_pointer_t; ///< Pointer type to the value type. Generator(handle_type h) @@ -38,8 +38,8 @@ struct Generator coro.destroy(); } - Generator(const Generator&) = delete; - Generator& operator=(const Generator&) = delete; + Generator(Generator const&) = delete; + Generator& operator=(Generator const&) = delete; Generator(Generator&& rhs) noexcept : coro(std::exchange(rhs.coro, {})) diff --git a/libraries/core/src/morpheus/core/conformance/print.hpp b/libraries/core/src/morpheus/core/conformance/print.hpp index fb9cf5867..c8b1cf57a 100644 --- a/libraries/core/src/morpheus/core/conformance/print.hpp +++ b/libraries/core/src/morpheus/core/conformance/print.hpp @@ -2,11 +2,11 @@ #include +// clang-format off #if __has_include() #include // IWYU pragma: export #endif // #if __has_include() -// clang-format off #if (__cpp_lib_print >= 202207L && (__cpp_lib_format >= 201907L)) // Clang 18 support for std::print but has a incomplete implementation of std::format, just use FMT in this case. namespace morpheus { namespace print_ns = std; } #else diff --git a/libraries/core/src/morpheus/core/conformance/version.hpp b/libraries/core/src/morpheus/core/conformance/version.hpp index d8d3d64bb..c05df6a0b 100644 --- a/libraries/core/src/morpheus/core/conformance/version.hpp +++ b/libraries/core/src/morpheus/core/conformance/version.hpp @@ -10,8 +10,8 @@ /// \note /// #include on Windows can accidentally picks up VERSION files. Use the old /// instead. For details see: https://bugs.llvm.org/show_bug.cgi?id=42540 -//#if __has_include() && (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_PC_WINDOWS) - #include // IWYU pragma: export -//#else -// #include -//#endif +// #if __has_include() && (MORPHEUS_BUILD_PLATFORM == MORPHEUS_TARGET_PLATFORM_PC_WINDOWS) +#include // IWYU pragma: export +// #else +// #include +// #endif diff --git a/libraries/core/src/morpheus/core/containers/concepts/associative.hpp b/libraries/core/src/morpheus/core/containers/concepts/associative.hpp index a0ef80489..561b2cc34 100644 --- a/libraries/core/src/morpheus/core/containers/concepts/associative.hpp +++ b/libraries/core/src/morpheus/core/containers/concepts/associative.hpp @@ -14,8 +14,14 @@ namespace morpheus::containers::concepts /// [associative.reqmts], details at /// AssociativeContainer. template -concept Associative = AllocatorAware && requires(T t, typename T::value_type v, typename T::key_type k, typename T::size_type s, typename T::iterator i, - typename T::const_iterator ci, typename T::key_compare c, typename T::node_type n, +concept Associative = AllocatorAware && requires(T t, + typename T::value_type v, + typename T::key_type k, + typename T::size_type s, + typename T::iterator i, + typename T::const_iterator ci, + typename T::key_compare c, + typename T::node_type n, std::initializer_list il) { requires(std::default_initializable) and (std::copy_constructible); { T(c) }; diff --git a/libraries/core/src/morpheus/core/containers/concepts/container.hpp b/libraries/core/src/morpheus/core/containers/concepts/container.hpp index 460108014..61c83ee90 100644 --- a/libraries/core/src/morpheus/core/containers/concepts/container.hpp +++ b/libraries/core/src/morpheus/core/containers/concepts/container.hpp @@ -26,7 +26,9 @@ concept Container = requires(C c) { { end(c) } -> std::same_as; { cbegin(std::as_const(c)) } -> std::same_as; { cend(std::as_const(c)) } -> std::same_as; - requires (not std::bidirectional_iterator) or requires {{ size(c) } -> std::same_as; }; + requires(not std::bidirectional_iterator) or requires { + { size(c) } -> std::same_as; + }; { c.max_size() } -> std::same_as; { empty(c) } -> std::same_as; }; diff --git a/libraries/core/src/morpheus/core/containers/concepts/detail/return_types.hpp b/libraries/core/src/morpheus/core/containers/concepts/detail/return_types.hpp index 844ab8eed..d2d65c90d 100644 --- a/libraries/core/src/morpheus/core/containers/concepts/detail/return_types.hpp +++ b/libraries/core/src/morpheus/core/containers/concepts/detail/return_types.hpp @@ -7,27 +7,19 @@ namespace morpheus::containers::concepts::detail { template -concept InsertReturnType = requires -{ - requires std::same_as or std::same_as>; -}; +concept InsertReturnType = requires { requires std::same_as or std::same_as>; }; template -concept InsertNodeHandleReturnType = requires -{ +concept InsertNodeHandleReturnType = requires { requires requires { requires std::same_as; } or requires { requires std::same_as; }; }; template -concept BoundReturnType = requires -{ - requires std::same_as or std::same_as>; -}; +concept BoundReturnType = + requires { requires std::same_as or std::same_as>; }; template -concept BoundConstReturnType = requires -{ - requires std::same_as or std::same_as>; -}; +concept BoundConstReturnType = + requires { requires std::same_as or std::same_as>; }; -} // namespace morpheus::containers::concepts +} // namespace morpheus::containers::concepts::detail diff --git a/libraries/core/src/morpheus/core/containers/concepts/sequence.hpp b/libraries/core/src/morpheus/core/containers/concepts/sequence.hpp index fb4b1d746..e3f46b45c 100644 --- a/libraries/core/src/morpheus/core/containers/concepts/sequence.hpp +++ b/libraries/core/src/morpheus/core/containers/concepts/sequence.hpp @@ -1,13 +1,13 @@ #pragma once -#include "morpheus/core/containers/concepts/container.hpp" #include "morpheus/core/conformance/ranges.hpp" +#include "morpheus/core/containers/concepts/container.hpp" #include "morpheus/core/meta/is_array.hpp" #include "morpheus/core/meta/is_string.hpp" #include -#include #include +#include #include #include @@ -19,32 +19,33 @@ namespace morpheus::containers::concepts /// [sequence.requirements], details at /// SequenceContainer. template -concept Sequence = Container && requires(T t, typename T::value_type v, typename T::size_type s, typename T::iterator i, std::initializer_list il){ - { T(s, v) }; - { T(i, i) }; +concept Sequence = + Container && requires(T t, typename T::value_type v, typename T::size_type s, typename T::iterator i, std::initializer_list il) { + { T(s, v) }; + { T(i, i) }; #if (__cpp_lib_containers_ranges >= 202202L) - { T(std::from_range, ranges::subrange{}) }; + { T(std::from_range, ranges::subrange{}) }; #endif // (__cpp_lib_containers_ranges >= 202202L) - { T(il) }; - { t = il }; - { t.insert(i, v) } -> std::same_as; - { t.insert(i, std::move(v)) } -> std::same_as; - { t.insert(i, s, v) } -> std::same_as; - { t.insert(i, i, i) } -> std::same_as; + { T(il) }; + { t = il }; + { t.insert(i, v) } -> std::same_as; + { t.insert(i, std::move(v)) } -> std::same_as; + { t.insert(i, s, v) } -> std::same_as; + { t.insert(i, i, i) } -> std::same_as; #if (__cpp_lib_containers_ranges >= 202202L) - { t.insert_range(i, ranges::subrange{}) } -> std::same_as; + { t.insert_range(i, ranges::subrange{}) } -> std::same_as; #endif // (__cpp_lib_containers_ranges >= 202202L) - { t.insert(i, il) } -> std::same_as; - { t.erase(i) } -> std::same_as; - { t.erase(i, i) } -> std::same_as; - { t.clear() } -> std::same_as; - { t.assign(i, i) } -> std::same_as; + { t.insert(i, il) } -> std::same_as; + { t.erase(i) } -> std::same_as; + { t.erase(i, i) } -> std::same_as; + { t.clear() } -> std::same_as; + { t.assign(i, i) } -> std::same_as; #if (__cpp_lib_containers_ranges >= 202202L) - { t.assign_range(ranges::subrange{}) } -> std::same_as; + { t.assign_range(ranges::subrange{}) } -> std::same_as; #endif // (__cpp_lib_containers_ranges >= 202202L) - { t.assign(il) } -> std::same_as; - { t.assign(s, v) } -> std::same_as; -}; + { t.assign(il) } -> std::same_as; + { t.assign(s, v) } -> std::same_as; + }; /// \concept StrictSequence /// Concept strictly capturing the requirements for a sequence container as outline in the standard at @@ -58,10 +59,6 @@ concept Sequence = Container && requires(T t, typename T::value_type v, typen /// However they are listed as as Sequence types while having interfaces that differ from the Sequence /// container requirements so this extension concept exactly mirrors that requirement. template -concept StrictSequence = meta::is_array_v || - meta::is_string_v || - std::same_as> || - Sequence; - +concept StrictSequence = meta::is_array_v || meta::is_string_v || std::same_as> || Sequence; } // namespace morpheus::containers::concepts diff --git a/libraries/core/src/morpheus/core/containers/concepts/unordered.hpp b/libraries/core/src/morpheus/core/containers/concepts/unordered.hpp index 3eaed7bcd..5119a56da 100644 --- a/libraries/core/src/morpheus/core/containers/concepts/unordered.hpp +++ b/libraries/core/src/morpheus/core/containers/concepts/unordered.hpp @@ -1,7 +1,7 @@ #pragma once -#include "morpheus/core/containers/concepts/detail/return_types.hpp" #include "morpheus/core/containers/concepts/allocator_aware.hpp" +#include "morpheus/core/containers/concepts/detail/return_types.hpp" #include "morpheus/core/functional/concepts/hash.hpp" #include @@ -15,12 +15,19 @@ namespace morpheus::containers::concepts /// [unord.req], details at /// UnorderedAssociativeContainerr. template -concept Unordered = AllocatorAware && requires(T t, typename T::value_type v, typename T::key_type k, typename T::size_type s, typename T::iterator i, - typename T::const_iterator ci, typename T::hasher h, typename T::key_equal e, typename T::local_iterator l, - typename T::node_type n, std::initializer_list il) -{ +concept Unordered = AllocatorAware && requires(T t, + typename T::value_type v, + typename T::key_type k, + typename T::size_type s, + typename T::iterator i, + typename T::const_iterator ci, + typename T::hasher h, + typename T::key_equal e, + typename T::local_iterator l, + typename T::node_type n, + std::initializer_list il) { requires functional::concepts::Hash; - requires (std::default_initializable) && (std::copy_constructible); + requires(std::default_initializable) && (std::copy_constructible); { T(s, h, e) }; { T(s, h) }; { T(s) }; diff --git a/libraries/core/src/morpheus/core/conversion/adapters/std/chrono.hpp b/libraries/core/src/morpheus/core/conversion/adapters/std/chrono.hpp index 36487d5bb..bed0ca263 100644 --- a/libraries/core/src/morpheus/core/conversion/adapters/std/chrono.hpp +++ b/libraries/core/src/morpheus/core/conversion/adapters/std/chrono.hpp @@ -15,10 +15,10 @@ /// \def MORPHEUS_CPP_LIB_CHRONO_FORMATTING /// Ensures that std::format support for std::chrono is implemented as specified in /// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0355r7.html -#define MORPHEUS_CPP_LIB_CHRONO_FORMATTING \ - (((MORPHEUS_COMPILER == MORPHEUS_VISUALSTUDIO_COMPILER) && (__cpp_lib_chrono < 201907L)) || \ - ((MORPHEUS_COMPILER == MORPHEUS_GNUC_COMPILER) && (MORPHEUS_COMP_VER < 140000000)) || \ - ((MORPHEUS_COMPILER == MORPHEUS_CLANG_COMPILER) && (MORPHEUS_COMP_VER < 200000000)) || \ +#define MORPHEUS_CPP_LIB_CHRONO_FORMATTING \ + (((MORPHEUS_COMPILER == MORPHEUS_VISUALSTUDIO_COMPILER) && (__cpp_lib_chrono < 201907L)) || \ + ((MORPHEUS_COMPILER == MORPHEUS_GNUC_COMPILER) && (MORPHEUS_COMP_VER < 140000000)) || \ + ((MORPHEUS_COMPILER == MORPHEUS_CLANG_COMPILER) && (MORPHEUS_COMP_VER < 200000000)) || \ ((MORPHEUS_COMPILER == MORPHEUS_APPLE_CLANG_COMPILER) && (MORPHEUS_COMP_VER < 150000000))) #if MORPHEUS_CPP_LIB_CHRONO_FORMATTING @@ -292,7 +292,10 @@ struct morpheus::fmt_ns::formatter : morp auto format(morpheus::date_ns::year_month_weekday const& year_month_weekday, format_context& ctx) const -> format_context::iterator { using namespace std::literals; - return morpheus::fmt_ns::format_to(ctx.out(), "{}/{}/{}"sv, year_month_weekday.year(), months[static_cast(year_month_weekday.month()) - 1], + return morpheus::fmt_ns::format_to(ctx.out(), + "{}/{}/{}"sv, + year_month_weekday.year(), + months[static_cast(year_month_weekday.month()) - 1], year_month_weekday.weekday_indexed()); } }; diff --git a/libraries/core/src/morpheus/core/cpu.cpp b/libraries/core/src/morpheus/core/cpu.cpp index 8cc6083b0..646a4f7e6 100644 --- a/libraries/core/src/morpheus/core/cpu.cpp +++ b/libraries/core/src/morpheus/core/cpu.cpp @@ -35,6 +35,7 @@ constexpr std::uint32_t extended_leaf_range_mask = ~extended_leaf_range_start; */ auto cpuid(std::uint32_t const leaf, std::uint32_t const subleaf = 0) { + // clang-format off CpuidResults results; #if (MORPHEUS_IS_GCC_COMPATIBLE_COMPILER) __get_cpuid(leaf, &results[0], &results[1], &results[2], &results[3]); @@ -46,6 +47,7 @@ auto cpuid(std::uint32_t const leaf, std::uint32_t const subleaf = 0) results[2] = static_cast(result_leaf[2]); results[3] = static_cast(result_leaf[3]); #endif + // clang-format on return results; } @@ -65,7 +67,7 @@ auto get_max_extended_leaf_function() //--------------------------------------------------------------------------------------------------------------------- -auto query_leaf_functions(const std::uint32_t max_leaf) +auto query_leaf_functions(std::uint32_t const max_leaf) { CpuidLeafs results(max_leaf); std::uint32_t current_leaf = 0; @@ -75,7 +77,7 @@ auto query_leaf_functions(const std::uint32_t max_leaf) //--------------------------------------------------------------------------------------------------------------------- -auto query_extended_leaf_functions(const std::uint32_t max_extended_leaf) +auto query_extended_leaf_functions(std::uint32_t const max_extended_leaf) { CpuidLeafs results(extended_leaf_range_mask & max_extended_leaf); std::uint32_t current_leaf = 0; diff --git a/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp b/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp index 8814251db..2d45a47ab 100644 --- a/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp +++ b/libraries/core/src/morpheus/core/memory/polymorphic_value.hpp @@ -169,7 +169,9 @@ struct allocator_wrapper : A }; template -class allocated_pointer_control_block : public control_block, allocator_wrapper +class allocated_pointer_control_block + : public control_block + , allocator_wrapper { U* mValue; diff --git a/libraries/core/src/morpheus/core/meta/binary_search.hpp b/libraries/core/src/morpheus/core/meta/binary_search.hpp index 94a1e5bb5..d06917c38 100644 --- a/libraries/core/src/morpheus/core/meta/binary_search.hpp +++ b/libraries/core/src/morpheus/core/meta/binary_search.hpp @@ -6,7 +6,7 @@ namespace morpheus::meta { -template typename Predicate, std::size_t Begin, std::size_t End> +template