fixing put pixel resize issue

This commit is contained in:
2026-02-03 11:58:06 +01:00
parent 2d9f193a72
commit 7639c27df4
6 changed files with 172 additions and 19 deletions

View File

@@ -8,7 +8,7 @@ namespace mlx
class PutPixelManager
{
public:
PutPixelManager(NonOwningPtr<class Renderer> renderer) : p_renderer(renderer) {}
PutPixelManager(NonOwningPtr<class Renderer> renderer);
// Returns a valid pointer when a new texture has been created
NonOwningPtr<Texture> DrawPixel(int x, int y, std::uint64_t draw_layer, mlx_color color);
@@ -20,6 +20,7 @@ namespace mlx
private:
NonOwningPtr<Texture> GetLayer(std::uint64_t draw_layer, bool& is_newlayer);
std::unique_ptr<Texture> NewTexture();
private:
std::unordered_map<std::uint64_t, NonOwningPtr<Texture>> m_placements;

View File

@@ -89,7 +89,13 @@ namespace mlx
mlx_color GetPixel(int x, int y) noexcept;
void GetRegion(int x, int y, int w, int h, mlx_color* dst) noexcept;
void Clear(VkCommandBuffer cmd, Vec4f color) override;
void CopyTo(Texture& other);
void Resize(std::uint32_t width, std::uint32_t height);
void Swap(Texture& texture) noexcept;
// If a valid cmd buffer is passed, this function takes ownership and makes it invalid after
void SyncCPUBuffer(VkCommandBuffer cmd = VK_NULL_HANDLE);
void Update(VkCommandBuffer cmd);
~Texture() override { Destroy(); }

View File

@@ -6,6 +6,29 @@
namespace mlx
{
PutPixelManager::PutPixelManager(NonOwningPtr<class Renderer> renderer) : p_renderer(renderer)
{
MLX_PROFILE_FUNCTION();
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
// Suboptimal for multi-windows applications
if(event.What() == Event::ResizeEventCode)
{
VkExtent2D extent{ .width = 0, .height = 0 };
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!?)");
for(auto& texture : m_textures)
texture->Resize(extent.width, extent.height);
}
};
EventBus::RegisterListener({ functor, "mlx_put_pixel_manager_" + std::to_string(reinterpret_cast<std::uintptr_t>(this)) });
}
NonOwningPtr<Texture> PutPixelManager::DrawPixel(int x, int y, std::uint64_t draw_layer, mlx_color color)
{
MLX_PROFILE_FUNCTION();
@@ -53,21 +76,8 @@ namespace mlx
is_newlayer = true;
if(m_current_texture_index >= m_textures.size())
{
VkExtent2D extent{ .width = 0, .height = 0 };
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)");
m_textures.push_back(NewTexture());
#ifdef DEBUG
m_textures.push_back(std::make_unique<Texture>(CPUBuffer{}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_put_pixel_layer_" + std::to_string(m_current_texture_index)));
#else
m_textures.push_back(std::make_unique<Texture>(CPUBuffer{}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, std::string_view{}));
#endif
}
try
{
m_placements[draw_layer] = m_textures.at(m_current_texture_index).get();
@@ -83,6 +93,23 @@ namespace mlx
}
}
std::unique_ptr<Texture> PutPixelManager::NewTexture()
{
VkExtent2D extent{ .width = 0, .height = 0 };
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
return std::make_unique<Texture>(CPUBuffer{}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_put_pixel_layer_" + std::to_string(m_current_texture_index));
#else
return std::make_unique<Texture>(CPUBuffer{}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, std::string_view{});
#endif
}
void PutPixelManager::ResetRenderData()
{
m_placements.clear();

View File

@@ -24,7 +24,7 @@
namespace mlx
{
mlx_color ReverseColor(mlx_color color)
MLX_FORCEINLINE mlx_color ReverseColor(mlx_color color)
{
mlx_color reversed_color;
reversed_color.r = color.a;
@@ -362,8 +362,16 @@ namespace mlx
m_staging_buffer->Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, {}, {});
#endif
SyncCPUBuffer();
}
void Texture::SyncCPUBuffer(VkCommandBuffer cmd)
{
if(!m_staging_buffer.has_value())
return;
VkImageLayout old_layout = m_layout;
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
if(cmd == VK_NULL_HANDLE)
cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, cmd);
kvfCopyImageToBuffer(cmd, m_staging_buffer->Get(), m_image, m_staging_buffer->GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { m_width, m_height, 1 });
@@ -375,6 +383,98 @@ namespace mlx
kvfDestroyCommandBuffer(RenderCore::Get().GetDevice(), cmd);
}
void Texture::CopyTo(Texture& other)
{
VkImageLayout old_layout = m_layout;
VkImageLayout other_old_layout = other.GetLayout();
VkImageSubresourceLayers subresource{};
subresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresource.mipLevel = 0;
subresource.layerCount = 1;
subresource.baseArrayLayer = 0;
VkExtent3D extent{};
extent.width = m_width;
extent.height = m_height;
extent.depth = 1;
VkOffset3D offset{};
offset.x = 0;
offset.y = 0;
offset.z = 0;
VkImageCopy region{};
region.srcSubresource = subresource;
region.dstSubresource = subresource;
region.extent = extent;
region.srcOffset = offset;
region.dstOffset = offset;
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, cmd);
other.TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
kvfCopyImageToImage(cmd, m_image, m_layout, other.Get(), other.GetLayout(), 1, &region);
TransitionLayout(old_layout, cmd);
other.TransitionLayout(other_old_layout, cmd);
kvfEndCommandBuffer(cmd);
SyncCPUBuffer(cmd);
}
void Texture::Resize(std::uint32_t width, std::uint32_t height)
{
#ifdef DEBUG
Texture new_texture = Texture(CPUBuffer{}, width, height, m_format, m_is_multisampled, m_debug_name);
#else
Texture new_texture = Texture(CPUBuffer{}, width, height, m_format, m_is_multisampled, std::string_view{});
#endif
if(m_staging_buffer.has_value())
new_texture.OpenCPUBuffer();
// Suboptimal operations, should bake all of them in a single command buffer
new_texture.Clear(VK_NULL_HANDLE, Vec4f{ 0.f });
CopyTo(new_texture);
Swap(new_texture);
}
void Texture::Swap(Texture& texture) noexcept
{
MLX_PROFILE_FUNCTION();
#ifdef DEBUG
std::swap(m_debug_name, texture.m_debug_name);
#endif
std::swap(m_allocation, texture.m_allocation);
std::swap(m_image, texture.m_image);
std::swap(m_image_view, texture.m_image_view);
std::swap(m_sampler, texture.m_sampler);
std::swap(m_format, texture.m_format);
std::swap(m_tiling, texture.m_tiling);
std::swap(m_layout, texture.m_layout);
std::swap(m_type, texture.m_type);
std::swap(m_width, texture.m_width);
std::swap(m_height, texture.m_height);
std::swap(m_is_multisampled, texture.m_is_multisampled);
if(m_staging_buffer.has_value() && texture.m_staging_buffer.has_value())
m_staging_buffer->Swap(*texture.m_staging_buffer);
else if(m_staging_buffer.has_value())
m_staging_buffer.reset();
else if(texture.m_staging_buffer.has_value())
texture.m_staging_buffer.reset();
m_has_been_modified = true;
texture.m_has_been_modified = true;
}
Texture* StbTextureLoad(const std::filesystem::path& file, int* w, int* h)
{
using namespace std::literals;