diff --git a/README.md b/README.md index 2f99e3d..d08e6ed 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ ###### MacroLibX, a rewrite of 42 School's MiniLibX using SDL2 and Vulkan. The goal of this version is to provide a light, fast, and modern graphical tool while keeping the same API. -## đŸ’Ģ Features +## 🌟 Features -### 🏁 Performances +### 🚀 Performances Built on top of Vulkan, the MacroLibX takes advantage of its very low-level nature to achieve high performance with great control over available resources. ### đŸ’ģ Cross-Platform @@ -27,6 +27,12 @@ One of the guidelines of this lib was to get as close as possible to the old min ### 📖 It's all FOSS Everything in this repo is entirely free and open source, all available under the MIT license (even the third-party libraries used). +### 🔍 Valgrind suppressions file +Experimental for now, a [suppressions file for valgrind](./valgrind.supp) is given to remove potential leaks comming from Xorg, Nvidia drivers, SDL2, or any other tool which the user has no control. It is far from perfect at the moment and may allow some leaks but it will block the majority. + +### ⛔ Error system +Strong error handling informing the user of problems with their code and even capable of informing them of graphics memory leaks that tools like Valgrind cannot detect. + ## đŸ–Ĩī¸ Installation ### Dependencies @@ -101,5 +107,4 @@ You can force the mlx to use your integrated GPU by using `make FORCE_INTEGRATED The mlx can dump it's graphics memory use to json files every two seconds by enabling this option `make GRAPHICS_MEMORY_DUMP=true`. ## License - -This project and all its files, except the [`third_party`](./third_party) directory or unless otherwise mentionned, are licenced under the [MIT license](./LICENSE). +This project and all its files, even the [`third_party`](./third_party) directory or unless otherwise mentionned, are licenced under the [MIT license](./LICENSE). diff --git a/includes/mlx_profile.h b/includes/mlx_profile.h index 5f6f527..5a06edb 100644 --- a/includes/mlx_profile.h +++ b/includes/mlx_profile.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/11/10 08:49:17 by maldavid #+# #+# */ -/* Updated: 2023/12/11 20:35:57 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/16 20:20:35 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -50,19 +50,49 @@ #elif defined(unix) || defined(__unix__) || defined(__unix) #define MLX_PLAT_UNIX #else - #error "Unknown environment!" + #error "Unknown environment (not Windows, not Linux, not MacOS, not Unix)" #endif -#ifdef MLX_COMPILER_MSVC - #ifdef MLX_BUILD - #define MLX_API __declspec(dllexport) +#ifdef MLX_PLAT_WINDOWS + #ifdef MLX_COMPILER_MSVC + #ifdef MLX_BUILD + #define MLX_API __declspec(dllexport) + #else + #define MLX_API __declspec(dllimport) + #endif + #elif defined(MLX_COMPILER_GCC) + #ifdef MLX_BUILD + #define MLX_API __attribute__((dllexport)) + #else + #define MLX_API __attribute__((dllimport)) + #endif #else - #define MLX_API __declspec(dllimport) + #define MLX_API #endif +#elif defined(MLX_COMPILER_GCC) + #define MLX_API __attribute__((visibility("default"))) #else #define MLX_API #endif +#if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) || defined(__ghs__) + #define MLX_FUNC_SIG __PRETTY_FUNCTION__ +#elif defined(__DMC__) && (__DMC__ >= 0x810) + #define MLX_FUNC_SIG __PRETTY_FUNCTION__ +#elif (defined(__FUNCSIG__) || (_MSC_VER)) + #define MLX_FUNC_SIG __FUNCSIG__ +#elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500)) + #define MLX_FUNC_SIG __FUNCTION__ +#elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550) + #define MLX_FUNC_SIG __FUNC__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) + #define MLX_FUNC_SIG __func__ +#elif defined(__cplusplus) && (__cplusplus >= 201103) + #define MLX_FUNC_SIG __func__ +#else + #define MLX_FUNC_SIG "Unknown function" +#endif + // Checking common assumptions #ifdef __cplusplus #include diff --git a/src/core/application.inl b/src/core/application.inl index 3fd33c0..d9c367a 100644 --- a/src/core/application.inl +++ b/src/core/application.inl @@ -88,14 +88,32 @@ namespace mlx::core int Application::getTexturePixel(void* img, int x, int y) { + if(img == nullptr) + { + core::error::report(e_kind::error, "wrong texture (NULL)"); + return 0; + } Texture* texture = static_cast(img); + if(!texture->isInit()) + { + core::error::report(e_kind::error, "trying to get a pixel from texture that has been destroyed"); + return 0; + } return texture->getPixel(x, y); } void Application::setTexturePixel(void* img, int x, int y, uint32_t color) { + if(img == nullptr) + { + core::error::report(e_kind::error, "wrong texture (NULL)"); + return; + } Texture* texture = static_cast(img); - texture->setPixel(x, y, color); + if(!texture->isInit()) + core::error::report(e_kind::error, "trying to set a pixel on texture that has been destroyed"); + else + texture->setPixel(x, y, color); } void Application::loopHook(int (*f)(void*), void* param) diff --git a/src/core/bridge.cpp b/src/core/bridge.cpp index 4091d3a..44d723f 100644 --- a/src/core/bridge.cpp +++ b/src/core/bridge.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/04 17:35:20 by maldavid #+# #+# */ -/* Updated: 2023/12/14 17:47:17 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 20:20:41 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,13 +17,20 @@ #include #include #include +#include + +static void* __mlx_ptr = nullptr; + +#define MLX_CHECK_APPLICATION_POINTER(ptr) \ + if(ptr != __mlx_ptr || ptr == NULL) \ + mlx::core::error::report(e_kind::fatal_error, "invalid mlx pointer passed to '%s'", MLX_FUNC_SIG); \ + else {} // just to avoid issues with possible if-else statements outside this macro extern "C" { void* mlx_init() { - static bool init = false; - if(init) + if(__mlx_ptr != nullptr) { mlx::core::error::report(e_kind::error, "MLX cannot be initialized multiple times"); return NULL; // not nullptr for the C compatibility @@ -33,29 +40,33 @@ extern "C" mlx::Render_Core::get().init(); if(app == nullptr) mlx::core::error::report(e_kind::fatal_error, "Tout a pÊtÊ"); - init = true; - return static_cast(app); + __mlx_ptr = static_cast(app); + return __mlx_ptr; } void* mlx_new_window(void* mlx, int w, int h, const char* title) { + MLX_CHECK_APPLICATION_POINTER(mlx); return static_cast(mlx)->newGraphicsSuport(w, h, title); } int mlx_loop_hook(void* mlx, int (*f)(void*), void* param) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->loopHook(f, param); return 0; } int mlx_loop(void* mlx) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->run(); return 0; } int mlx_loop_end(void* mlx) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->loopEnd(); return 0; } @@ -72,34 +83,40 @@ extern "C" int mlx_mouse_move(void* mlx, void* win, int x, int y) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->mouseMove(win, x, y); return 0; } int mlx_mouse_get_pos(void* mlx, int* x, int* y) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->getMousePos(x, y); return 0; } int mlx_on_event(void* mlx, void* win, mlx_event_type event, int (*funct_ptr)(int, void*), void* param) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->onEvent(win, static_cast(event), funct_ptr, param); return 0; } void* mlx_new_image(void* mlx, int width, int height) { + MLX_CHECK_APPLICATION_POINTER(mlx); return static_cast(mlx)->newTexture(width, height); } int mlx_get_image_pixel(void* mlx, void* img, int x, int y) { + MLX_CHECK_APPLICATION_POINTER(mlx); return static_cast(mlx)->getTexturePixel(img, x, y); } void mlx_set_image_pixel(void* mlx, void* img, int x, int y, int color) { + MLX_CHECK_APPLICATION_POINTER(mlx); unsigned char color_bits[4]; color_bits[0] = (color & 0x00FF0000) >> 16; color_bits[1] = (color & 0x0000FF00) >> 8; @@ -110,18 +127,21 @@ extern "C" int mlx_put_image_to_window(void* mlx, void* win, void* img, int x, int y) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->texturePut(win, img, x, y); return 0; } int mlx_destroy_image(void* mlx, void* img) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->destroyTexture(img); return 0; } void* mlx_png_file_to_image(void* mlx, char* filename, int* width, int* height) { + MLX_CHECK_APPLICATION_POINTER(mlx); std::filesystem::path file(filename); if(file.extension() != ".png") { @@ -133,6 +153,7 @@ extern "C" void* mlx_jpg_file_to_image(void* mlx, char* filename, int* width, int* height) { + MLX_CHECK_APPLICATION_POINTER(mlx); std::filesystem::path file(filename); if(file.extension() != ".jpg" && file.extension() != ".jpeg") { @@ -144,6 +165,7 @@ extern "C" void* mlx_bmp_file_to_image(void* mlx, char* filename, int* width, int* height) { + MLX_CHECK_APPLICATION_POINTER(mlx); std::filesystem::path file(filename); if(file.extension() != ".bmp" && file.extension() != ".dib") { @@ -155,6 +177,7 @@ extern "C" int mlx_pixel_put(void* mlx, void* win, int x, int y, int color) { + MLX_CHECK_APPLICATION_POINTER(mlx); unsigned char color_bits[4]; color_bits[0] = (color & 0x00FF0000) >> 16; color_bits[1] = (color & 0x0000FF00) >> 8; @@ -166,6 +189,7 @@ extern "C" int mlx_string_put(void* mlx, void* win, int x, int y, int color, char* str) { + MLX_CHECK_APPLICATION_POINTER(mlx); unsigned char color_bits[4]; color_bits[0] = (color & 0x00FF0000) >> 16; color_bits[1] = (color & 0x0000FF00) >> 8; @@ -177,6 +201,7 @@ extern "C" void mlx_set_font(void* mlx, void* win, char* filepath) { + MLX_CHECK_APPLICATION_POINTER(mlx); std::filesystem::path file(filepath); if(std::strcmp(filepath, "default") != 0 && file.extension() != ".ttf" && file.extension() != ".tte") { @@ -188,6 +213,7 @@ extern "C" void mlx_set_font_scale(void* mlx, void* win, char* filepath, float scale) { + MLX_CHECK_APPLICATION_POINTER(mlx); std::filesystem::path file(filepath); if(std::strcmp(filepath, "default") != 0 && file.extension() != ".ttf" && file.extension() != ".tte") { @@ -199,25 +225,30 @@ extern "C" int mlx_clear_window(void* mlx, void* win) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->clearGraphicsSupport(win); return 0; } int mlx_destroy_window(void* mlx, void* win) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->destroyGraphicsSupport(win); return 0; } int mlx_destroy_display(void* mlx) { + MLX_CHECK_APPLICATION_POINTER(mlx); delete static_cast(mlx); mlx::Render_Core::get().destroy(); + __mlx_ptr = nullptr; return 0; } int mlx_get_screens_size(void* mlx, int* w, int* h) { + MLX_CHECK_APPLICATION_POINTER(mlx); static_cast(mlx)->getScreenSize(w, h); return 0; } diff --git a/src/renderer/buffers/vk_buffer.cpp b/src/renderer/buffers/vk_buffer.cpp index a98bb74..903de12 100644 --- a/src/renderer/buffers/vk_buffer.cpp +++ b/src/renderer/buffers/vk_buffer.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/08 18:55:57 by maldavid #+# #+# */ -/* Updated: 2023/12/12 22:11:47 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/16 17:10:17 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -97,22 +97,15 @@ namespace mlx } // TODO, use global cmd buffer pool to manage resources - CmdPool cmdpool; - cmdpool.init(); - CmdBuffer cmdBuffer; - cmdBuffer.init(&cmdpool); - - cmdBuffer.beginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer(); + cmd.beginRecord(); VkBufferCopy copyRegion{}; copyRegion.size = _size; - vkCmdCopyBuffer(cmdBuffer.get(), buffer._buffer, _buffer, 1, ©Region); + vkCmdCopyBuffer(cmd.get(), buffer._buffer, _buffer, 1, ©Region); - cmdBuffer.endRecord(); - cmdBuffer.submitIdle(); - - cmdBuffer.destroy(); - cmdpool.destroy(); + cmd.endRecord(); + cmd.submitIdle(); return true; } diff --git a/src/renderer/command/single_time_cmd_manager.cpp b/src/renderer/command/single_time_cmd_manager.cpp index c64f445..7d1ffc8 100644 --- a/src/renderer/command/single_time_cmd_manager.cpp +++ b/src/renderer/command/single_time_cmd_manager.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/12/15 19:57:49 by maldavid #+# #+# */ -/* Updated: 2023/12/15 20:21:54 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 18:46:26 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -22,7 +22,24 @@ namespace mlx { _pool.init(); for(int i = 0; i < MIN_POOL_SIZE; i++) - _buffers.emplace_back().init(&_pool); + { + _buffers.emplace_back(); + _buffers.back().init(&_pool); + } + } + + CmdBuffer& SingleTimeCmdManager::getCmdBuffer() noexcept + { + for(CmdBuffer& buf : _buffers) + { + if(buf.isReadyToBeUsed()) + { + buf.reset(); + return buf; + } + } + _buffers.emplace_back().init(&_pool); + return _buffers.back(); } void SingleTimeCmdManager::destroy() noexcept @@ -33,15 +50,4 @@ namespace mlx }); _pool.destroy(); } - - CmdBuffer& SingleTimeCmdManager::getCmdBuffer() noexcept - { - for(CmdBuffer& buf : _buffers) - { - if(buf.isReadyToBeUsed()) - return buf; - } - _buffers.emplace_back().init(&_pool); - return _buffers.back(); - } } diff --git a/src/renderer/command/single_time_cmd_manager.h b/src/renderer/command/single_time_cmd_manager.h index a05dca3..bf08869 100644 --- a/src/renderer/command/single_time_cmd_manager.h +++ b/src/renderer/command/single_time_cmd_manager.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/12/15 18:25:57 by maldavid #+# #+# */ -/* Updated: 2023/12/15 19:59:40 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 18:09:56 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -35,6 +35,8 @@ namespace mlx inline static constexpr const uint8_t MIN_POOL_SIZE = 8; + private: + private: std::vector _buffers; CmdPool _pool; diff --git a/src/renderer/command/vk_cmd_buffer.cpp b/src/renderer/command/vk_cmd_buffer.cpp index 143b9b2..e417508 100644 --- a/src/renderer/command/vk_cmd_buffer.cpp +++ b/src/renderer/command/vk_cmd_buffer.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/06 18:26:06 by maldavid #+# #+# */ -/* Updated: 2023/11/08 20:17:49 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 18:51:03 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -39,11 +39,14 @@ namespace mlx #endif _fence.init(); + _state = state::idle; } void CmdBuffer::beginRecord(VkCommandBufferUsageFlags usage) { - if(_is_recording) + if(!isInit()) + core::error::report(e_kind::fatal_error, "Vulkan : begenning record on un uninit command buffer"); + if(_state == state::recording) return; VkCommandBufferBeginInfo beginInfo{}; @@ -52,17 +55,19 @@ namespace mlx if(vkBeginCommandBuffer(_cmd_buffer, &beginInfo) != VK_SUCCESS) core::error::report(e_kind::fatal_error, "Vulkan : failed to begin recording command buffer"); - _is_recording = true; + _state = state::recording; } void CmdBuffer::endRecord() { - if(!_is_recording) + if(!isInit()) + core::error::report(e_kind::fatal_error, "Vulkan : ending record on un uninit command buffer"); + if(_state != state::recording) return; if(vkEndCommandBuffer(_cmd_buffer) != VK_SUCCESS) core::error::report(e_kind::fatal_error, "Vulkan : failed to end recording command buffer"); - _is_recording = false; + _state = state::idle; } void CmdBuffer::submitIdle() noexcept @@ -83,6 +88,8 @@ namespace mlx vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, fence); vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX); vkDestroyFence(device, fence, nullptr); + _state = state::submitted; + _state = state::ready; } void CmdBuffer::submit(Semaphore& semaphores) noexcept @@ -103,11 +110,13 @@ namespace mlx if(vkQueueSubmit(Render_Core::get().getQueue().getGraphic(), 1, &submitInfo, _fence.get()) != VK_SUCCESS) core::error::report(e_kind::fatal_error, "Vulkan error : failed to submit draw command buffer"); + _state = state::submitted; } void CmdBuffer::destroy() noexcept { _fence.destroy(); _cmd_buffer = VK_NULL_HANDLE; + _state = state::uninit; } } diff --git a/src/renderer/command/vk_cmd_buffer.h b/src/renderer/command/vk_cmd_buffer.h index bc8e653..f3fe39d 100644 --- a/src/renderer/command/vk_cmd_buffer.h +++ b/src/renderer/command/vk_cmd_buffer.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/06 18:25:42 by maldavid #+# #+# */ -/* Updated: 2023/12/15 20:19:42 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 18:44:48 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -21,6 +21,16 @@ namespace mlx { class CmdBuffer { + public: + enum class state + { + uninit = 0, // buffer not initialized or destroyed + ready, // buffer ready to be used after having been submitted + idle, // buffer has recorded informations but has not been submitted + recording, // buffer is currently recording + submitted, // buffer has been submitted + }; + public: void init(class CmdManager* manager); void init(class CmdPool* pool); @@ -29,13 +39,15 @@ namespace mlx void beginRecord(VkCommandBufferUsageFlags usage = 0); void submit(class Semaphore& semaphores) noexcept; void submitIdle() noexcept; - inline void waitForExecution() noexcept { _fence.waitAndReset(); } + inline void waitForExecution() noexcept { _fence.waitAndReset(); _state = state::ready; } inline void reset() noexcept { vkResetCommandBuffer(_cmd_buffer, 0); } - inline bool isReadyToBeUsed() const noexcept { return _fence.isReady(); } void endRecord(); - inline bool isRecording() const noexcept { return _is_recording; } - inline bool isInit() const noexcept { return _cmd_buffer != VK_NULL_HANDLE; } + inline bool isInit() const noexcept { return _state != state::uninit; } + inline bool isReadyToBeUsed() const noexcept { return _state == state::ready; } + inline bool isRecording() const noexcept { return _state == state::recording; } + inline bool hasBeenSubmitted() const noexcept { return _state == state::submitted; } + inline state getCurrentState() const noexcept { return _state; } inline VkCommandBuffer& operator()() noexcept { return _cmd_buffer; } inline VkCommandBuffer& get() noexcept { return _cmd_buffer; } @@ -45,7 +57,7 @@ namespace mlx Fence _fence; VkCommandBuffer _cmd_buffer = VK_NULL_HANDLE; class CmdPool* _pool = nullptr; - bool _is_recording = false; + state _state = state::uninit; }; } diff --git a/src/renderer/core/memory.cpp b/src/renderer/core/memory.cpp index 9e2d9b7..5ff7c67 100644 --- a/src/renderer/core/memory.cpp +++ b/src/renderer/core/memory.cpp @@ -6,7 +6,7 @@ /* By: kbz_8 +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/10/20 22:02:37 by kbz_8 #+# #+# */ -/* Updated: 2023/12/10 22:44:55 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/16 19:14:15 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,7 +17,11 @@ #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 #define VMA_VULKAN_VERSION 1002000 -#define VMA_ASSERT(expr) (static_cast(expr) ? void(0) : mlx::core::error::report(e_kind::fatal_error, "Graphics allocator : an assertion has been catched : '%s'", #expr)) +#ifdef DEBUG + #define VMA_ASSERT(expr) (static_cast(expr) ? void(0) : mlx::core::error::report(e_kind::fatal_error, "Graphics allocator : an assertion has been catched : '%s'", #expr)) +#else + #define VMA_ASSERT(expr) ((void)0) +#endif #define VMA_IMPLEMENTATION #ifdef MLX_COMPILER_CLANG @@ -93,6 +97,7 @@ namespace mlx #ifdef DEBUG core::error::report(e_kind::message, "Graphics Allocator : created new buffer"); #endif + _active_buffers_allocations++; return allocation; } @@ -103,6 +108,7 @@ namespace mlx #ifdef DEBUG core::error::report(e_kind::message, "Graphics Allocator : destroyed buffer"); #endif + _active_buffers_allocations--; } VmaAllocation GPUallocator::createImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name) noexcept @@ -115,6 +121,7 @@ namespace mlx #ifdef DEBUG core::error::report(e_kind::message, "Graphics Allocator : created new image"); #endif + _active_images_allocations++; return allocation; } @@ -125,6 +132,7 @@ namespace mlx #ifdef DEBUG core::error::report(e_kind::message, "Graphics Allocator : destroyed image"); #endif + _active_images_allocations--; } void GPUallocator::mapMemory(VmaAllocation allocation, void** data) noexcept @@ -164,6 +172,10 @@ namespace mlx void GPUallocator::destroy() noexcept { + if(_active_images_allocations != 0) + core::error::report(e_kind::error, "Graphics allocator : some user-dependant allocations were not freed before destroying the display (%d active allocations)", _active_images_allocations); + else if(_active_buffers_allocations != 0) + core::error::report(e_kind::error, "Graphics allocator : some MLX-dependant allocations were not freed before destroying the display (%d active allocations), please report, this should not happen", _active_buffers_allocations); vmaDestroyAllocator(_allocator); } } diff --git a/src/renderer/core/memory.h b/src/renderer/core/memory.h index 71e5974..363056d 100644 --- a/src/renderer/core/memory.h +++ b/src/renderer/core/memory.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/10/20 02:13:03 by maldavid #+# #+# */ -/* Updated: 2023/12/08 19:07:34 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/16 18:53:51 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -44,6 +44,8 @@ namespace mlx private: VmaAllocator _allocator; + uint32_t _active_buffers_allocations = 0; + uint32_t _active_images_allocations = 0; }; } diff --git a/src/renderer/core/vk_fence.cpp b/src/renderer/core/vk_fence.cpp index 7b58f58..bad8872 100644 --- a/src/renderer/core/vk_fence.cpp +++ b/src/renderer/core/vk_fence.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */ -/* Updated: 2023/12/15 20:31:29 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 18:47:36 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -23,7 +23,7 @@ namespace mlx VkResult res; if((res = vkCreateFence(Render_Core::get().getDevice().get(), &fenceInfo, nullptr, &_fence)) != VK_SUCCESS) - core::error::report(e_kind::fatal_error, "Vulkan : failed to create CPU synchronization object, %s", RCore::verbaliseResultVk(res)); + core::error::report(e_kind::fatal_error, "Vulkan : failed to create a synchronization object (fence), %s", RCore::verbaliseResultVk(res)); #ifdef DEBUG core::error::report(e_kind::message, "Vulkan : created new fence"); #endif diff --git a/src/renderer/core/vk_fence.h b/src/renderer/core/vk_fence.h index ec5c8a1..aa7c685 100644 --- a/src/renderer/core/vk_fence.h +++ b/src/renderer/core/vk_fence.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/04/02 17:52:09 by maldavid #+# #+# */ -/* Updated: 2023/12/15 20:31:25 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 17:27:28 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/src/renderer/core/vk_semaphore.cpp b/src/renderer/core/vk_semaphore.cpp index 59234eb..604d215 100644 --- a/src/renderer/core/vk_semaphore.cpp +++ b/src/renderer/core/vk_semaphore.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/08 19:01:08 by maldavid #+# #+# */ -/* Updated: 2023/12/12 15:51:37 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/16 18:47:29 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -24,7 +24,7 @@ namespace mlx VkResult res; if( (res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_imageAvailableSemaphores)) != VK_SUCCESS || (res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_renderFinishedSemaphores)) != VK_SUCCESS) - core::error::report(e_kind::fatal_error, "Vulkan : failed to create GPU synchronization object, %s", RCore::verbaliseResultVk(res)); + core::error::report(e_kind::fatal_error, "Vulkan : failed to create a synchronization object (semaphore), %s", RCore::verbaliseResultVk(res)); #ifdef DEBUG core::error::report(e_kind::message, "Vulkan : created new semaphore"); #endif diff --git a/src/renderer/images/vk_image.cpp b/src/renderer/images/vk_image.cpp index ddd6315..54e3ecf 100644 --- a/src/renderer/images/vk_image.cpp +++ b/src/renderer/images/vk_image.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/01/25 11:59:07 by maldavid #+# #+# */ -/* Updated: 2023/11/18 17:21:14 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 17:10:33 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -167,8 +167,6 @@ namespace mlx } _allocation = Render_Core::get().getAllocator().createImage(&imageInfo, &alloc_info, _image, name); - - _pool.init(); } void Image::createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept @@ -209,11 +207,8 @@ namespace mlx void Image::copyFromBuffer(Buffer& buffer) { - if(!_transfer_cmd.isInit()) - _transfer_cmd.init(&_pool); - - _transfer_cmd.reset(); - _transfer_cmd.beginRecord(); + CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer(); + cmd.beginRecord(); VkImageMemoryBarrier copy_barrier{}; copy_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -226,7 +221,7 @@ namespace mlx copy_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier.subresourceRange.levelCount = 1; copy_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, ©_barrier); + vkCmdPipelineBarrier(cmd.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, ©_barrier); VkBufferImageCopy region{}; region.bufferOffset = 0; @@ -239,7 +234,7 @@ namespace mlx region.imageOffset = { 0, 0, 0 }; region.imageExtent = { _width, _height, 1 }; - vkCmdCopyBufferToImage(_transfer_cmd.get(), buffer.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(cmd.get(), buffer.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier{}; use_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -253,19 +248,16 @@ namespace mlx use_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier.subresourceRange.levelCount = 1; use_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &use_barrier); + vkCmdPipelineBarrier(cmd.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &use_barrier); - _transfer_cmd.endRecord(); - _transfer_cmd.submitIdle(); + cmd.endRecord(); + cmd.submitIdle(); } void Image::copyToBuffer(Buffer& buffer) { - if(!_transfer_cmd.isInit()) - _transfer_cmd.init(&_pool); - - _transfer_cmd.reset(); - _transfer_cmd.beginRecord(); + CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer(); + cmd.beginRecord(); VkImageMemoryBarrier copy_barrier{}; copy_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -278,7 +270,7 @@ namespace mlx copy_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier.subresourceRange.levelCount = 1; copy_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, ©_barrier); + vkCmdPipelineBarrier(cmd.get(), VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, ©_barrier); VkBufferImageCopy region{}; region.bufferOffset = 0; @@ -291,7 +283,7 @@ namespace mlx region.imageOffset = { 0, 0, 0 }; region.imageExtent = { _width, _height, 1 }; - vkCmdCopyImageToBuffer(_transfer_cmd.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer.get(), 1, ®ion); + vkCmdCopyImageToBuffer(cmd.get(), _image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer.get(), 1, ®ion); VkImageMemoryBarrier use_barrier{}; use_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -305,10 +297,10 @@ namespace mlx use_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier.subresourceRange.levelCount = 1; use_barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(_transfer_cmd.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &use_barrier); + vkCmdPipelineBarrier(cmd.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &use_barrier); - _transfer_cmd.endRecord(); - _transfer_cmd.submitIdle(); + cmd.endRecord(); + cmd.submitIdle(); } void Image::transitionLayout(VkImageLayout new_layout) @@ -316,10 +308,8 @@ namespace mlx if(new_layout == _layout) return; - if(!_transfer_cmd.isInit()) - _transfer_cmd.init(&_pool); - _transfer_cmd.reset(); - _transfer_cmd.beginRecord(); + CmdBuffer& cmd = Render_Core::get().getSingleTimeCmdBuffer(); + cmd.beginRecord(); VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -354,10 +344,10 @@ namespace mlx else destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - vkCmdPipelineBarrier(_transfer_cmd.get(), sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); + vkCmdPipelineBarrier(cmd.get(), sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier); - _transfer_cmd.endRecord(); - _transfer_cmd.submitIdle(); + cmd.endRecord(); + cmd.submitIdle(); _layout = new_layout; } @@ -379,7 +369,6 @@ namespace mlx { destroySampler(); destroyImageView(); - destroyCmdPool(); if(_image != VK_NULL_HANDLE) Render_Core::get().getAllocator().destroyImage(_allocation, _image); diff --git a/src/renderer/images/vk_image.h b/src/renderer/images/vk_image.h index f1cc20d..a5600e6 100644 --- a/src/renderer/images/vk_image.h +++ b/src/renderer/images/vk_image.h @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2023/01/25 11:54:21 by maldavid #+# #+# */ -/* Updated: 2023/12/15 21:07:34 by maldavid ### ########.fr */ +/* Updated: 2023/12/15 21:44:30 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -39,7 +39,6 @@ namespace mlx _width = width; _height = height; _layout = layout; - _pool.init(); } void create(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool decated_memory = false); void createImageView(VkImageViewType type, VkImageAspectFlags aspectFlags) noexcept; @@ -64,11 +63,8 @@ namespace mlx private: void destroySampler() noexcept; void destroyImageView() noexcept; - inline void destroyCmdPool() noexcept { _transfer_cmd.destroy(); _pool.destroy(); } private: - CmdBuffer _transfer_cmd; - CmdPool _pool; VmaAllocation _allocation; VkImage _image = VK_NULL_HANDLE; VkImageView _image_view = VK_NULL_HANDLE; diff --git a/src/renderer/swapchain/vk_swapchain.cpp b/src/renderer/swapchain/vk_swapchain.cpp index 826830c..cada9ba 100644 --- a/src/renderer/swapchain/vk_swapchain.cpp +++ b/src/renderer/swapchain/vk_swapchain.cpp @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/06 18:22:28 by maldavid #+# #+# */ -/* Updated: 2023/12/10 22:32:54 by kbz_8 ### ########.fr */ +/* Updated: 2023/12/15 21:49:19 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */ @@ -146,9 +146,6 @@ namespace mlx vkDestroySwapchainKHR(Render_Core::get().getDevice().get(), _swapChain, nullptr); _swapChain = VK_NULL_HANDLE; for(Image& img : _images) - { img.destroyImageView(); - img.destroyCmdPool(); - } } } diff --git a/test/main.c b/test/main.c index 8be11b1..851aeda 100644 --- a/test/main.c +++ b/test/main.c @@ -6,7 +6,7 @@ /* By: maldavid +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2022/10/04 17:55:21 by maldavid #+# #+# */ -/* Updated: 2023/12/15 21:08:07 by maldavid ### ########.fr */ +/* Updated: 2023/12/16 19:14:56 by maldavid ### ########.fr */ /* */ /* ************************************************************************** */