Refactor logging and tracing in SDL3 application

- Replaced macro-based logging with a dedicated Logger class for improved readability and maintainability.
- Introduced TraceGuard class for automatic function entry/exit logging.
- Updated all relevant source files to utilize the new logging and tracing mechanisms.
- Consolidated SDL_MAIN_HANDLED definition into a separate header file (sdl_macros.hpp) for better organization.
- Ensured consistent logging practices across the application, including error handling and debug information.
This commit is contained in:
2026-01-04 01:14:05 +00:00
parent b5af532c19
commit 198179bfca
20 changed files with 133 additions and 106 deletions

View File

@@ -1,9 +1,7 @@
#ifndef SDL3CPP_APP_SDL3_APP_HPP
#define SDL3CPP_APP_SDL3_APP_HPP
#ifndef SDL_MAIN_HANDLED
#define SDL_MAIN_HANDLED
#endif
#include "sdl_macros.hpp"
#include <array>
#include <filesystem>

View File

@@ -9,7 +9,7 @@
namespace sdl3cpp::app {
void Sdl3App::LoadSceneData() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
shaderPathMap_ = scriptEngine_.LoadShaderPathsMap();
if (shaderPathMap_.empty()) {
throw std::runtime_error("Lua script did not provide shader paths");
@@ -54,12 +54,12 @@ void Sdl3App::LoadSceneData() {
}
void Sdl3App::CreateVertexBuffer() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
if (vertices_.empty()) {
throw std::runtime_error("Cannot create vertex buffer: no vertices loaded");
}
VkDeviceSize bufferSize = sizeof(vertices_[0]) * vertices_.size();
TRACE_VAR(bufferSize);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("bufferSize", bufferSize);
std::cout << "Creating vertex buffer: " << vertices_.size() << " vertices ("
<< (bufferSize / 1024) << " KB)\n";
std::cout.flush();
@@ -75,12 +75,12 @@ void Sdl3App::CreateVertexBuffer() {
}
void Sdl3App::CreateIndexBuffer() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
if (indices_.empty()) {
throw std::runtime_error("Cannot create index buffer: no indices loaded");
}
VkDeviceSize bufferSize = sizeof(indices_[0]) * indices_.size();
TRACE_VAR(bufferSize);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("bufferSize", bufferSize);
std::cout << "Creating index buffer: " << indices_.size() << " indices ("
<< (bufferSize / 1024) << " KB)\n";
std::cout.flush();

View File

@@ -6,7 +6,7 @@
namespace sdl3cpp::app {
void Sdl3App::CreateFramebuffers() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
swapChainFramebuffers_.resize(swapChainImageViews_.size());
for (size_t i = 0; i < swapChainImageViews_.size(); ++i) {
VkImageView attachments[] = {swapChainImageViews_[i]};
@@ -28,7 +28,7 @@ void Sdl3App::CreateFramebuffers() {
}
void Sdl3App::CreateCommandPool() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
QueueFamilyIndices indices = FindQueueFamilies(physicalDevice_);
VkCommandPoolCreateInfo poolInfo{};
@@ -42,7 +42,7 @@ void Sdl3App::CreateCommandPool() {
}
void Sdl3App::CreateSyncObjects() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
VkSemaphoreCreateInfo semaphoreInfo{};
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

View File

@@ -19,7 +19,7 @@ namespace sdl3cpp::app {
extern std::atomic<bool> g_signalReceived;
std::vector<char> ReadFile(const std::string& path) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
// Validate file exists before attempting to open
if (!std::filesystem::exists(path)) {
@@ -116,8 +116,8 @@ void ShowErrorDialog(const char* title, const std::string& message) {
Sdl3App::Sdl3App(const std::filesystem::path& scriptPath, bool luaDebug)
: scriptEngine_(scriptPath, luaDebug),
scriptDirectory_(scriptPath.parent_path()) {
TRACE_FUNCTION();
TRACE_VAR(scriptPath);
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
sdl3cpp::logging::Logger::GetInstance().TraceVariable("scriptPath", scriptPath);
}
bool Sdl3App::ShouldStop() {
@@ -125,7 +125,7 @@ bool Sdl3App::ShouldStop() {
}
void Sdl3App::Run() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
InitSDL();
InitVulkan();
MainLoop();
@@ -133,9 +133,9 @@ void Sdl3App::Run() {
}
void Sdl3App::InitSDL() {
TRACE_FUNCTION();
TRACE_VAR(kWidth);
TRACE_VAR(kHeight);
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
sdl3cpp::logging::Logger::GetInstance().TraceVariable("kWidth", kWidth);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("kHeight", kHeight);
try {
ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed");
@@ -160,18 +160,18 @@ void Sdl3App::InitSDL() {
std::string("Failed to create application window.\n\nError: ") + errorMsg);
throw std::runtime_error(errorMsg);
}
TRACE_VAR(window_);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("window_", window_);
SDL_StartTextInput(window_);
try {
audioPlayer_ = std::make_unique<AudioPlayer>();
scriptEngine_.SetAudioPlayer(audioPlayer_.get());
} catch (const std::exception& exc) {
LOG_WARN("AudioPlayer initialization failed: " + std::string(exc.what()));
sdl3cpp::logging::Logger::GetInstance().Warn("AudioPlayer initialization failed: " + std::string(exc.what()));
}
}
void Sdl3App::InitVulkan() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
try {
CreateInstance();
} catch (const std::exception& e) {
@@ -222,8 +222,8 @@ void Sdl3App::InitVulkan() {
}
void Sdl3App::MainLoop() {
TRACE_FUNCTION();
TRACE_VAR(guiHasCommands_);
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
sdl3cpp::logging::Logger::GetInstance().TraceVariable("guiHasCommands_", guiHasCommands_);
bool running = true;
auto start = std::chrono::steady_clock::now();
auto lastProgressTime = start;
@@ -238,14 +238,14 @@ void Sdl3App::MainLoop() {
if (!firstFrameCompleted_) {
auto elapsed = now - start;
if (elapsed > kLaunchTimeout) {
LOG_ERROR("Launch timeout: Application failed to render first frame within " + std::to_string(std::chrono::duration_cast<std::chrono::seconds>(kLaunchTimeout).count()) + " seconds. This typically indicates GPU driver issue, window manager problem, or Vulkan swapchain configuration mismatch.");
sdl3cpp::logging::Logger::GetInstance().Error("Launch timeout: Application failed to render first frame within " + std::to_string(std::chrono::duration_cast<std::chrono::seconds>(kLaunchTimeout).count()) + " seconds. This typically indicates GPU driver issue, window manager problem, or Vulkan swapchain configuration mismatch.");
throw std::runtime_error("Launch timeout: First frame did not complete");
}
// Print progress indicator every second during launch
if (now - lastProgressTime > std::chrono::seconds(1)) {
auto waitTime = std::chrono::duration_cast<std::chrono::seconds>(elapsed).count();
LOG_INFO("Waiting for first frame... (" + std::to_string(waitTime) + "s)");
sdl3cpp::logging::Logger::GetInstance().Info("Waiting for first frame... (" + std::to_string(waitTime) + "s)");
lastProgressTime = now;
}
}
@@ -285,7 +285,7 @@ void Sdl3App::MainLoop() {
}
void Sdl3App::Cleanup() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
CleanupSwapChain();
vkDestroyBuffer(device_, vertexBuffer_, nullptr);

View File

@@ -8,7 +8,7 @@
namespace sdl3cpp::app {
void Sdl3App::CreateInstance() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
// Early validation: Check if Vulkan is available
uint32_t apiVersion = 0;
@@ -54,8 +54,8 @@ void Sdl3App::CreateInstance() {
}
std::vector<const char*> extensionList(extensions, extensions + extensionCount);
TRACE_VAR(extensionCount);
TRACE_VAR(extensionList.size());
sdl3cpp::logging::Logger::GetInstance().TraceVariable("extensionCount", extensionCount);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("extensionList.size(", extensionList.size());
// Enable validation layers if available
std::vector<const char*> layerList;
@@ -104,14 +104,14 @@ void Sdl3App::CreateInstance() {
}
void Sdl3App::CreateSurface() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
if (!SDL_Vulkan_CreateSurface(window_, instance_, nullptr, &surface_)) {
throw std::runtime_error("Failed to create Vulkan surface");
}
}
void Sdl3App::PickPhysicalDevice() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
uint32_t deviceCount = 0;
VkResult enumResult = vkEnumeratePhysicalDevices(instance_, &deviceCount, nullptr);
if (enumResult != VK_SUCCESS) {
@@ -172,7 +172,7 @@ void Sdl3App::PickPhysicalDevice() {
}
void Sdl3App::CreateLogicalDevice() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
QueueFamilyIndices indices = FindQueueFamilies(physicalDevice_);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
@@ -199,17 +199,17 @@ void Sdl3App::CreateLogicalDevice() {
createInfo.ppEnabledExtensionNames = kDeviceExtensions.data();
if (vkCreateDevice(physicalDevice_, &createInfo, nullptr, &device_) != VK_SUCCESS) {
LOG_ERROR("Failed to create logical device");
sdl3cpp::logging::Logger::GetInstance().Error("Failed to create logical device");
throw std::runtime_error("Failed to create logical device");
}
LOG_INFO("Logical device created successfully");
sdl3cpp::logging::Logger::GetInstance().Info("Logical device created successfully");
vkGetDeviceQueue(device_, *indices.graphicsFamily, 0, &graphicsQueue_);
vkGetDeviceQueue(device_, *indices.presentFamily, 0, &presentQueue_);
}
QueueFamilyIndices Sdl3App::FindQueueFamilies(VkPhysicalDevice device) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
@@ -241,7 +241,7 @@ QueueFamilyIndices Sdl3App::FindQueueFamilies(VkPhysicalDevice device) {
}
bool Sdl3App::CheckDeviceExtensionSupport(VkPhysicalDevice device) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
uint32_t extensionCount = 0;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
@@ -259,14 +259,14 @@ bool Sdl3App::CheckDeviceExtensionSupport(VkPhysicalDevice device) {
for (const auto& missing : requiredExtensions) {
missingList += " - " + missing + "\n";
}
LOG_ERROR("Missing required device extensions:\n" + missingList);
sdl3cpp::logging::Logger::GetInstance().Error("Missing required device extensions:\n" + missingList);
}
return requiredExtensions.empty();
}
SwapChainSupportDetails Sdl3App::QuerySwapChainSupport(VkPhysicalDevice device) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
SwapChainSupportDetails details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface_, &details.capabilities);
@@ -289,7 +289,7 @@ SwapChainSupportDetails Sdl3App::QuerySwapChainSupport(VkPhysicalDevice device)
}
bool Sdl3App::IsDeviceSuitable(VkPhysicalDevice device) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
QueueFamilyIndices indices = FindQueueFamilies(device);
bool extensionsSupported = CheckDeviceExtensionSupport(device);

View File

@@ -7,7 +7,7 @@
namespace sdl3cpp::app {
VkShaderModule Sdl3App::CreateShaderModule(const std::vector<char>& code) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
@@ -21,7 +21,7 @@ VkShaderModule Sdl3App::CreateShaderModule(const std::vector<char>& code) {
}
void Sdl3App::CreateGraphicsPipeline() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
if (shaderPathMap_.empty()) {
throw std::runtime_error("No shader paths were loaded before pipeline creation");
}

View File

@@ -127,12 +127,12 @@ void Sdl3App::PrintGpuDiagnostics(const std::string& errorContext) {
ss << "5. Try with different Vulkan settings or validation layers\n";
ss << "========================================\n";
// LOG_ERROR(ss.str());
// sdl3cpp::logging::Logger::GetInstance().Error(ss.str());
std::cerr << ss.str() << std::endl;
}
void Sdl3App::CreateCommandBuffers() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
commandBuffers_.resize(swapChainFramebuffers_.size());
VkCommandBufferAllocateInfo allocInfo{};
@@ -148,8 +148,8 @@ void Sdl3App::CreateCommandBuffers() {
void Sdl3App::RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex, float time,
const std::array<float, 16>& viewProj) {
TRACE_FUNCTION();
TRACE_VAR(imageIndex);
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
sdl3cpp::logging::Logger::GetInstance().TraceVariable("imageIndex", imageIndex);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@@ -192,14 +192,17 @@ void Sdl3App::RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageI
}
*/
vkCmdEndRenderPass(commandBuffer);
// Temporarily disable GUI rendering to test if it's causing the GPU hang
/*
if (guiRenderer_) {
guiRenderer_->BlitToSwapchain(commandBuffer, swapChainImages_[imageIndex]);
}
*/
vkEndCommandBuffer(commandBuffer);
}
void Sdl3App::ProcessGuiEvent(const SDL_Event& event) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
switch (event.type) {
case SDL_EVENT_MOUSE_MOTION:
guiInputSnapshot_.mouseX = static_cast<float>(event.motion.x);
@@ -232,7 +235,7 @@ void Sdl3App::ProcessGuiEvent(const SDL_Event& event) {
}
void Sdl3App::SetupGuiRenderer() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
guiHasCommands_ = scriptEngine_.HasGuiCommands();
if (!guiHasCommands_) {
guiRenderer_.reset();
@@ -247,18 +250,18 @@ void Sdl3App::SetupGuiRenderer() {
}
void Sdl3App::DrawFrame(float time) {
TRACE_FUNCTION();
LOG_DEBUG("Drawing frame at time " + std::to_string(time));
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
sdl3cpp::logging::Logger::GetInstance().Debug("Drawing frame at time " + std::to_string(time));
// Use reasonable timeout instead of infinite wait (5 seconds)
constexpr uint64_t kFenceTimeout = 5000000000ULL; // 5 seconds in nanoseconds
VkResult fenceResult = vkWaitForFences(device_, 1, &inFlightFence_, VK_TRUE, kFenceTimeout);
if (fenceResult == VK_TIMEOUT) {
LOG_ERROR("Fence wait timeout: GPU appears to be hung");
sdl3cpp::logging::Logger::GetInstance().Error("Fence wait timeout: GPU appears to be hung");
PrintGpuDiagnostics("Fence wait timeout after 5 seconds");
throw std::runtime_error("Fence wait timeout: GPU appears to be hung");
} else if (fenceResult != VK_SUCCESS) {
LOG_ERROR("Fence wait failed with code: " + std::to_string(fenceResult));
sdl3cpp::logging::Logger::GetInstance().Error("Fence wait failed with code: " + std::to_string(fenceResult));
PrintGpuDiagnostics("Fence wait failed with error code " + std::to_string(fenceResult));
throw std::runtime_error("Fence wait failed");
}
@@ -279,7 +282,7 @@ void Sdl3App::DrawFrame(float time) {
} else if (framebufferResized_) {
logMsg += " - RESIZE_EVENT";
}
LOG_INFO(logMsg);
sdl3cpp::logging::Logger::GetInstance().Info(logMsg);
// Detect infinite swapchain recreation loop
constexpr int kMaxConsecutiveRecreations = 10;
@@ -299,7 +302,7 @@ void Sdl3App::DrawFrame(float time) {
} else if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to acquire swap chain image");
}
TRACE_VAR(imageIndex);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("imageIndex", imageIndex);
float aspect = static_cast<float>(swapChainExtent_.width) / static_cast<float>(swapChainExtent_.height);
auto viewProj = scriptEngine_.GetViewProjectionMatrix(aspect);

View File

@@ -7,7 +7,7 @@
namespace sdl3cpp::app {
void Sdl3App::CreateSwapChain() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
SwapChainSupportDetails support = QuerySwapChainSupport(physicalDevice_);
// Validate swap chain support
@@ -23,16 +23,16 @@ void Sdl3App::CreateSwapChain() {
// Validate window dimensions
int windowWidth = 0, windowHeight = 0;
SDL_GetWindowSize(window_, &windowWidth, &windowHeight);
LOG_INFO("Window size: " + std::to_string(windowWidth) + "x" + std::to_string(windowHeight));
sdl3cpp::logging::Logger::GetInstance().Info("Window size: " + std::to_string(windowWidth) + "x" + std::to_string(windowHeight));
if (windowWidth == 0 || windowHeight == 0) {
LOG_ERROR("Invalid window dimensions (" + std::to_string(windowWidth) + "x" + std::to_string(windowHeight) + "). Window may be minimized or invalid.");
sdl3cpp::logging::Logger::GetInstance().Error("Invalid window dimensions (" + std::to_string(windowWidth) + "x" + std::to_string(windowHeight) + "). Window may be minimized or invalid.");
throw std::runtime_error("Invalid window dimensions (" +
std::to_string(windowWidth) + "x" + std::to_string(windowHeight) + ").\n" +
"Window may be minimized or invalid.");
}
LOG_DEBUG("Surface capabilities - Min extent: " + std::to_string(support.capabilities.minImageExtent.width) + "x" + std::to_string(support.capabilities.minImageExtent.height) +
sdl3cpp::logging::Logger::GetInstance().Debug("Surface capabilities - Min extent: " + std::to_string(support.capabilities.minImageExtent.width) + "x" + std::to_string(support.capabilities.minImageExtent.height) +
", Max extent: " + std::to_string(support.capabilities.maxImageExtent.width) + "x" + std::to_string(support.capabilities.maxImageExtent.height) +
", Min images: " + std::to_string(support.capabilities.minImageCount) +
", Max images: " + std::to_string(support.capabilities.maxImageCount));
@@ -45,7 +45,7 @@ void Sdl3App::CreateSwapChain() {
if (support.capabilities.maxImageCount > 0 && imageCount > support.capabilities.maxImageCount) {
imageCount = support.capabilities.maxImageCount;
}
TRACE_VAR(imageCount);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("imageCount", imageCount);
VkSwapchainCreateInfoKHR createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
@@ -85,7 +85,7 @@ void Sdl3App::CreateSwapChain() {
}
void Sdl3App::CreateImageViews() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
swapChainImageViews_.resize(swapChainImages_.size());
for (size_t i = 0; i < swapChainImages_.size(); ++i) {
VkImageViewCreateInfo viewInfo{};
@@ -108,7 +108,7 @@ void Sdl3App::CreateImageViews() {
}
void Sdl3App::CreateRenderPass() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
VkAttachmentDescription colorAttachment{};
colorAttachment.format = swapChainImageFormat_;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
@@ -151,7 +151,7 @@ void Sdl3App::CreateRenderPass() {
}
void Sdl3App::CleanupSwapChain() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
for (auto framebuffer : swapChainFramebuffers_) {
vkDestroyFramebuffer(device_, framebuffer, nullptr);
}
@@ -173,7 +173,7 @@ void Sdl3App::CleanupSwapChain() {
}
void Sdl3App::RecreateSwapChain() {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
int width = 0;
int height = 0;
@@ -184,13 +184,13 @@ void Sdl3App::RecreateSwapChain() {
while (width == 0 || height == 0) {
// Escape hatch 1: Check for signal (Ctrl+C)
if (ShouldStop()) {
LOG_WARN("Received stop signal while waiting for valid window dimensions");
sdl3cpp::logging::Logger::GetInstance().Warn("Received stop signal while waiting for valid window dimensions");
throw std::runtime_error("Application shutdown requested");
}
// Escape hatch 2: Timeout after maximum attempts
if (attempts >= kMaxAttempts) {
LOG_ERROR("Timeout waiting for valid window dimensions after " + std::to_string(attempts) + " attempts. Window size stuck at: " + std::to_string(width) + "x" + std::to_string(height));
sdl3cpp::logging::Logger::GetInstance().Error("Timeout waiting for valid window dimensions after " + std::to_string(attempts) + " attempts. Window size stuck at: " + std::to_string(width) + "x" + std::to_string(height));
throw std::runtime_error("Window resize timeout: dimensions remain 0x0");
}
@@ -204,12 +204,12 @@ void Sdl3App::RecreateSwapChain() {
// Log periodically for debugging
if (attempts % 10 == 0) {
LOG_DEBUG("Still waiting for valid window dimensions (attempt " + std::to_string(attempts) + "/" + std::to_string(kMaxAttempts) + "): " + std::to_string(width) + "x" + std::to_string(height));
sdl3cpp::logging::Logger::GetInstance().Debug("Still waiting for valid window dimensions (attempt " + std::to_string(attempts) + "/" + std::to_string(kMaxAttempts) + "): " + std::to_string(width) + "x" + std::to_string(height));
}
}
}
LOG_INFO("Window resize resolved: " + std::to_string(width) + "x" + std::to_string(height));
sdl3cpp::logging::Logger::GetInstance().Info("Window resize resolved: " + std::to_string(width) + "x" + std::to_string(height));
vkDeviceWaitIdle(device_);
CleanupSwapChain();
CreateSwapChain();
@@ -223,7 +223,7 @@ void Sdl3App::RecreateSwapChain() {
}
VkSurfaceFormatKHR Sdl3App::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB &&
availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
@@ -234,7 +234,7 @@ VkSurfaceFormatKHR Sdl3App::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceF
}
VkPresentModeKHR Sdl3App::ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return availablePresentMode;

9
src/app/sdl_macros.hpp Normal file
View File

@@ -0,0 +1,9 @@
#ifndef SDL3CPP_APP_SDL_MACROS_HPP
#define SDL3CPP_APP_SDL_MACROS_HPP
// SDL macros required for core library functionality
#ifndef SDL_MAIN_HANDLED
#define SDL_MAIN_HANDLED
#endif
#endif // SDL3CPP_APP_SDL_MACROS_HPP

View File

@@ -15,12 +15,12 @@ uint32_t FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, Vk
for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) {
if ((typeFilter & (1 << i)) &&
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
LOG_DEBUG("Found suitable memory type: " + std::to_string(i));
sdl3cpp::logging::Logger::GetInstance().Debug("Found suitable memory type: " + std::to_string(i));
return i;
}
}
LOG_ERROR("Failed to find suitable memory type");
sdl3cpp::logging::Logger::GetInstance().Error("Failed to find suitable memory type");
throw std::runtime_error("Failed to find suitable memory type");
}
@@ -41,10 +41,10 @@ VkExtent2D ChooseSwapExtent(VkSurfaceCapabilitiesKHR capabilities, SDL_Window* w
void CreateBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage,
VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
LOG_DEBUG("Creating buffer with size " + std::to_string(size) + " bytes");
sdl3cpp::logging::Logger::GetInstance().Debug("Creating buffer with size " + std::to_string(size) + " bytes");
// Validate buffer size
if (size == 0) {
LOG_ERROR("Cannot create buffer with size 0");
sdl3cpp::logging::Logger::GetInstance().Error("Cannot create buffer with size 0");
throw std::runtime_error("Cannot create buffer with size 0");
}

View File

@@ -2,6 +2,7 @@
#include "gui/gui_renderer.hpp"
#include "app/vulkan_api.hpp"
#include "logging/logger.hpp"
#include <algorithm>
#include <array>
@@ -356,7 +357,9 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
physicalDevice_(physicalDevice),
swapchainFormat_(swapchainFormat),
scriptDirectory_(scriptDirectory),
canvas_(std::make_unique<Canvas>()) {}
canvas_(std::make_unique<Canvas>()) {
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
}
GuiRenderer::~GuiRenderer() {
DestroyStagingBuffer();

View File

@@ -84,15 +84,17 @@ private:
std::mutex mutex_;
};
#define LOG_TRACE(msg) sdl3cpp::logging::Logger::GetInstance().Trace(msg)
#define LOG_DEBUG(msg) sdl3cpp::logging::Logger::GetInstance().Debug(msg)
#define LOG_INFO(msg) sdl3cpp::logging::Logger::GetInstance().Info(msg)
#define LOG_WARN(msg) sdl3cpp::logging::Logger::GetInstance().Warn(msg)
#define LOG_ERROR(msg) sdl3cpp::logging::Logger::GetInstance().Error(msg)
#define TRACE_FUNCTION() sdl3cpp::logging::Logger::GetInstance().TraceFunction(__func__)
#define TRACE_VAR(var) sdl3cpp::logging::Logger::GetInstance().TraceVariable(#var, var)
#define TRACE_FUNCTION_ARGS(...) sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(__func__, __VA_ARGS__)
class TraceGuard {
public:
TraceGuard(const std::string& funcName) : funcName_(funcName) {
Logger::GetInstance().Trace("Entering " + funcName_);
}
~TraceGuard() {
Logger::GetInstance().Trace("Exiting " + funcName_);
}
private:
std::string funcName_;
};
} // namespace sdl3cpp::logging

View File

@@ -71,6 +71,7 @@ RuntimeConfig GenerateDefaultRuntimeConfig(const char* argv0) {
}
RuntimeConfig LoadRuntimeConfigFromJson(const std::filesystem::path& configPath, bool dumpConfig) {
sdl3cpp::logging::Logger::GetInstance().TraceFunctionWithArgs(__PRETTY_FUNCTION__, configPath.string(), dumpConfig);
std::ifstream configStream(configPath);
if (!configStream) {
throw std::runtime_error("Failed to open config file: " + configPath.string());
@@ -251,9 +252,9 @@ AppOptions ParseCommandLine(int argc, char** argv) {
}
void LogRuntimeConfig(const RuntimeConfig& config) {
TRACE_VAR(config.width);
TRACE_VAR(config.height);
TRACE_VAR(config.scriptPath);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("config.width", config.width);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("config.height", config.height);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("config.scriptPath", config.scriptPath);
}
void WriteRuntimeConfigJson(const RuntimeConfig& runtimeConfig,
@@ -323,7 +324,7 @@ int main(int argc, char** argv) {
}
logger.EnableConsoleOutput(true);
logger.SetOutputFile("sdl3_app.log");
LOG_INFO("Application starting");
sdl3cpp::logging::Logger::GetInstance().Info("Application starting");
LogRuntimeConfig(options.runtimeConfig);
if (options.seedOutput) {
WriteRuntimeConfigJson(options.runtimeConfig, *options.seedOutput);
@@ -339,7 +340,7 @@ int main(int argc, char** argv) {
app.Run();
} catch (const std::runtime_error& e) {
std::string errorMsg = e.what();
LOG_ERROR("Runtime error: " + errorMsg);
sdl3cpp::logging::Logger::GetInstance().Error("Runtime error: " + errorMsg);
// Check if this is a timeout/hang error - show simpler message for these
bool isTimeoutError = errorMsg.find("timeout") != std::string::npos ||
@@ -365,7 +366,7 @@ int main(int argc, char** argv) {
}
return EXIT_FAILURE;
} catch (const std::exception& e) {
LOG_ERROR("Exception: " + std::string(e.what()));
sdl3cpp::logging::Logger::GetInstance().Error("Exception: " + std::string(e.what()));
SDL_ShowSimpleMessageBox(
SDL_MESSAGEBOX_ERROR,
"Application Error",

View File

@@ -10,7 +10,9 @@
namespace sdl3cpp::script {
AudioManager::AudioManager(const std::filesystem::path& scriptDirectory)
: scriptDirectory_(scriptDirectory) {}
: scriptDirectory_(scriptDirectory) {
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
}
void AudioManager::SetAudioPlayer(app::AudioPlayer* audioPlayer) {
audioPlayer_ = audioPlayer;
@@ -21,7 +23,7 @@ void AudioManager::SetAudioPlayer(app::AudioPlayer* audioPlayer) {
try {
ExecuteAudioCommand(audioPlayer_, command);
} catch (const std::exception& exc) {
LOG_ERROR("AudioPlayer command execution failed: " + std::string(exc.what()));
sdl3cpp::logging::Logger::GetInstance().Error("AudioPlayer command execution failed: " + std::string(exc.what()));
}
}
pendingAudioCommands_.clear();

View File

@@ -11,6 +11,7 @@
namespace sdl3cpp::script {
GuiManager::GuiManager(lua_State* L) : L_(L) {
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
lua_getglobal(L_, "gui_input");
if (!lua_isnil(L_, -1)) {
guiInputRef_ = luaL_ref(L_, LUA_REGISTRYINDEX);
@@ -35,12 +36,12 @@ std::vector<GuiCommand> GuiManager::LoadGuiCommands() {
if (lua_pcall(L_, 0, 1, 0) != LUA_OK) {
std::string message = GetLuaError();
lua_pop(L_, 1);
LOG_ERROR("Lua get_gui_commands failed: " + message);
sdl3cpp::logging::Logger::GetInstance().Error("Lua get_gui_commands failed: " + message);
throw std::runtime_error("Lua get_gui_commands failed: " + message);
}
if (!lua_istable(L_, -1)) {
lua_pop(L_, 1);
LOG_ERROR("'get_gui_commands' did not return a table");
sdl3cpp::logging::Logger::GetInstance().Error("'get_gui_commands' did not return a table");
throw std::runtime_error("'get_gui_commands' did not return a table");
}
@@ -51,7 +52,7 @@ std::vector<GuiCommand> GuiManager::LoadGuiCommands() {
lua_rawgeti(L_, -1, static_cast<int>(i));
if (!lua_istable(L_, -1)) {
lua_pop(L_, 1);
LOG_ERROR("GUI command at index " + std::to_string(i) + " is not a table");
sdl3cpp::logging::Logger::GetInstance().Error("GUI command at index " + std::to_string(i) + " is not a table");
throw std::runtime_error("GUI command at index " + std::to_string(i) + " is not a table");
}
int commandIndex = lua_gettop(L_);
@@ -59,7 +60,7 @@ std::vector<GuiCommand> GuiManager::LoadGuiCommands() {
const char* typeName = lua_tostring(L_, -1);
if (!typeName) {
lua_pop(L_, 2);
LOG_ERROR("GUI command at index " + std::to_string(i) + " is missing a type");
sdl3cpp::logging::Logger::GetInstance().Error("GUI command at index " + std::to_string(i) + " is missing a type");
throw std::runtime_error("GUI command at index " + std::to_string(i) + " is missing a type");
}
GuiCommand command{};

View File

@@ -10,7 +10,7 @@
namespace sdl3cpp::script {
void LuaBindings::RegisterBindings(lua_State* L, ScriptEngine* engine) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
lua_pushlightuserdata(L, engine);
lua_pushcclosure(L, &LoadMeshFromFile, 1);
lua_setglobal(L, "load_mesh_from_file");
@@ -41,10 +41,10 @@ void LuaBindings::RegisterBindings(lua_State* L, ScriptEngine* engine) {
}
int LuaBindings::LoadMeshFromFile(lua_State* L) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
auto* engine = static_cast<ScriptEngine*>(lua_touserdata(L, lua_upvalueindex(1)));
const char* path = luaL_checkstring(L, 1);
TRACE_VAR(path);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("path", path);
MeshPayload payload;
std::string error;
@@ -60,10 +60,10 @@ int LuaBindings::LoadMeshFromFile(lua_State* L) {
}
int LuaBindings::PhysicsCreateBox(lua_State* L) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
auto* engine = static_cast<ScriptEngine*>(lua_touserdata(L, lua_upvalueindex(1)));
const char* name = luaL_checkstring(L, 1);
TRACE_VAR(name);
sdl3cpp::logging::Logger::GetInstance().TraceVariable("name", name);
if (!lua_istable(L, 2) || !lua_istable(L, 4) || !lua_istable(L, 5)) {
luaL_error(L, "physics_create_box expects vector tables for half extents, origin, and rotation");

View File

@@ -1,4 +1,5 @@
#include "script/physics_bridge.hpp"
#include "logging/logger.hpp"
#include <btBulletDynamicsCommon.h>
@@ -14,6 +15,7 @@ PhysicsBridge::PhysicsBridge()
broadphase_.get(),
solver_.get(),
collisionConfig_.get())) {
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
world_->setGravity(btVector3(0.0f, -9.81f, 0.0f));
}

View File

@@ -1,4 +1,5 @@
#include "script/scene_manager.hpp"
#include "logging/logger.hpp"
#include <lua.hpp>
@@ -8,7 +9,9 @@
namespace sdl3cpp::script {
SceneManager::SceneManager(lua_State* L) : L_(L) {}
SceneManager::SceneManager(lua_State* L) : L_(L) {
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
}
std::vector<SceneManager::SceneObject> SceneManager::LoadSceneObjects() {
lua_getglobal(L_, "get_scene_objects");

View File

@@ -25,13 +25,13 @@ ScriptEngine::ScriptEngine(const std::filesystem::path& scriptPath, bool debugEn
shaderManager_(std::make_unique<ShaderManager>(L_)),
guiManager_(std::make_unique<GuiManager>(L_)),
audioManager_(std::make_unique<AudioManager>(scriptDirectory_)) {
TRACE_FUNCTION();
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);;
if (!L_) {
LOG_ERROR("Failed to create Lua state");
sdl3cpp::logging::Logger::GetInstance().Error("Failed to create Lua state");
throw std::runtime_error("Failed to create Lua state");
}
LOG_DEBUG("Lua state created successfully");
sdl3cpp::logging::Logger::GetInstance().Debug("Lua state created successfully");
luaL_openlibs(L_);
LuaBindings::RegisterBindings(L_, this);
@@ -61,11 +61,11 @@ ScriptEngine::ScriptEngine(const std::filesystem::path& scriptPath, bool debugEn
lua_pop(L_, 1);
lua_close(L_);
L_ = nullptr;
LOG_ERROR("Failed to load Lua script: " + message);
sdl3cpp::logging::Logger::GetInstance().Error("Failed to load Lua script: " + message);
throw std::runtime_error("Failed to load Lua script: " + message);
}
LOG_INFO("Lua script loaded successfully: " + scriptPath.string());
sdl3cpp::logging::Logger::GetInstance().Info("Lua script loaded successfully: " + scriptPath.string());
}
ScriptEngine::~ScriptEngine() {

View File

@@ -1,4 +1,5 @@
#include "script/shader_manager.hpp"
#include "logging/logger.hpp"
#include <lua.hpp>
@@ -8,7 +9,9 @@
namespace sdl3cpp::script {
ShaderManager::ShaderManager(lua_State* L) : L_(L) {}
ShaderManager::ShaderManager(lua_State* L) : L_(L) {
sdl3cpp::logging::TraceGuard trace(__PRETTY_FUNCTION__);
}
std::unordered_map<std::string, ShaderManager::ShaderPaths> ShaderManager::LoadShaderPathsMap() {
lua_getglobal(L_, "get_shader_paths");