From b6098d4dc658d56ae420f6783c0160e154f1b1e4 Mon Sep 17 00:00:00 2001 From: Caleb Burke Date: Sun, 4 Oct 2026 23:14:17 -0700 Subject: [PATCH] New logger --- editor/utilities/logger.hpp | 9 +- engine/include/sophia/event.hpp | 10 +- engine/include/sophia/ui/panel_registry.hpp | 2 +- engine/include/sophia/util/assert.hpp | 20 ++- engine/include/sophia/util/delegate.hpp | 13 +- engine/include/sophia/util/logger.hpp | 168 +++++++++--------- engine/include/sophia/util/pool.hpp | 11 +- engine/src/application.cpp | 13 +- engine/src/renderer/mesh_render_system.cpp | 5 +- engine/src/renderer/render_context.cpp | 4 +- engine/src/renderer/render_graph.cpp | 16 +- engine/src/renderer/sprite_render_system.cpp | 5 +- .../src/resources/resource_registry_ref.cpp | 2 +- engine/src/vulkan/access.cpp | 2 +- engine/src/vulkan/device.cpp | 33 ++-- engine/src/vulkan/shader.cpp | 16 +- engine/src/vulkan/swapchain.cpp | 2 +- engine/src/vulkan/vk_check.hpp | 20 +++ sandbox/main.cpp | 10 -- 19 files changed, 191 insertions(+), 170 deletions(-) create mode 100644 engine/src/vulkan/vk_check.hpp diff --git a/editor/utilities/logger.hpp b/editor/utilities/logger.hpp index 846896f..f42ac22 100644 --- a/editor/utilities/logger.hpp +++ b/editor/utilities/logger.hpp @@ -1,8 +1,13 @@ #pragma once +#include #include +#include template -void log(Args... args) { - sophia::log::print("\033[1;38;2;170;90;255m[editor]\033[0m", args...); +void log(std::format_string fmt, Args&&... args) { + if constexpr (sophia::log::enabled) { + sophia::log::print("\033[1;38;2;170;90;255m[editor]\033[0m {}", + std::format(fmt, std::forward(args)...)); + } } diff --git a/engine/include/sophia/event.hpp b/engine/include/sophia/event.hpp index 213fa54..2302e4f 100644 --- a/engine/include/sophia/event.hpp +++ b/engine/include/sophia/event.hpp @@ -83,7 +83,7 @@ class EventSystem { this->eventDelegates[eventType] = std::make_unique(EventDelegate()); - log::trace("EventSystem creating new event type: ", eventType); + log::trace("EventSystem creating new event type: {}", eventType); } EventDelegate& delegate = @@ -102,7 +102,7 @@ class EventSystem { this->eventDelegates[eventType] = std::make_unique(EventDelegate()); - log::trace("EventSystem creating new event type: ", eventType); + log::trace("EventSystem creating new event type: {}", eventType); } EventDelegate& delegate = @@ -124,12 +124,14 @@ class EventSystem { std::any_cast&>(*this->eventDelegates.at(eventType)); delegate.invoke(event); } catch (const std::out_of_range& error) { - log::error("event dispatch failed: ", event.toString()); + log::error("event dispatch failed: {}", event.toString()); } } private: - EventSystem() { log::info("EventSystem Initialized: ", this); } + EventSystem() { + log::info("EventSystem Initialized: {}", static_cast(this)); + } ~EventSystem() { log::info("EventSystem Destroyed"); } std::unordered_map> eventDelegates; diff --git a/engine/include/sophia/ui/panel_registry.hpp b/engine/include/sophia/ui/panel_registry.hpp index 5836fee..408a248 100644 --- a/engine/include/sophia/ui/panel_registry.hpp +++ b/engine/include/sophia/ui/panel_registry.hpp @@ -38,7 +38,7 @@ class PanelRegistry { const T& get(PanelHandle handle) const { const Panel& panel = get(handle); SOPHIA_ASSERT(dynamic_cast(&panel) != nullptr, - "PanelHandle does not refer to a", typeid(T).name()); + "PanelHandle does not refer to a {}", typeid(T).name()); return static_cast(panel); } diff --git a/engine/include/sophia/util/assert.hpp b/engine/include/sophia/util/assert.hpp index 5bc0363..3b66620 100644 --- a/engine/include/sophia/util/assert.hpp +++ b/engine/include/sophia/util/assert.hpp @@ -1,7 +1,9 @@ /** * Usage: * SOPHIA_ASSERT(pipelineLayout != nullptr); - * SOPHIA_ASSERT(index < count, "index", index, "out of bounds:", count); + * SOPHIA_ASSERT(index < count, "index {} out of bounds: {}", index, count); + * + * The optional message is a std::format string, checked at compile time. * * Compiled out entirely in release (NDEBUG) builds, matching 's * assert() semantics: don't rely on side effects inside the condition. @@ -10,16 +12,18 @@ #pragma once #include +#include #include #ifndef NDEBUG -#define SOPHIA_ASSERT(condition, ...) \ - do { \ - if (!(condition)) { \ - ::sophia::log::fatal("Assertion failed:", #condition, "at", __FILE__, \ - ":", __LINE__ __VA_OPT__(, ) __VA_ARGS__); \ - std::abort(); \ - } \ +#define SOPHIA_ASSERT(condition, ...) \ + do { \ + if (!(condition)) { \ + ::sophia::log::fatal( \ + "Assertion failed: {} at {}:{}" __VA_OPT__(" - {}"), #condition, \ + __FILE__, __LINE__ __VA_OPT__(, ::std::format(__VA_ARGS__))); \ + std::abort(); \ + } \ } while (false) #else #define SOPHIA_ASSERT(condition, ...) ((void)0) diff --git a/engine/include/sophia/util/delegate.hpp b/engine/include/sophia/util/delegate.hpp index c526c06..335498b 100644 --- a/engine/include/sophia/util/delegate.hpp +++ b/engine/include/sophia/util/delegate.hpp @@ -2,13 +2,12 @@ #include #include +#include #include #include #include #include -#include - #define DEFAULT_DELEGATE_FUNCTOR_ALLOC 5 namespace sophia { @@ -39,7 +38,9 @@ class expired_weak_object : public std::runtime_error { template std::function createWeakFunction(void (O::*method)(A...), std::shared_ptr obj) { - if (!obj) { throw std::invalid_argument("method and obj must not be null"); } + if (!obj) { + throw std::invalid_argument("method and obj must not be null"); + } std::weak_ptr weakObj = obj; @@ -82,7 +83,7 @@ class Delegate { try { this->functors[i](std::forward(args)...); } catch (const expired_weak_object& e) { - log::error("delegate invoke error: ", e.what()); + log::error("delegate invoke error: {}", e.what()); deadFunctorIndexs.push_back(i); } } @@ -97,7 +98,9 @@ class Delegate { void operator=(Functor c) { clear(); - if (c != nullptr) { add(c); } + if (c != nullptr) { + add(c); + } } void operator+=(Functor c) { add(c); } diff --git a/engine/include/sophia/util/logger.hpp b/engine/include/sophia/util/logger.hpp index cc3110d..f492daa 100644 --- a/engine/include/sophia/util/logger.hpp +++ b/engine/include/sophia/util/logger.hpp @@ -1,23 +1,36 @@ /** - * Lots of work still needs to be done in here. + * std::format-style logging. Format strings are checked at compile time. * * Usage: * using namespace sophia; - * log::fatal("fatal message") - * log::info("Infomation message") + * log::fatal("failed to load {}", path) + * log::info("loaded {} meshes in {:.2f}ms", count, ms) + * log::debug("value: {}", x) // prefixed with file:line * log::print("no prefix, just the message") * + * Everything is compiled out in release (NDEBUG) builds. + * * TODO Impl some form of log error handling */ #pragma once -#include -#include +#include +#include +#include +#include +#include +#include #include namespace sophia::log { +#ifndef NDEBUG +inline constexpr bool enabled = true; +#else +inline constexpr bool enabled = false; +#endif // !NDEBUG + enum class LEVEL { NONE, FATAL, @@ -29,118 +42,113 @@ enum class LEVEL { TRACE, }; -// Helper print functions -#define LOG_PRINT_HELPER(MSG) std::cout << MSG -#define LOG_PREFIX_FATAL LOG_PRINT_HELPER("\033[1;91m[FATAL]\033[0m ") -#define LOG_PREFIX_ERROR LOG_PRINT_HELPER("\033[1;31m[ERROR]\033[0m ") -#define LOG_PREFIX_WARNING LOG_PRINT_HELPER("\033[1;33m[WARNING]\033[0m ") -#define LOG_PREFIX_INFO LOG_PRINT_HELPER("\033[32m[INFO]\033[0m ") -#define LOG_PREFIX_VERBOSE LOG_PRINT_HELPER("\033[36m[VERBOSE]\033[0m ") -#define LOG_PREFIX_DEBUG LOG_PRINT_HELPER("\033[1;34m[DEBUG]\033[0m ") -#define LOG_PREFIX_TRACE LOG_PRINT_HELPER("\033[1;90m[TRACE]\033[0m ") +namespace detail { -template -void log(LEVEL level = LEVEL::NONE, Args... args) { -#ifndef NDEBUG +constexpr std::string_view prefix(LEVEL level) { switch (level) { case LEVEL::FATAL: - LOG_PREFIX_FATAL; - break; + return "\033[1;91m[FATAL]\033[0m "; case LEVEL::ERROR: - LOG_PREFIX_ERROR; - break; + return "\033[1;31m[ERROR]\033[0m "; case LEVEL::WARNING: - LOG_PREFIX_WARNING; - break; + return "\033[1;33m[WARNING]\033[0m "; case LEVEL::INFO: - LOG_PREFIX_INFO; - break; + return "\033[32m[INFO]\033[0m "; case LEVEL::VERBOSE: - LOG_PREFIX_VERBOSE; - break; - // case LEVEL::DEBUGGING: - // LOG_PREFIX_DEBUG; - // break; + return "\033[36m[VERBOSE]\033[0m "; + case LEVEL::DEBUGGING: + return "\033[1;34m[DEBUG]\033[0m "; case LEVEL::TRACE: - LOG_PREFIX_TRACE; - break; + return "\033[1;90m[TRACE]\033[0m "; default: - std::cout << "\033[1;90m[LOG]\033[0m "; - break; + return "\033[1;90m[LOG]\033[0m "; } +} - ((std::cout << ' ' << std::forward(args)), ...); - std::cout << std::endl; -#else - (void)level; - (void)std::initializer_list{((void)args, 0)...}; -#endif // !NDEBUG +inline void write(std::string_view prefix, std::string_view message) { + std::println(stdout, "{}{}", prefix, message); + std::fflush(stdout); +} + +// Captures the caller's location alongside the format string, since a +// defaulted std::source_location parameter can't follow a parameter pack. +template +struct FormatWithLocation { + std::format_string fmt; + std::source_location location; + + template + requires std::is_convertible_v + consteval FormatWithLocation( + const S& fmt, + std::source_location location = std::source_location::current()) + : fmt(fmt), location(location) {} +}; + +} // namespace detail + +template +void log(LEVEL level, std::format_string fmt, Args&&... args) { + if constexpr (enabled) { + detail::write(detail::prefix(level), + std::format(fmt, std::forward(args)...)); + } } template -void fatal(Args... args) { - log(LEVEL::FATAL, args...); +void fatal(std::format_string fmt, Args&&... args) { + log(LEVEL::FATAL, fmt, std::forward(args)...); } template -void error(Args... args) { - log(LEVEL::ERROR, args...); +void error(std::format_string fmt, Args&&... args) { + log(LEVEL::ERROR, fmt, std::forward(args)...); } template -void warning(Args... args) { - log(LEVEL::WARNING, args...); +void warning(std::format_string fmt, Args&&... args) { + log(LEVEL::WARNING, fmt, std::forward(args)...); } template -void info(Args... args) { - log(LEVEL::INFO, args...); +void info(std::format_string fmt, Args&&... args) { + log(LEVEL::INFO, fmt, std::forward(args)...); } template -void verbose(Args... args) { - log(LEVEL::VERBOSE, args...); +void verbose(std::format_string fmt, Args&&... args) { + log(LEVEL::VERBOSE, fmt, std::forward(args)...); } template -void debug(const char* file, u16 line, Args... args) { -#ifndef NDEBUG - LOG_PREFIX_DEBUG; - std::cout << file << "::" << line; - ((std::cout << ' ' << std::forward(args)), ...); - std::cout << std::endl; -#else - (void)file; - (void)line; - (void)std::initializer_list{((void)args, 0)...}; -#endif // !NDEBUG +void debug(detail::FormatWithLocation...> fmt, + Args&&... args) { + if constexpr (enabled) { + detail::write( + detail::prefix(LEVEL::DEBUGGING), + std::format("{}:{} {}", fmt.location.file_name(), fmt.location.line(), + std::format(fmt.fmt, std::forward(args)...))); + } } -// trick -#define debug(...) debug(__FILE__, __LINE__, __VA_ARGS__) template -void trace(Args... args) { - log(LEVEL::TRACE, args...); +void trace(std::format_string fmt, Args&&... args) { + log(LEVEL::TRACE, fmt, std::forward(args)...); } -// Like the functions above, but with no "[LEVEL]" prefix: just the arguments, -// separated by spaces, then a newline. With none, an empty line. +// Like the functions above, but with no "[LEVEL]" prefix. With no arguments, +// an empty line. inline void print() { -#ifndef NDEBUG - std::cout << std::endl; -#endif // !NDEBUG + if constexpr (enabled) { + detail::write("", ""); + } } -template -void print(First first, Rest... rest) { -#ifndef NDEBUG - std::cout << first; - ((std::cout << ' ' << rest), ...); - std::cout << std::endl; -#else - (void)first; - (void)std::initializer_list{((void)rest, 0)...}; -#endif // !NDEBUG +template +void print(std::format_string fmt, Args&&... args) { + if constexpr (enabled) { + detail::write("", std::format(fmt, std::forward(args)...)); + } } } // namespace sophia::log diff --git a/engine/include/sophia/util/pool.hpp b/engine/include/sophia/util/pool.hpp index 6ab2416..5cddcac 100644 --- a/engine/include/sophia/util/pool.hpp +++ b/engine/include/sophia/util/pool.hpp @@ -111,15 +111,12 @@ class Pool { }; const Slot& validate(Handle handle) const { - SOPHIA_ASSERT(handle.isValid(), "invalid handle:", name); - SOPHIA_ASSERT(handle.index < slots.size(), name, - "handle index out of range:", handle.index); + SOPHIA_ASSERT(handle.isValid(), "invalid handle: {}", name); + SOPHIA_ASSERT(handle.index < slots.size(), "{} handle index out of range: {}", name, static_cast(handle.index)); const Slot& slot = slots[handle.index]; - SOPHIA_ASSERT(slot.generation == handle.generation, "stale", name, - "handle (generation mismatch):", handle.index); - SOPHIA_ASSERT(slot.item != nullptr, name, - "handle refers to a released item:", handle.index); + SOPHIA_ASSERT(slot.generation == handle.generation, "stale {} handle (generation mismatch): {}", name, static_cast(handle.index)); + SOPHIA_ASSERT(slot.item != nullptr, "{} handle refers to a released item: {}", name, static_cast(handle.index)); return slot; } diff --git a/engine/src/application.cpp b/engine/src/application.cpp index 51d3b2d..f85118f 100644 --- a/engine/src/application.cpp +++ b/engine/src/application.cpp @@ -35,17 +35,6 @@ namespace sophia { namespace { -struct Vertex { - glm::vec2 position; - glm::vec3 color; -}; - -struct PushConstants { - glm::mat4 transform; - glm::vec4 color; - glm::vec4 data; -}; - std::vector commandLineArgs; constexpr ClearColor CLEAR_COLOR = {0.01f, 0.01f, 0.02f, 1.0f}; @@ -287,7 +276,7 @@ class Application::Impl { auto endTime = std::chrono::high_resolution_clock::now(); double totalRuntime = std::chrono::duration(endTime - startTime).count(); - log::info("Application ran for", totalRuntime, "s"); + log::info("Application ran for {:.2f}s", totalRuntime); } void pushMesh(std::vector vertices, std::vector indices) { diff --git a/engine/src/renderer/mesh_render_system.cpp b/engine/src/renderer/mesh_render_system.cpp index 71f19ed..7df390c 100644 --- a/engine/src/renderer/mesh_render_system.cpp +++ b/engine/src/renderer/mesh_render_system.cpp @@ -43,8 +43,9 @@ void MeshRenderSystem::render(vk::CommandBuffer commandBuffer, u32 available = MAX_INSTANCES_PER_FRAME - this->instanceCursor; if (instances.size() > available) { - log::warning("MeshRenderSystem: frame instance buffer full, dropping", - instances.size() - available, "meshes"); + log::warning( + "MeshRenderSystem: frame instance buffer full, dropping {} meshes", + instances.size() - available); } Buffer& buffer = *this->instanceBuffers[this->frameIndex]; diff --git a/engine/src/renderer/render_context.cpp b/engine/src/renderer/render_context.cpp index e5c39b0..5ea487a 100644 --- a/engine/src/renderer/render_context.cpp +++ b/engine/src/renderer/render_context.cpp @@ -38,7 +38,7 @@ vk::CommandBuffer RenderContext::beginFrame() { } if (fenceResult != vk::Result::eSuccess) { - log::error("failed to wait for fence: " + vk::to_string(fenceResult)); + log::error("failed to wait for fence: {}", vk::to_string(fenceResult)); } vk::Semaphore imageAvailable = frame.imageAvailable.get(); @@ -62,7 +62,7 @@ vk::CommandBuffer RenderContext::beginFrame() { imageInFlight, vk::True, std::numeric_limits::max()); if (fenceResult != vk::Result::eSuccess) { - log::error("failed to wait for fence: " + vk::to_string(fenceResult)); + log::error("failed to wait for fence: {}", vk::to_string(fenceResult)); } } diff --git a/engine/src/renderer/render_graph.cpp b/engine/src/renderer/render_graph.cpp index 170bba9..ca970d9 100644 --- a/engine/src/renderer/render_graph.cpp +++ b/engine/src/renderer/render_graph.cpp @@ -106,8 +106,8 @@ void RenderGraph::recordRendering(vk::CommandBuffer commandBuffer, Pass& pass) { const Image& image = *this->images[color.image.index].image; SOPHIA_ASSERT(image.getExtent().width == extent.width && image.getExtent().height == extent.height, - "Pass", pass.name, - "has color attachments of different sizes"); + "Pass {} has color attachments of different sizes", + pass.name); vk::RenderingAttachmentInfo attachment{}; attachment.imageView = image.getView(); @@ -129,8 +129,8 @@ void RenderGraph::recordRendering(vk::CommandBuffer commandBuffer, Pass& pass) { const Image& image = *this->images[pass.depthAttachment->image.index].image; SOPHIA_ASSERT(image.getExtent().width == extent.width && image.getExtent().height == extent.height, - "Pass", pass.name, - "has a depth attachment of a different size"); + "Pass {} has a depth attachment of a different size", + pass.name); depthAttachment.imageView = image.getView(); depthAttachment.imageLayout = @@ -168,8 +168,8 @@ RenderGraph::PassBuilder& RenderGraph::PassBuilder::writeColor( RenderGraph::PassBuilder& RenderGraph::PassBuilder::writeDepth( ImageRef image, vk::AttachmentLoadOp loadOp, float clearDepth) { - SOPHIA_ASSERT(!this->pass.depthAttachment, "Pass", this->pass.name, - "already has a depth attachment"); + SOPHIA_ASSERT(!this->pass.depthAttachment, + "Pass {} already has a depth attachment", this->pass.name); this->use(image, Access::DepthWrite); this->pass.depthAttachment = DepthAttachment{image, loadOp, clearDepth}; return *this; @@ -184,8 +184,8 @@ RenderGraph::PassBuilder& RenderGraph::PassBuilder::use(ImageRef image, SOPHIA_ASSERT(image.isValid() && image.index < this->graph.images.size(), "ImageRef doesn't belong to this graph"); for (const ImageUse& existing : this->pass.uses) { - SOPHIA_ASSERT(existing.image.index != image.index, "Pass", this->pass.name, - "uses the same image twice"); + SOPHIA_ASSERT(existing.image.index != image.index, + "Pass {} uses the same image twice", this->pass.name); } this->pass.uses.push_back({image, access}); diff --git a/engine/src/renderer/sprite_render_system.cpp b/engine/src/renderer/sprite_render_system.cpp index 932b0ec..da1e896 100644 --- a/engine/src/renderer/sprite_render_system.cpp +++ b/engine/src/renderer/sprite_render_system.cpp @@ -45,8 +45,9 @@ void SpriteRenderSystem::render(vk::CommandBuffer commandBuffer, u32 available = MAX_INSTANCES_PER_FRAME - this->instanceCursor; if (instances.size() > available) { - log::warning("SpriteRenderSystem: frame instance buffer full, dropping", - instances.size() - available, "sprites"); + log::warning( + "SpriteRenderSystem: frame instance buffer full, dropping {} sprites", + instances.size() - available); } Buffer& buffer = *this->instanceBuffers[this->frameIndex]; diff --git a/engine/src/resources/resource_registry_ref.cpp b/engine/src/resources/resource_registry_ref.cpp index a329abf..7b04592 100644 --- a/engine/src/resources/resource_registry_ref.cpp +++ b/engine/src/resources/resource_registry_ref.cpp @@ -26,7 +26,7 @@ TextureHandle ResourceRegistryRef::load(const std::string& path) { // Always decode to RGBA8, whatever the file has. stbi_uc* pixels = stbi_load(path.c_str(), &width, &height, &channels, 4); if (pixels == nullptr) { - log::fatal("failed to load texture", path, "-", stbi_failure_reason()); + log::fatal("failed to load texture {} - {}", path, stbi_failure_reason()); throw std::runtime_error("failed to load texture: " + path); } diff --git a/engine/src/vulkan/access.cpp b/engine/src/vulkan/access.cpp index 027d9dc..8a1f84e 100644 --- a/engine/src/vulkan/access.cpp +++ b/engine/src/vulkan/access.cpp @@ -75,7 +75,7 @@ AccessState getStateForLayout(vk::ImageLayout layout) { } } - log::fatal("Unsupported image layout:", vk::to_string(layout)); + log::fatal("Unsupported image layout: {}", vk::to_string(layout)); throw std::runtime_error("Unsupported image layout."); } diff --git a/engine/src/vulkan/device.cpp b/engine/src/vulkan/device.cpp index 6b25081..7509a02 100644 --- a/engine/src/vulkan/device.cpp +++ b/engine/src/vulkan/device.cpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -19,16 +20,16 @@ debugCallback(vk::DebugUtilsMessageSeverityFlagBitsEXT m_severity, (void)pUser_data; if (m_severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eError) { - log::error(pCallback_data->pMessage); + log::error("{}", pCallback_data->pMessage); return VK_SUCCESS; } else if (m_severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning) { - log::warning(pCallback_data->pMessage); + log::warning("{}", pCallback_data->pMessage); } else if (m_severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo) { - log::info(pCallback_data->pMessage); + log::info("{}", pCallback_data->pMessage); } else if (m_severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose) { - log::verbose(pCallback_data->pMessage); + log::verbose("{}", pCallback_data->pMessage); } else { - log::info(pCallback_data->pMessage); + log::info("{}", pCallback_data->pMessage); } return VK_FALSE; @@ -107,8 +108,8 @@ static void forEachRequiredFeature(DeviceFeatureChain& chain, Fn&& fn) { static bool checkDeviceFeatureSupport(const vk::PhysicalDevice& device) { vk::PhysicalDeviceProperties properties = device.getProperties(); if (properties.apiVersion < SOPHIA_VULKAN_API_VERSION) { - log::verbose("Skipping ", properties.deviceName, - ": Vulkan 1.3 not supported"); + log::verbose("Skipping {}: Vulkan 1.3 not supported", + properties.deviceName.data()); return false; } @@ -119,8 +120,8 @@ static bool checkDeviceFeatureSupport(const vk::PhysicalDevice& device) { bool allSupported = true; forEachRequiredFeature(supported, [&](vk::Bool32 has, const char* name) { if (!has) { - log::verbose("Skipping ", properties.deviceName, - ": missing device feature ", name); + log::verbose("Skipping {}: missing device feature {}", + properties.deviceName.data(), name); allSupported = false; } }); @@ -197,7 +198,7 @@ void Device::createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, this->allocator, &static_cast(bufferInfo), &allocInfo, &rawBuffer, &allocation, nullptr); if (result != VK_SUCCESS) { - log::fatal("failed to create buffer. Error: ", + log::fatal("failed to create buffer. Error: {}", vk::to_string(static_cast(result))); throw std::runtime_error("failed to create buffer"); } @@ -220,7 +221,7 @@ vk::CommandBuffer Device::beginSingleTimeCommands() { throw vk::SystemError(result); } } catch (const vk::SystemError& error) { - log::error("failed to allocate single time commandBuffer. Error: ", + log::error("failed to allocate single time commandBuffer. Error: {}", error.what()); throw std::runtime_error("failed to allocate single time commandBuffer"); } @@ -234,7 +235,7 @@ vk::CommandBuffer Device::beginSingleTimeCommands() { throw vk::SystemError(result); } } catch (const vk::SystemError& error) { - log::error("failed to begin single time commandBuffer. Error: ", + log::error("failed to begin single time commandBuffer. Error: {}", error.what()); throw std::runtime_error("failed to begin single time commandBuffer"); } @@ -278,7 +279,7 @@ void Device::createImageWithInfo(const vk::ImageCreateInfo& imageInfo, this->allocator, &static_cast(imageInfo), &allocInfo, &rawImage, &allocation, nullptr); if (result != VK_SUCCESS) { - log::fatal("failed to create image. Error: ", + log::fatal("failed to create image. Error: {}", vk::to_string(static_cast(result))); throw std::runtime_error("failed to create image"); } @@ -374,7 +375,7 @@ std::vector Device::getRequiredExtensions() { throw std::exception(); } - log::verbose("Number of available extensions: ", available_extension_count); + log::verbose("Number of available extensions: {}", available_extension_count); log::verbose("Available extensions:"); for (const auto& e : available_extensions) { @@ -482,7 +483,7 @@ void Device::pickPhysicalDevice() { log::fatal("Failed to find any physical devices."); throw std::exception(); } - log::verbose("Physical Devices count: ", physicalDevices.size()); + log::verbose("Physical Devices count: {}", physicalDevices.size()); // Select first physical device that is suitable for (const auto& device : physicalDevices) { @@ -498,7 +499,7 @@ void Device::pickPhysicalDevice() { } this->properties = this->physicalDevice.getProperties(); - log::verbose("Physical Device: ", this->properties.deviceName); + log::verbose("Physical Device: {}", this->properties.deviceName.data()); } void Device::createLogicalDevice() { diff --git a/engine/src/vulkan/shader.cpp b/engine/src/vulkan/shader.cpp index e0de91b..027aaad 100644 --- a/engine/src/vulkan/shader.cpp +++ b/engine/src/vulkan/shader.cpp @@ -25,7 +25,7 @@ std::vector readFile(const std::string& path) { std::ifstream file(path, std::ios::ate | std::ios::binary); if (!file.is_open()) { - log::error("failed to open shader: " + path); + log::error("failed to open shader: {}", path); throw std::runtime_error("failed to open: " + path); } @@ -46,22 +46,23 @@ void Shader::compile(const std::string& path, ShaderStage shaderStage) { std::vector source = readFile(path); - log::info("Compiling shader: " + path); + log::info("Compiling shader: {}", path); shaderc::Compiler compiler; shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv( source.data(), source.size(), toShadercKind(shaderStage), path.c_str()); if (result.GetCompilationStatus() != shaderc_compilation_status_success) { - log::fatal("failed to compile shader:", path, result.GetErrorMessage()); + log::fatal("failed to compile shader: {}: {}", path, + result.GetErrorMessage()); throw std::runtime_error("failed to compile shader: " + path + ": " + result.GetErrorMessage()); } this->spirv.assign(result.cbegin(), result.cend()); - log::info("Successfully compiled shader: " + path + " (" + - std::to_string(this->spirv.size() * 4) + " bytes)"); + log::info("Successfully compiled shader: {} ({} bytes)", path, + this->spirv.size() * 4); } void Shader::load(const std::string& path, ShaderStage shaderStage) { @@ -70,15 +71,14 @@ void Shader::load(const std::string& path, ShaderStage shaderStage) { std::vector bytes = readFile(path); if (bytes.size() % sizeof(u32) != 0) { - log::fatal("invalid SPIR-V binary (size not a multiple of 4):", path); + log::fatal("invalid SPIR-V binary (size not a multiple of 4): {}", path); throw std::runtime_error("invalid SPIR-V binary: " + path); } this->spirv.assign(reinterpret_cast(bytes.data()), reinterpret_cast(bytes.data() + bytes.size())); - log::info("Loaded precompiled shader: " + path + " (" + - std::to_string(bytes.size()) + " bytes)"); + log::info("Loaded precompiled shader: {} ({} bytes)", path, bytes.size()); } Shader::Builder& Shader::Builder::fromGLSL(const std::string& path) { diff --git a/engine/src/vulkan/swapchain.cpp b/engine/src/vulkan/swapchain.cpp index 66fe4b0..6aaf02e 100644 --- a/engine/src/vulkan/swapchain.cpp +++ b/engine/src/vulkan/swapchain.cpp @@ -114,7 +114,7 @@ void Swapchain::createSwapchain() { this->device.get()->createSwapchainKHR(this->swapchainCreateInfo); // log::trace("created vk::SwapchainKHR"); } catch (const vk::SystemError& err) { - log::fatal("failed to create swapchain. Error: ", err.what()); + log::fatal("failed to create swapchain. Error: {}", err.what()); throw std::runtime_error("failed to create swapchain"); } } diff --git a/engine/src/vulkan/vk_check.hpp b/engine/src/vulkan/vk_check.hpp new file mode 100644 index 0000000..ab77d9c --- /dev/null +++ b/engine/src/vulkan/vk_check.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include +#include + +inline void vk_check(vk::Result result, std::source_location loc = + std::source_location::current()) { + if (result != vk::Result::eSuccess) { + std::fprintf(stderr, "%s:%u: %s: %s\n", loc.file_name(), loc.line(), + loc.function_name(), vk::to_string(result).c_str()); + std::abort(); + } +} + +inline void vk_check(VkResult result, std::source_location loc = + std::source_location::current()) { + vk_check(static_cast(result), loc); +} diff --git a/sandbox/main.cpp b/sandbox/main.cpp index b8415e1..af1b5ce 100644 --- a/sandbox/main.cpp +++ b/sandbox/main.cpp @@ -11,16 +11,6 @@ #include #include -#define VK_CHECK(expr) \ - do { \ - vk::Result result_ = (expr); \ - if (result_ != vk::Result::eSuccess) { \ - std::fprintf(stderr, "%s:%d: %s -> %d\n", __FILE__, __LINE__, #expr, \ - result_); \ - std::abort(); \ - } \ - } while (0) - constexpr uint32_t WIDTH = 1280; constexpr uint32_t HEIGHT = 720; constexpr const char* NAME = "";