mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 14:15:02 +00:00
refactor: Enhance service architecture by introducing IPlatformService and updating dependencies
- Removed core/platform.hpp and core/vulkan_utils.cpp, integrating their functionality into new platform_service implementations. - Updated service registrations to utilize IPlatformService for improved modularity. - Refactored event bus usage across services to leverage IEventBus interface. - Enhanced buffer management in BufferService with detailed logging and error handling. - Updated GUI rendering services to utilize buffer service for resource management. - Cleaned up includes and improved overall code organization for better maintainability.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
#include "service_based_app.hpp"
|
||||
#include "events/event_bus.hpp"
|
||||
#include "events/i_event_bus.hpp"
|
||||
#include "services/interfaces/i_window_service.hpp"
|
||||
#include "services/interfaces/i_graphics_service.hpp"
|
||||
#include "services/impl/json_config_service.hpp"
|
||||
#include "services/impl/platform_service.hpp"
|
||||
#include "services/impl/sdl_window_service.hpp"
|
||||
#include "services/impl/sdl_input_service.hpp"
|
||||
#include "services/impl/vulkan_device_service.hpp"
|
||||
@@ -24,6 +26,7 @@
|
||||
#include "services/impl/bullet_physics_service.hpp"
|
||||
#include "services/impl/crash_recovery_service.hpp"
|
||||
#include "services/impl/logger_service.hpp"
|
||||
#include "services/interfaces/i_platform_service.hpp"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -173,8 +176,12 @@ void ServiceBasedApp::RegisterServices() {
|
||||
registry_.RegisterService<services::ICrashRecoveryService, services::impl::CrashRecoveryService>(
|
||||
registry_.GetService<services::ILogger>());
|
||||
|
||||
// Platform service (needed for SDL error enrichment)
|
||||
registry_.RegisterService<services::IPlatformService, services::impl::PlatformService>(
|
||||
registry_.GetService<services::ILogger>());
|
||||
|
||||
// Event bus (needed by window service)
|
||||
registry_.RegisterService<events::EventBus, events::EventBus>();
|
||||
registry_.RegisterService<events::IEventBus, events::EventBus>();
|
||||
|
||||
// Configuration service
|
||||
services::impl::RuntimeConfig runtimeConfig;
|
||||
@@ -185,11 +192,12 @@ void ServiceBasedApp::RegisterServices() {
|
||||
// Window service
|
||||
registry_.RegisterService<services::IWindowService, services::impl::SdlWindowService>(
|
||||
registry_.GetService<services::ILogger>(),
|
||||
registry_.GetService<events::EventBus>());
|
||||
registry_.GetService<services::IPlatformService>(),
|
||||
registry_.GetService<events::IEventBus>());
|
||||
|
||||
// Input service
|
||||
registry_.RegisterService<services::IInputService, services::impl::SdlInputService>(
|
||||
registry_.GetService<events::EventBus>(),
|
||||
registry_.GetService<events::IEventBus>(),
|
||||
registry_.GetService<services::ILogger>());
|
||||
|
||||
// Audio service (needed before script bindings execute)
|
||||
@@ -237,7 +245,7 @@ void ServiceBasedApp::RegisterServices() {
|
||||
// Swapchain service
|
||||
registry_.RegisterService<services::ISwapchainService, services::impl::SwapchainService>(
|
||||
registry_.GetService<services::IVulkanDeviceService>(),
|
||||
registry_.GetService<events::EventBus>(),
|
||||
registry_.GetService<events::IEventBus>(),
|
||||
registry_.GetService<services::ILogger>());
|
||||
|
||||
// Pipeline service
|
||||
@@ -273,7 +281,8 @@ void ServiceBasedApp::RegisterServices() {
|
||||
|
||||
// GUI service
|
||||
registry_.RegisterService<services::IGuiService, services::impl::VulkanGuiService>(
|
||||
registry_.GetService<services::ILogger>());
|
||||
registry_.GetService<services::ILogger>(),
|
||||
registry_.GetService<services::IBufferService>());
|
||||
|
||||
// Physics service
|
||||
registry_.RegisterService<services::IPhysicsService, services::impl::BulletPhysicsService>(
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "../services/interfaces/i_physics_service.hpp"
|
||||
#include "../services/interfaces/i_scene_service.hpp"
|
||||
#include "../services/interfaces/i_audio_service.hpp"
|
||||
#include "../events/event_bus.hpp"
|
||||
#include "../events/i_event_bus.hpp"
|
||||
#include "../events/event_types.hpp"
|
||||
#include <chrono>
|
||||
|
||||
@@ -60,7 +60,7 @@ void ApplicationController::HandleEvents() {
|
||||
}
|
||||
|
||||
// Check for quit events
|
||||
auto eventBus = registry_.GetService<events::EventBus>();
|
||||
auto eventBus = registry_.GetService<events::IEventBus>();
|
||||
if (eventBus) {
|
||||
// Process queued events
|
||||
eventBus->ProcessQueue();
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef SDL3CPP_CORE_PLATFORM_HPP
|
||||
#define SDL3CPP_CORE_PLATFORM_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::platform {
|
||||
|
||||
// Platform detection
|
||||
#ifdef _WIN32
|
||||
constexpr bool IsWindows = true;
|
||||
constexpr bool IsUnix = false;
|
||||
#else
|
||||
constexpr bool IsWindows = false;
|
||||
constexpr bool IsUnix = true;
|
||||
#endif
|
||||
|
||||
// Get user configuration directory (platform-specific)
|
||||
std::optional<std::filesystem::path> GetUserConfigDirectory();
|
||||
|
||||
// Format platform-specific error messages
|
||||
std::string GetPlatformError();
|
||||
|
||||
} // namespace sdl3cpp::platform
|
||||
|
||||
#endif // SDL3CPP_CORE_PLATFORM_HPP
|
||||
@@ -1,114 +0,0 @@
|
||||
#include "vulkan_utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::vulkan::utils {
|
||||
|
||||
namespace {
|
||||
|
||||
uint32_t FindMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
|
||||
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i) {
|
||||
if ((typeFilter & (1 << i)) &&
|
||||
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Failed to find suitable memory type");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VkExtent2D ChooseSwapExtent(VkSurfaceCapabilitiesKHR capabilities, SDL_Window* window) {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
|
||||
return VkExtent2D{
|
||||
static_cast<uint32_t>(std::clamp(width, static_cast<int>(capabilities.minImageExtent.width),
|
||||
static_cast<int>(capabilities.maxImageExtent.width))),
|
||||
static_cast<uint32_t>(std::clamp(height, static_cast<int>(capabilities.minImageExtent.height),
|
||||
static_cast<int>(capabilities.maxImageExtent.height)))
|
||||
};
|
||||
}
|
||||
|
||||
void CreateBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
|
||||
// Validate buffer size
|
||||
if (size == 0) {
|
||||
throw std::runtime_error("Cannot create buffer with size 0");
|
||||
}
|
||||
|
||||
// Check available memory before allocating
|
||||
VkPhysicalDeviceMemoryProperties memProps;
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);
|
||||
|
||||
uint64_t totalAvailable = 0;
|
||||
for (uint32_t i = 0; i < memProps.memoryHeapCount; ++i) {
|
||||
if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
|
||||
totalAvailable += memProps.memoryHeaps[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > totalAvailable) {
|
||||
throw std::runtime_error("Requested buffer size (" +
|
||||
std::to_string(size / (1024 * 1024)) + " MB) exceeds available GPU memory (" +
|
||||
std::to_string(totalAvailable / (1024 * 1024)) + " MB)");
|
||||
}
|
||||
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
bufferInfo.usage = usage;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VkResult createResult = vkCreateBuffer(device, &bufferInfo, nullptr, &buffer);
|
||||
if (createResult != VK_SUCCESS) {
|
||||
throw std::runtime_error("Failed to create buffer (error code: " +
|
||||
std::to_string(createResult) + ", size: " +
|
||||
std::to_string(size / 1024) + " KB)");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
|
||||
try {
|
||||
allocInfo.memoryTypeIndex =
|
||||
FindMemoryType(physicalDevice, memRequirements.memoryTypeBits, properties);
|
||||
} catch (const std::exception& e) {
|
||||
vkDestroyBuffer(device, buffer, nullptr);
|
||||
throw std::runtime_error(std::string("Failed to find suitable memory type: ") + e.what());
|
||||
}
|
||||
|
||||
VkResult allocResult = vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory);
|
||||
if (allocResult != VK_SUCCESS) {
|
||||
vkDestroyBuffer(device, buffer, nullptr);
|
||||
std::string errorMsg = "Failed to allocate buffer memory.\n";
|
||||
errorMsg += "Requested: " + std::to_string(memRequirements.size / (1024 * 1024)) + " MB\n";
|
||||
errorMsg += "Error code: " + std::to_string(allocResult) + "\n";
|
||||
if (allocResult == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
|
||||
errorMsg += "\nOut of GPU memory. Try:\n";
|
||||
errorMsg += "- Closing other GPU-intensive applications\n";
|
||||
errorMsg += "- Reducing window resolution\n";
|
||||
errorMsg += "- Upgrading GPU or system memory";
|
||||
} else if (allocResult == VK_ERROR_OUT_OF_HOST_MEMORY) {
|
||||
errorMsg += "\nOut of system memory. Try:\n";
|
||||
errorMsg += "- Closing other applications\n";
|
||||
errorMsg += "- Adding more RAM to your system";
|
||||
}
|
||||
throw std::runtime_error(errorMsg);
|
||||
}
|
||||
|
||||
vkBindBufferMemory(device, buffer, bufferMemory, 0);
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::vulkan::utils
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace sdl3cpp::vulkan::utils {
|
||||
|
||||
VkExtent2D ChooseSwapExtent(VkSurfaceCapabilitiesKHR capabilities, SDL_Window* window);
|
||||
|
||||
void CreateBuffer(VkDevice device, VkPhysicalDevice physicalDevice, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory);
|
||||
|
||||
} // namespace sdl3cpp::vulkan::utils
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../di/lifecycle.hpp"
|
||||
#include "event_listener.hpp"
|
||||
#include "event_types.hpp"
|
||||
#include "i_event_bus.hpp"
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
@@ -40,7 +41,7 @@ namespace sdl3cpp::events {
|
||||
* eventBus.ProcessQueue(); // Call once per frame
|
||||
* @endcode
|
||||
*/
|
||||
class EventBus : public di::IInitializable, public di::IShutdownable {
|
||||
class EventBus : public IEventBus, public di::IInitializable, public di::IShutdownable {
|
||||
public:
|
||||
EventBus() = default;
|
||||
~EventBus() = default;
|
||||
@@ -60,7 +61,7 @@ public:
|
||||
* @param type The event type to subscribe to
|
||||
* @param listener The callback function to invoke
|
||||
*/
|
||||
void Subscribe(EventType type, EventListener listener);
|
||||
void Subscribe(EventType type, EventListener listener) override;
|
||||
|
||||
/**
|
||||
* @brief Subscribe to all event types.
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
*
|
||||
* @param listener The callback function to invoke for all events
|
||||
*/
|
||||
void SubscribeAll(EventListener listener);
|
||||
void SubscribeAll(EventListener listener) override;
|
||||
|
||||
/**
|
||||
* @brief Publish an event synchronously.
|
||||
@@ -83,7 +84,7 @@ public:
|
||||
*
|
||||
* @param event The event to publish
|
||||
*/
|
||||
void Publish(const Event& event);
|
||||
void Publish(const Event& event) override;
|
||||
|
||||
/**
|
||||
* @brief Publish an event asynchronously.
|
||||
@@ -96,7 +97,7 @@ public:
|
||||
*
|
||||
* @param event The event to publish
|
||||
*/
|
||||
void PublishAsync(const Event& event);
|
||||
void PublishAsync(const Event& event) override;
|
||||
|
||||
/**
|
||||
* @brief Process all queued asynchronous events.
|
||||
@@ -106,14 +107,14 @@ public:
|
||||
*
|
||||
* Thread-safe: Can be called while other threads are calling PublishAsync().
|
||||
*/
|
||||
void ProcessQueue();
|
||||
void ProcessQueue() override;
|
||||
|
||||
/**
|
||||
* @brief Remove all event listeners.
|
||||
*
|
||||
* Useful for testing or resetting the event bus state.
|
||||
*/
|
||||
void ClearListeners();
|
||||
void ClearListeners() override;
|
||||
|
||||
/**
|
||||
* @brief Get the number of listeners for a specific event type.
|
||||
@@ -121,14 +122,14 @@ public:
|
||||
* @param type The event type to query
|
||||
* @return The number of listeners subscribed to this event type
|
||||
*/
|
||||
size_t GetListenerCount(EventType type) const;
|
||||
size_t GetListenerCount(EventType type) const override;
|
||||
|
||||
/**
|
||||
* @brief Get the number of global listeners.
|
||||
*
|
||||
* @return The number of listeners subscribed to all events
|
||||
*/
|
||||
size_t GetGlobalListenerCount() const;
|
||||
size_t GetGlobalListenerCount() const override;
|
||||
|
||||
// IInitializable interface
|
||||
void Initialize() override {}
|
||||
|
||||
23
src/events/i_event_bus.hpp
Normal file
23
src/events/i_event_bus.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "event_listener.hpp"
|
||||
#include "event_types.hpp"
|
||||
#include <cstddef>
|
||||
|
||||
namespace sdl3cpp::events {
|
||||
|
||||
class IEventBus {
|
||||
public:
|
||||
virtual ~IEventBus() = default;
|
||||
|
||||
virtual void Subscribe(EventType type, EventListener listener) = 0;
|
||||
virtual void SubscribeAll(EventListener listener) = 0;
|
||||
virtual void Publish(const Event& event) = 0;
|
||||
virtual void PublishAsync(const Event& event) = 0;
|
||||
virtual void ProcessQueue() = 0;
|
||||
virtual void ClearListeners() = 0;
|
||||
virtual size_t GetListenerCount(EventType type) const = 0;
|
||||
virtual size_t GetGlobalListenerCount() const = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::events
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "gui/gui_renderer.hpp"
|
||||
|
||||
#include "../core/vulkan_utils.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
@@ -17,7 +15,6 @@
|
||||
#include "../../third_party/font8x8_basic.h"
|
||||
|
||||
namespace script = sdl3cpp::script;
|
||||
namespace vulkan_utils = sdl3cpp::vulkan::utils;
|
||||
|
||||
namespace sdl3cpp::gui {
|
||||
namespace {
|
||||
@@ -350,12 +347,14 @@ private:
|
||||
};
|
||||
|
||||
GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat swapchainFormat,
|
||||
const std::filesystem::path& scriptDirectory)
|
||||
const std::filesystem::path& scriptDirectory,
|
||||
std::shared_ptr<services::IBufferService> bufferService)
|
||||
: device_(device),
|
||||
physicalDevice_(physicalDevice),
|
||||
swapchainFormat_(swapchainFormat),
|
||||
scriptDirectory_(scriptDirectory),
|
||||
canvas_(std::make_unique<Canvas>()) {
|
||||
canvas_(std::make_unique<Canvas>()),
|
||||
bufferService_(std::move(bufferService)) {
|
||||
}
|
||||
|
||||
GuiRenderer::~GuiRenderer() {
|
||||
@@ -516,7 +515,10 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
vulkan_utils::CreateBuffer(device_, physicalDevice_, static_cast<VkDeviceSize>(size),
|
||||
if (!bufferService_) {
|
||||
throw std::runtime_error("Buffer service not available for GUI staging buffer");
|
||||
}
|
||||
bufferService_->CreateBuffer(static_cast<VkDeviceSize>(size),
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||
stagingBuffer_, stagingMemory_);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "script/gui_types.hpp"
|
||||
#include "services/interfaces/i_buffer_service.hpp"
|
||||
|
||||
namespace sdl3cpp::gui {
|
||||
|
||||
@@ -28,7 +29,8 @@ struct ParsedSvg {
|
||||
class GuiRenderer {
|
||||
public:
|
||||
GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat swapchainFormat,
|
||||
const std::filesystem::path& scriptDirectory);
|
||||
const std::filesystem::path& scriptDirectory,
|
||||
std::shared_ptr<services::IBufferService> bufferService);
|
||||
~GuiRenderer();
|
||||
|
||||
GuiRenderer(const GuiRenderer&) = delete;
|
||||
@@ -63,6 +65,7 @@ private:
|
||||
uint32_t canvasHeight_ = 0;
|
||||
std::unique_ptr<Canvas> canvas_;
|
||||
std::unordered_map<std::string, ParsedSvg> svgCache_;
|
||||
std::shared_ptr<services::IBufferService> bufferService_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::gui
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "app/service_based_app.hpp"
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include "services/interfaces/i_logger.hpp"
|
||||
#include "core/platform.hpp"
|
||||
#include "services/impl/platform_service.hpp"
|
||||
|
||||
using namespace sdl3cpp::services;
|
||||
|
||||
@@ -168,7 +168,8 @@ RuntimeConfig LoadRuntimeConfigFromJson(const std::filesystem::path& configPath,
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> GetDefaultConfigPath() {
|
||||
if (auto dir = sdl3cpp::platform::GetUserConfigDirectory()) {
|
||||
sdl3cpp::services::impl::PlatformService platformService;
|
||||
if (auto dir = platformService.GetUserConfigDirectory()) {
|
||||
return *dir / "default_runtime.json";
|
||||
}
|
||||
return std::nullopt;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "buffer_service.hpp"
|
||||
#include "../../core/vulkan_utils.hpp"
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
@@ -97,7 +97,94 @@ void BufferService::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
auto device = deviceService_->GetDevice();
|
||||
auto physicalDevice = deviceService_->GetPhysicalDevice();
|
||||
|
||||
vulkan::utils::CreateBuffer(device, physicalDevice, size, usage, properties, buffer, bufferMemory);
|
||||
if (logger_) {
|
||||
logger_->Debug("Creating buffer with size " + std::to_string(size) + " bytes");
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
if (logger_) {
|
||||
logger_->Error("Cannot create buffer with size 0");
|
||||
}
|
||||
throw std::runtime_error("Cannot create buffer with size 0");
|
||||
}
|
||||
|
||||
VkPhysicalDeviceMemoryProperties memProps;
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);
|
||||
|
||||
uint64_t totalAvailable = 0;
|
||||
for (uint32_t i = 0; i < memProps.memoryHeapCount; ++i) {
|
||||
if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) {
|
||||
totalAvailable += memProps.memoryHeaps[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > totalAvailable) {
|
||||
throw std::runtime_error("Requested buffer size (" +
|
||||
std::to_string(size / (1024 * 1024)) + " MB) exceeds available GPU memory (" +
|
||||
std::to_string(totalAvailable / (1024 * 1024)) + " MB)");
|
||||
}
|
||||
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
bufferInfo.usage = usage;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VkResult createResult = vkCreateBuffer(device, &bufferInfo, nullptr, &buffer);
|
||||
if (createResult != VK_SUCCESS) {
|
||||
throw std::runtime_error("Failed to create buffer (error code: " +
|
||||
std::to_string(createResult) + ", size: " +
|
||||
std::to_string(size / 1024) + " KB)");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
|
||||
bool foundType = false;
|
||||
for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) {
|
||||
if ((memRequirements.memoryTypeBits & (1 << i)) &&
|
||||
(memProps.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
allocInfo.memoryTypeIndex = i;
|
||||
foundType = true;
|
||||
if (logger_) {
|
||||
logger_->Debug("Found suitable memory type: " + std::to_string(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundType) {
|
||||
vkDestroyBuffer(device, buffer, nullptr);
|
||||
if (logger_) {
|
||||
logger_->Error("Failed to find suitable memory type");
|
||||
}
|
||||
throw std::runtime_error("Failed to find suitable memory type");
|
||||
}
|
||||
|
||||
VkResult allocResult = vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory);
|
||||
if (allocResult != VK_SUCCESS) {
|
||||
vkDestroyBuffer(device, buffer, nullptr);
|
||||
std::string errorMsg = "Failed to allocate buffer memory.\n";
|
||||
errorMsg += "Requested: " + std::to_string(memRequirements.size / (1024 * 1024)) + " MB\n";
|
||||
errorMsg += "Error code: " + std::to_string(allocResult) + "\n";
|
||||
if (allocResult == VK_ERROR_OUT_OF_DEVICE_MEMORY) {
|
||||
errorMsg += "\nOut of GPU memory. Try:\n";
|
||||
errorMsg += "- Closing other GPU-intensive applications\n";
|
||||
errorMsg += "- Reducing window resolution\n";
|
||||
errorMsg += "- Upgrading GPU or system memory";
|
||||
} else if (allocResult == VK_ERROR_OUT_OF_HOST_MEMORY) {
|
||||
errorMsg += "\nOut of system memory. Try:\n";
|
||||
errorMsg += "- Closing other applications\n";
|
||||
errorMsg += "- Adding more RAM to your system";
|
||||
}
|
||||
throw std::runtime_error(errorMsg);
|
||||
}
|
||||
|
||||
vkBindBufferMemory(device, buffer, bufferMemory, 0);
|
||||
}
|
||||
|
||||
void BufferService::CleanupBuffers() {
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
#include "core/platform.hpp"
|
||||
#include "platform_service.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace sdl3cpp::platform {
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
std::optional<std::filesystem::path> GetUserConfigDirectory() {
|
||||
PlatformService::PlatformService(std::shared_ptr<ILogger> logger)
|
||||
: logger_(std::move(logger)) {
|
||||
}
|
||||
|
||||
std::optional<std::filesystem::path> PlatformService::GetUserConfigDirectory() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("PlatformService", "GetUserConfigDirectory");
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (const char* appData = std::getenv("APPDATA")) {
|
||||
return std::filesystem::path(appData) / "sdl3cpp";
|
||||
@@ -25,8 +33,7 @@ std::optional<std::filesystem::path> GetUserConfigDirectory() {
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace {
|
||||
std::string FormatWin32Error(DWORD errorCode) {
|
||||
std::string PlatformService::FormatWin32Error(unsigned long errorCode) const {
|
||||
if (errorCode == ERROR_SUCCESS) {
|
||||
return "ERROR_SUCCESS";
|
||||
}
|
||||
@@ -44,7 +51,6 @@ std::string FormatWin32Error(DWORD errorCode) {
|
||||
std::string message;
|
||||
if (length > 0 && buffer != nullptr) {
|
||||
message = std::string(buffer, length);
|
||||
// Remove trailing newlines
|
||||
while (!message.empty() && (message.back() == '\n' || message.back() == '\r')) {
|
||||
message.pop_back();
|
||||
}
|
||||
@@ -54,10 +60,12 @@ std::string FormatWin32Error(DWORD errorCode) {
|
||||
}
|
||||
return message;
|
||||
}
|
||||
} // anonymous namespace
|
||||
#endif
|
||||
|
||||
std::string GetPlatformError() {
|
||||
std::string PlatformService::GetPlatformError() const {
|
||||
if (logger_) {
|
||||
logger_->Trace("PlatformService", "GetPlatformError");
|
||||
}
|
||||
#ifdef _WIN32
|
||||
DWORD win32Error = ::GetLastError();
|
||||
if (win32Error != ERROR_SUCCESS) {
|
||||
@@ -69,4 +77,4 @@ std::string GetPlatformError() {
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::platform
|
||||
} // namespace sdl3cpp::services::impl
|
||||
24
src/services/impl/platform_service.hpp
Normal file
24
src/services/impl/platform_service.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_platform_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
class PlatformService : public IPlatformService {
|
||||
public:
|
||||
explicit PlatformService(std::shared_ptr<ILogger> logger = nullptr);
|
||||
~PlatformService() override = default;
|
||||
|
||||
std::optional<std::filesystem::path> GetUserConfigDirectory() const override;
|
||||
std::string GetPlatformError() const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
#ifdef _WIN32
|
||||
std::string FormatWin32Error(unsigned long errorCode) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -12,7 +12,7 @@ const std::unordered_map<SDL_Keycode, std::string> SdlInputService::kGuiKeyNames
|
||||
{SDLK_RALT, "ralt"}
|
||||
};
|
||||
|
||||
SdlInputService::SdlInputService(std::shared_ptr<events::EventBus> eventBus, std::shared_ptr<ILogger> logger)
|
||||
SdlInputService::SdlInputService(std::shared_ptr<events::IEventBus> eventBus, std::shared_ptr<ILogger> logger)
|
||||
: eventBus_(std::move(eventBus)), logger_(logger) {
|
||||
|
||||
// Subscribe to input events
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "../interfaces/i_input_service.hpp"
|
||||
#include "../interfaces/i_gui_script_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../../events/event_bus.hpp"
|
||||
#include "../../events/i_event_bus.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
@@ -23,7 +23,7 @@ public:
|
||||
*
|
||||
* @param eventBus Event bus to subscribe to
|
||||
*/
|
||||
explicit SdlInputService(std::shared_ptr<events::EventBus> eventBus, std::shared_ptr<ILogger> logger);
|
||||
explicit SdlInputService(std::shared_ptr<events::IEventBus> eventBus, std::shared_ptr<ILogger> logger);
|
||||
|
||||
// IInputService interface
|
||||
void ProcessEvent(const SDL_Event& event) override;
|
||||
@@ -36,7 +36,7 @@ public:
|
||||
void UpdateGuiInput() override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<events::EventBus> eventBus_;
|
||||
std::shared_ptr<events::IEventBus> eventBus_;
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
InputState state_;
|
||||
script::GuiInputSnapshot guiInputSnapshot_;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "sdl_window_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../../core/platform.hpp"
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
@@ -10,7 +9,7 @@ namespace sdl3cpp::services::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string BuildSdlErrorMessage(const char* context) {
|
||||
std::string BuildSdlErrorMessage(const char* context, const std::shared_ptr<IPlatformService>& platformService) {
|
||||
std::ostringstream oss;
|
||||
oss << context;
|
||||
const char* sdlError = SDL_GetError();
|
||||
@@ -20,17 +19,19 @@ std::string BuildSdlErrorMessage(const char* context) {
|
||||
oss << ": (SDL_GetError returned an empty string)";
|
||||
}
|
||||
|
||||
std::string platformError = sdl3cpp::platform::GetPlatformError();
|
||||
if (!platformError.empty() && platformError != "No platform error") {
|
||||
oss << " [" << platformError << "]";
|
||||
if (platformService) {
|
||||
std::string platformError = platformService->GetPlatformError();
|
||||
if (!platformError.empty() && platformError != "No platform error") {
|
||||
oss << " [" << platformError << "]";
|
||||
}
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void ThrowSdlErrorIfFailed(bool success, const char* context) {
|
||||
void ThrowSdlErrorIfFailed(bool success, const char* context, const std::shared_ptr<IPlatformService>& platformService) {
|
||||
if (!success) {
|
||||
throw std::runtime_error(BuildSdlErrorMessage(context));
|
||||
throw std::runtime_error(BuildSdlErrorMessage(context, platformService));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +46,12 @@ void ShowErrorDialog(const char* title, const std::string& message) {
|
||||
|
||||
} // namespace
|
||||
|
||||
SdlWindowService::SdlWindowService(std::shared_ptr<ILogger> logger, std::shared_ptr<events::EventBus> eventBus)
|
||||
: logger_(std::move(logger)), eventBus_(std::move(eventBus)) {
|
||||
SdlWindowService::SdlWindowService(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IPlatformService> platformService,
|
||||
std::shared_ptr<events::IEventBus> eventBus)
|
||||
: logger_(std::move(logger)),
|
||||
platformService_(std::move(platformService)),
|
||||
eventBus_(std::move(eventBus)) {
|
||||
}
|
||||
|
||||
SdlWindowService::~SdlWindowService() {
|
||||
@@ -101,7 +106,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) {
|
||||
// Initialize SDL here if not already initialized
|
||||
if (SDL_WasInit(0) == 0) {
|
||||
try {
|
||||
ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed");
|
||||
ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed", platformService_);
|
||||
} catch (const std::exception& e) {
|
||||
ShowErrorDialog("SDL Initialization Failed",
|
||||
std::string("Failed to initialize SDL subsystems.\n\nError: ") + e.what());
|
||||
@@ -109,7 +114,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) {
|
||||
}
|
||||
|
||||
try {
|
||||
ThrowSdlErrorIfFailed(SDL_Vulkan_LoadLibrary(nullptr), "SDL_Vulkan_LoadLibrary failed");
|
||||
ThrowSdlErrorIfFailed(SDL_Vulkan_LoadLibrary(nullptr), "SDL_Vulkan_LoadLibrary failed", platformService_);
|
||||
} catch (const std::exception& e) {
|
||||
ShowErrorDialog("Vulkan Library Load Failed",
|
||||
std::string("Failed to load Vulkan library. Make sure Vulkan drivers are installed.\n\nError: ") + e.what());
|
||||
@@ -130,7 +135,7 @@ void SdlWindowService::CreateWindow(const WindowConfig& config) {
|
||||
);
|
||||
|
||||
if (!window_) {
|
||||
std::string errorMsg = BuildSdlErrorMessage("SDL_CreateWindow failed");
|
||||
std::string errorMsg = BuildSdlErrorMessage("SDL_CreateWindow failed", platformService_);
|
||||
ShowErrorDialog("Window Creation Failed",
|
||||
std::string("Failed to create application window.\n\nError: ") + errorMsg);
|
||||
throw std::runtime_error(errorMsg);
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
#include "../interfaces/i_window_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../interfaces/i_platform_service.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include "../../events/event_bus.hpp"
|
||||
#include "../../events/i_event_bus.hpp"
|
||||
#include <memory>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
@@ -25,7 +26,9 @@ public:
|
||||
* @param logger Logger service for logging
|
||||
* @param eventBus Event bus for publishing window/input events
|
||||
*/
|
||||
SdlWindowService(std::shared_ptr<ILogger> logger, std::shared_ptr<events::EventBus> eventBus);
|
||||
SdlWindowService(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IPlatformService> platformService,
|
||||
std::shared_ptr<events::IEventBus> eventBus);
|
||||
|
||||
~SdlWindowService() override;
|
||||
|
||||
@@ -47,7 +50,8 @@ public:
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<events::EventBus> eventBus_;
|
||||
std::shared_ptr<IPlatformService> platformService_;
|
||||
std::shared_ptr<events::IEventBus> eventBus_;
|
||||
SDL_Window* window_ = nullptr;
|
||||
bool shouldClose_ = false;
|
||||
bool initialized_ = false;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
SwapchainService::SwapchainService(std::shared_ptr<IVulkanDeviceService> deviceService,
|
||||
std::shared_ptr<events::EventBus> eventBus,
|
||||
std::shared_ptr<events::IEventBus> eventBus,
|
||||
std::shared_ptr<ILogger> logger)
|
||||
: deviceService_(std::move(deviceService)), eventBus_(std::move(eventBus)), logger_(logger) {
|
||||
// Subscribe to window resize events
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "../interfaces/i_vulkan_device_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include "../../events/event_bus.hpp"
|
||||
#include "../../events/i_event_bus.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -21,7 +21,7 @@ class SwapchainService : public ISwapchainService,
|
||||
public di::IShutdownable {
|
||||
public:
|
||||
explicit SwapchainService(std::shared_ptr<IVulkanDeviceService> deviceService,
|
||||
std::shared_ptr<events::EventBus> eventBus,
|
||||
std::shared_ptr<events::IEventBus> eventBus,
|
||||
std::shared_ptr<ILogger> logger);
|
||||
~SwapchainService() override;
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
|
||||
private:
|
||||
std::shared_ptr<IVulkanDeviceService> deviceService_;
|
||||
std::shared_ptr<events::EventBus> eventBus_;
|
||||
std::shared_ptr<events::IEventBus> eventBus_;
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
|
||||
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
VulkanGuiService::VulkanGuiService(std::shared_ptr<ILogger> logger)
|
||||
: logger_(std::move(logger)) {
|
||||
VulkanGuiService::VulkanGuiService(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IBufferService> bufferService)
|
||||
: logger_(std::move(logger)),
|
||||
bufferService_(std::move(bufferService)) {
|
||||
}
|
||||
|
||||
VulkanGuiService::~VulkanGuiService() {
|
||||
@@ -24,7 +26,7 @@ void VulkanGuiService::Initialize(VkDevice device,
|
||||
return;
|
||||
}
|
||||
|
||||
renderer_ = std::make_unique<gui::GuiRenderer>(device, physicalDevice, format, resourcePath);
|
||||
renderer_ = std::make_unique<gui::GuiRenderer>(device, physicalDevice, format, resourcePath, bufferService_);
|
||||
initialized_ = true;
|
||||
|
||||
logger_->Info("GUI service initialized");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../interfaces/i_gui_service.hpp"
|
||||
#include "../interfaces/i_buffer_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../../gui/gui_renderer.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
@@ -17,7 +18,8 @@ namespace sdl3cpp::services::impl {
|
||||
class VulkanGuiService : public IGuiService,
|
||||
public di::IShutdownable {
|
||||
public:
|
||||
explicit VulkanGuiService(std::shared_ptr<ILogger> logger);
|
||||
VulkanGuiService(std::shared_ptr<ILogger> logger,
|
||||
std::shared_ptr<IBufferService> bufferService);
|
||||
~VulkanGuiService() override;
|
||||
|
||||
// IGuiService interface
|
||||
@@ -38,6 +40,7 @@ public:
|
||||
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IBufferService> bufferService_;
|
||||
std::unique_ptr<gui::GuiRenderer> renderer_;
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
17
src/services/interfaces/i_platform_service.hpp
Normal file
17
src/services/interfaces/i_platform_service.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace sdl3cpp::services {
|
||||
|
||||
class IPlatformService {
|
||||
public:
|
||||
virtual ~IPlatformService() = default;
|
||||
|
||||
virtual std::optional<std::filesystem::path> GetUserConfigDirectory() const = 0;
|
||||
virtual std::string GetPlatformError() const = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services
|
||||
Reference in New Issue
Block a user