diff --git a/Makefile b/Makefile index 2ade2ba..f4d4a83 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ ifeq ($(OS), Darwin) endif ifeq ($(DEBUG), true) - CXXFLAGS += -g3 -D DEBUG + CXXFLAGS += -g3 -O0 -D DEBUG LDFLAGS += -rdynamic else CXXFLAGS += -O3 diff --git a/example/main.c b/example/main.c index 819bb89..84a524d 100644 --- a/example/main.c +++ b/example/main.c @@ -56,7 +56,14 @@ int update(void* param) mlx_transform_put_image_to_window(mlx->mlx, mlx->render_target_win, mlx->logo_bmp, 100, 40, 0.5f, 75.0f); mlx_put_image_to_window(mlx->mlx, mlx->render_target_win, mlx->img, 40, 60); - mlx_put_image_to_window(mlx->mlx, mlx->win, mlx->render_target_win, 40, 60); + for(int j = 0, color = 0; j < 200; j++) + { + mlx_pixel_put(mlx->mlx, mlx->render_target_win, j, j, 0xFFFF0000 + color); + mlx_pixel_put(mlx->mlx, mlx->render_target_win, 199 - j, j, 0xFF0000FF); + color += (color < 255); + } + + mlx_transform_put_image_to_window(mlx->mlx, mlx->win, mlx->render_target, 5, 250, 0.5f, 33.0f); i++; return 0; @@ -139,10 +146,14 @@ int main(void) int dummy; mlx.mlx = mlx_init(); - mlx.win = mlx_new_window(mlx.mlx, 400, 400, "My window"); + mlx.win = mlx_new_resizable_window(mlx.mlx, 400, 400, "My window"); + + mlx_get_screens_size(mlx.mlx, mlx.win, &w, &h); + printf("screen size : %dx%d\n", w, h); mlx.render_target = mlx_new_image(mlx.mlx, 200, 200); mlx.render_target_win = mlx_new_window(mlx.mlx, 200, 200, (char*)mlx.render_target); + mlx_clear_window(mlx.mlx, mlx.render_target_win, 0xFFC16868); mlx_set_fps_goal(mlx.mlx, 60); @@ -164,9 +175,6 @@ int main(void) mlx_loop_hook(mlx.mlx, update, &mlx); mlx_loop(mlx.mlx); - mlx_get_screens_size(mlx.mlx, mlx.win, &w, &h); - printf("screen size : %dx%d\n", w, h); - mlx_destroy_image(mlx.mlx, mlx.logo_png); mlx_destroy_image(mlx.mlx, mlx.logo_jpg); mlx_destroy_image(mlx.mlx, mlx.logo_bmp); diff --git a/runtime/Includes/Renderer/RenderCore.h b/runtime/Includes/Renderer/RenderCore.h index 9f139c6..f6b126c 100644 --- a/runtime/Includes/Renderer/RenderCore.h +++ b/runtime/Includes/Renderer/RenderCore.h @@ -1,7 +1,7 @@ #ifndef __MLX_RENDER_CORE__ #define __MLX_RENDER_CORE__ -constexpr const int MAX_FRAMES_IN_FLIGHT = 3; +constexpr const int MAX_FRAMES_IN_FLIGHT = 2; #include #include diff --git a/runtime/Includes/Renderer/Renderer.h b/runtime/Includes/Renderer/Renderer.h index 07f572b..0217a45 100644 --- a/runtime/Includes/Renderer/Renderer.h +++ b/runtime/Includes/Renderer/Renderer.h @@ -16,6 +16,7 @@ namespace mlx Renderer() = default; void Init(NonOwningPtr window); + void Init(NonOwningPtr render_target); void BeginFrame(); void EndFrame(); @@ -28,6 +29,7 @@ namespace mlx [[nodiscard]] inline std::size_t& GetPolygonDrawnCounterRef() noexcept { return m_polygons_drawn; } [[nodiscard]] inline std::size_t GetCurrentFrameIndex() const noexcept { return m_current_frame_index; } [[nodiscard]] inline NonOwningPtr GetWindow() const noexcept { return p_window; } + [[nodiscard]] inline NonOwningPtr GetRenderTarget() const noexcept { return p_render_target; } [[nodiscard]] inline const Swapchain& GetSwapchain() const noexcept { return m_swapchain; } void Destroy() noexcept; @@ -41,6 +43,7 @@ namespace mlx std::array m_cmd_buffers; std::array m_cmd_fences; NonOwningPtr p_window; + NonOwningPtr p_render_target; std::uint32_t m_current_frame_index = 0; std::size_t m_polygons_drawn = 0; std::size_t m_drawcalls = 0; diff --git a/runtime/Sources/Core/Graphics.cpp b/runtime/Sources/Core/Graphics.cpp index db79fa5..93721c4 100644 --- a/runtime/Sources/Core/Graphics.cpp +++ b/runtime/Sources/Core/Graphics.cpp @@ -10,7 +10,7 @@ namespace mlx m_has_window(false) { MLX_PROFILE_FUNCTION(); - m_renderer.Init(nullptr); + m_renderer.Init(render_target); m_scene_renderer.Init(render_target); p_scene = std::make_unique(); } diff --git a/runtime/Sources/Graphics/PutPixelManager.cpp b/runtime/Sources/Graphics/PutPixelManager.cpp index 3266ef6..9d4d575 100644 --- a/runtime/Sources/Graphics/PutPixelManager.cpp +++ b/runtime/Sources/Graphics/PutPixelManager.cpp @@ -9,11 +9,18 @@ namespace mlx { Verify((bool)p_renderer, "invalid renderer pointer"); - VkExtent2D swapchain_extent = kvfGetSwapchainImagesSize(p_renderer->GetSwapchain().Get()); + VkExtent2D extent; + if(p_renderer->GetWindow()) + extent = kvfGetSwapchainImagesSize(p_renderer->GetSwapchain().Get()); + else if(p_renderer->GetRenderTarget()) + extent = VkExtent2D{ .width = p_renderer->GetRenderTarget()->GetWidth(), .height = p_renderer->GetRenderTarget()->GetHeight() }; + else + FatalError("a renderer was created without window nor render target attached (wtf)"); + #ifdef DEBUG - auto res = m_textures.try_emplace(draw_layer, CPUBuffer{}, swapchain_extent.width, swapchain_extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_put_pixel_layer_" + std::to_string(draw_layer)); + auto res = m_textures.try_emplace(draw_layer, CPUBuffer{}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_put_pixel_layer_" + std::to_string(draw_layer)); #else - auto res = m_textures.try_emplace(draw_layer, CPUBuffer{}, swapchain_extent.width, swapchain_extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, std::string_view{}); + auto res = m_textures.try_emplace(draw_layer, CPUBuffer{}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, std::string_view{}); #endif if(res.second) res.first->second.Clear(VK_NULL_HANDLE, Vec4f{ 0.0f }); diff --git a/runtime/Sources/Renderer/Pipelines/Graphics.cpp b/runtime/Sources/Renderer/Pipelines/Graphics.cpp index bdd5a59..4a8024f 100644 --- a/runtime/Sources/Renderer/Pipelines/Graphics.cpp +++ b/runtime/Sources/Renderer/Pipelines/Graphics.cpp @@ -132,6 +132,7 @@ namespace mlx kvfDestroyFramebuffer(RenderCore::Get().GetDevice(), fb); DebugLog("Vulkan: framebuffer destroyed"); } + m_framebuffers.clear(); kvfDestroyPipelineLayout(RenderCore::Get().GetDevice(), m_pipeline_layout); m_pipeline_layout = VK_NULL_HANDLE; @@ -148,7 +149,6 @@ namespace mlx p_renderer = nullptr; m_clears.clear(); m_attachments.clear(); - m_framebuffers.clear(); } void GraphicPipeline::CreateFramebuffers(const std::vector>& render_targets, bool clear_attachments) @@ -156,6 +156,8 @@ namespace mlx MLX_PROFILE_FUNCTION(); std::vector attachments; std::vector attachment_views; + std::vector dependencies; + if(p_renderer) { attachments.push_back(kvfBuildSwapchainAttachmentDescription(p_renderer->GetSwapchain().Get(), clear_attachments)); @@ -164,11 +166,30 @@ namespace mlx for(NonOwningPtr image : render_targets) { - attachments.push_back(kvfBuildAttachmentDescription((kvfIsDepthFormat(image->GetFormat()) ? KVF_IMAGE_DEPTH : KVF_IMAGE_COLOR), image->GetFormat(), image->GetLayout(), image->GetLayout(), clear_attachments, VK_SAMPLE_COUNT_1_BIT)); + attachments.push_back(kvfBuildAttachmentDescription(KVF_IMAGE_COLOR, image->GetFormat(), image->GetLayout(), image->GetLayout(), clear_attachments, VK_SAMPLE_COUNT_1_BIT)); attachment_views.push_back(image->GetImageView()); +#if 0 + VkSubpassDependency& first_dependency = dependencies.emplace_back(); + first_dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + first_dependency.dstSubpass = 0; + first_dependency.srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + first_dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + first_dependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + first_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + first_dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + VkSubpassDependency& second_dependency = dependencies.emplace_back(); + second_dependency.srcSubpass = 0; + second_dependency.dstSubpass = VK_SUBPASS_EXTERNAL; + second_dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + second_dependency.dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + second_dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + second_dependency.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + second_dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; +#endif } - m_renderpass = kvfCreateRenderPass(RenderCore::Get().GetDevice(), attachments.data(), attachments.size(), GetPipelineBindPoint()); + m_renderpass = kvfCreateRenderPassWithSubpassDependencies(RenderCore::Get().GetDevice(), attachments.data(), attachments.size(), GetPipelineBindPoint(), dependencies.data(), dependencies.size()); m_clears.clear(); m_clears.resize(attachments.size()); DebugLog("Vulkan: renderpass created"); diff --git a/runtime/Sources/Renderer/RenderPasses/2DPass.cpp b/runtime/Sources/Renderer/RenderPasses/2DPass.cpp index 4a767ee..1f408c0 100644 --- a/runtime/Sources/Renderer/RenderPasses/2DPass.cpp +++ b/runtime/Sources/Renderer/RenderPasses/2DPass.cpp @@ -50,7 +50,7 @@ namespace mlx if(event.What() == Event::ResizeEventCode) m_pipeline.Destroy(); }; - EventBus::RegisterListener({ functor, "__MlxRender2DPass" }); + EventBus::RegisterListener({ functor, "mlx_2d_render_pass" }); p_viewer_data_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_vertex_shader->GetShaderLayout().set_layouts[0].second, ShaderType::Vertex); p_texture_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_fragment_shader->GetShaderLayout().set_layouts[0].second, ShaderType::Fragment); diff --git a/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp b/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp index c8dec0f..d9d674b 100644 --- a/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp +++ b/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp @@ -36,7 +36,7 @@ namespace mlx if(event.What() == Event::ResizeEventCode) m_pipeline.Destroy(); }; - EventBus::RegisterListener({ functor, "__MlxFinalPass" }); + EventBus::RegisterListener({ functor, "mlx_final_pass" }); p_set = RenderCore::Get().GetDescriptorPoolManager().GetAvailablePool().RequestDescriptorSet(p_fragment_shader->GetShaderLayout().set_layouts[0].second, ShaderType::Fragment); } diff --git a/runtime/Sources/Renderer/RenderPasses/Passes.cpp b/runtime/Sources/Renderer/RenderPasses/Passes.cpp index 29bebbb..41987d7 100644 --- a/runtime/Sources/Renderer/RenderPasses/Passes.cpp +++ b/runtime/Sources/Renderer/RenderPasses/Passes.cpp @@ -16,7 +16,7 @@ namespace mlx if(event.What() == Event::ResizeEventCode) m_main_render_texture.Destroy(); }; - EventBus::RegisterListener({ functor, "__MlxRenderPasses" }); + EventBus::RegisterListener({ functor, "mlx_render_passes" }); } void RenderPasses::Pass(Scene& scene, Renderer& renderer, const Vec4f& clear_color) diff --git a/runtime/Sources/Renderer/Renderer.cpp b/runtime/Sources/Renderer/Renderer.cpp index 9b9ea4e..8c18706 100644 --- a/runtime/Sources/Renderer/Renderer.cpp +++ b/runtime/Sources/Renderer/Renderer.cpp @@ -19,8 +19,24 @@ namespace mlx { MLX_PROFILE_FUNCTION(); p_window = window; - if(p_window) - m_swapchain.Init(p_window); + m_swapchain.Init(p_window); + for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { + m_image_available_semaphores[i] = kvfCreateSemaphore(RenderCore::Get().GetDevice()); + DebugLog("Vulkan: image available semaphore created"); + m_render_finished_semaphores[i] = kvfCreateSemaphore(RenderCore::Get().GetDevice()); + DebugLog("Vulkan: render finished semaphore created"); + m_cmd_buffers[i] = kvfCreateCommandBuffer(RenderCore::Get().GetDevice()); + DebugLog("Vulkan: command buffer created"); + m_cmd_fences[i] = kvfCreateFence(RenderCore::Get().GetDevice()); + DebugLog("Vulkan: fence created"); + } + } + + void Renderer::Init(NonOwningPtr render_target) + { + MLX_PROFILE_FUNCTION(); + p_render_target = render_target; for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { m_image_available_semaphores[i] = kvfCreateSemaphore(RenderCore::Get().GetDevice()); diff --git a/runtime/Sources/Renderer/Swapchain.cpp b/runtime/Sources/Renderer/Swapchain.cpp index c6c7e96..2d6e694 100644 --- a/runtime/Sources/Renderer/Swapchain.cpp +++ b/runtime/Sources/Renderer/Swapchain.cpp @@ -19,8 +19,6 @@ namespace mlx void Swapchain::Init(NonOwningPtr window) { p_window = window; - m_surface = window->CreateVulkanSurface(RenderCore::Get().GetInstance()); - DebugLog("Vulkan: surface created"); CreateSwapchain(); } @@ -53,11 +51,16 @@ namespace mlx void Swapchain::Destroy() { + if(m_swapchain == VK_NULL_HANDLE) + return; RenderCore::Get().WaitDeviceIdle(); for(Image& img : m_swapchain_images) img.DestroyImageView(); + m_swapchain_images.clear(); kvfDestroySwapchainKHR(RenderCore::Get().GetDevice(), m_swapchain); + m_swapchain = VK_NULL_HANDLE; + DebugLog("Vulkan: swapchain destroyed"); RenderCore::Get().vkDestroySurfaceKHR(RenderCore::Get().GetInstance(), m_surface, nullptr); m_surface = VK_NULL_HANDLE; @@ -66,10 +69,6 @@ namespace mlx void Swapchain::CreateSwapchain() { - for(Image& img : m_swapchain_images) - img.DestroyImageView(); - m_swapchain_images.clear(); - VkExtent2D extent; do { @@ -77,10 +76,11 @@ namespace mlx extent = { size.x, size.y }; } while(extent.width == 0 || extent.height == 0); - VkSwapchainKHR old_swapchain = m_swapchain; - m_swapchain = kvfCreateSwapchainKHR(RenderCore::Get().GetDevice(), RenderCore::Get().GetPhysicalDevice(), m_surface, extent, VK_NULL_HANDLE, true); - if(old_swapchain != VK_NULL_HANDLE) - kvfDestroySwapchainKHR(RenderCore::Get().GetDevice(), old_swapchain); + Destroy(); + + m_surface = p_window->CreateVulkanSurface(RenderCore::Get().GetInstance()); + DebugLog("Vulkan: surface created"); + m_swapchain = kvfCreateSwapchainKHR(RenderCore::Get().GetDevice(), RenderCore::Get().GetPhysicalDevice(), m_surface, extent, VK_NULL_HANDLE, false); m_images_count = kvfGetSwapchainImagesCount(m_swapchain); m_min_images_count = kvfGetSwapchainMinImagesCount(m_swapchain);