Merge branch 'master' into indev

This commit is contained in:
Daemo
2026-08-09 00:15:07 +02:00
8 changed files with 92 additions and 79 deletions
+4 -3
View File
@@ -19,9 +19,10 @@ namespace mlx
enum class Event
{
ResizeEventCode = 56,
FrameBeginEventCode = 57,
FatalErrorEventCode = 168,
ResizeEventCode = 1,
SwapchainResizeEventCode,
FrameBeginEventCode,
FatalErrorEventCode,
EndEnum
};
+12 -8
View File
@@ -1,26 +1,30 @@
#ifndef __MLX_FPS__
#define __MLX_FPS__
#include <chrono>
namespace mlx
{
typedef std::chrono::steady_clock fps_clock;
class FpsManager
{
public:
FpsManager() = default;
void Init();
bool Update();
inline void SetMaxFPS(std::uint32_t fps) noexcept { m_max_fps = fps; m_ns = 1000000000.0 / fps; }
void WaitUntilNextFrame();
inline void SetMaxFPS(std::uint32_t fps) noexcept { m_target_delta = fps_clock::duration(std::chrono::seconds(1)) / fps;}
~FpsManager() = default;
private:
double m_ns = 1000000000.0 / 1'337'000.0;
std::int64_t m_fps_before = 0;
std::int64_t m_fps_now = 0;
std::int64_t m_timer = 0;
std::uint32_t m_max_fps = 1'337'000;
std::uint32_t m_fps_elapsed_time = 0;
fps_clock::time_point m_current_time;
fps_clock::time_point m_target_time;
fps_clock::time_point m_last_time_record;
fps_clock::duration m_delta_time = fps_clock::duration().zero();
fps_clock::duration m_target_delta = fps_clock::duration().zero();
fps_clock::duration m_sleep_margin = std::chrono::microseconds(200);
};
}
+2 -3
View File
@@ -8,7 +8,7 @@
namespace mlx
{
Application::Application() : p_mem_manager(std::make_unique<MemManager>()), p_sdl_manager(std::make_unique<SDLManager>()), m_fps(), m_in()
Application::Application() : p_mem_manager(std::make_unique<MemManager>()), p_sdl_manager(std::make_unique<SDLManager>()), m_fps(), m_in()
{
MLX_PROFILE_FUNCTION();
std::srand(std::time(nullptr));
@@ -33,8 +33,7 @@ namespace mlx
while(m_in.IsRunning())
{
if(!m_fps.Update())
continue;
m_fps.WaitUntilNextFrame();
m_in.FetchInputs();
+6 -7
View File
@@ -45,10 +45,9 @@ extern "C"
void mlx_set_fps_goal(mlx_context mlx, int fps)
{
MLX_CHECK_APPLICATION_POINTER(mlx);
if(fps < 0)
mlx::Error("You cannot set a negative FPS cap (nice try)");
else
mlx->app->SetFPSCap(static_cast<std::uint32_t>(fps));
if(fps <= 0)
fps = -1;
mlx->app->SetFPSCap(static_cast<std::uint32_t>(fps));
}
void mlx_destroy_context(mlx_context mlx)
@@ -313,14 +312,14 @@ extern "C"
mlx::Error("Font loader: filepath is NULL");
return;
}
std::filesystem::path file(filepath);
if (std::strcmp(filepath, "default") != 0 && !std::filesystem::exists(file))
{
mlx::Error("TTF loader: unable to find file '%'", filepath);
return;
}
if(std::strcmp(filepath, "default") != 0)
{
if(file.extension() != ".ttf" && file.extension() != ".tte")
@@ -350,7 +349,7 @@ extern "C"
mlx::Error("Font loader: filepath is NULL");
return;
}
std::filesystem::path file(filepath);
if (std::strcmp(filepath, "default") != 0 && !std::filesystem::exists(file))
{
+23 -16
View File
@@ -1,30 +1,37 @@
#include <PreCompiled.h>
#include <Core/Fps.h>
#ifndef __APPLE__
#include <emmintrin.h>
#endif
namespace mlx
{
void FpsManager::Init()
{
m_timer = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
m_fps_before = m_timer;
m_fps_now = m_timer;
m_current_time = fps_clock::now();
m_target_time = m_current_time + m_target_delta;
}
bool FpsManager::Update()
void FpsManager::WaitUntilNextFrame()
{
using namespace std::chrono_literals;
m_fps_now = static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count());
if(std::chrono::duration<std::uint64_t>{m_fps_now - m_timer} >= 1s)
m_timer += m_fps_now;
m_fps_elapsed_time = m_fps_now - m_fps_before;
if(m_fps_elapsed_time >= m_ns)
m_current_time = fps_clock::now();
if(m_current_time < m_target_time)
{
m_fps_before += m_ns;
return true;
std::this_thread::sleep_until(m_target_time - m_sleep_margin);
m_current_time = fps_clock::now();
while (m_current_time < m_target_time)
{
#ifndef __APPLE__
_mm_pause(); // reduces CPU usage on x86 without yielding
#endif
m_current_time = fps_clock::now();
}
}
std::this_thread::sleep_for(std::chrono::duration<double, std::nano>(m_ns - 1));
return false;
else if (m_target_time < m_current_time - m_target_delta * 4)
m_target_time = m_current_time;
m_target_time += m_target_delta;
m_delta_time = m_current_time - m_last_time_record;
m_last_time_record = m_current_time;
}
}
+3 -3
View File
@@ -8,9 +8,9 @@ namespace mlx
{
namespace Internal
{
struct ResizeEventBroadcast : public EventBase
struct SwapchainResizeEventBroadcast : public EventBase
{
Event What() const override { return Event::ResizeEventCode; }
Event What() const override { return Event::SwapchainResizeEventCode; }
};
}
@@ -23,7 +23,7 @@ namespace mlx
if(!m_events_hooks.contains(window_id) || m_events_hooks[window_id][event].empty())
return;
if(event == MLX_WINDOW_EVENT && code == 8)
EventBus::SendBroadcast(Internal::ResizeEventBroadcast{});
EventBus::SendBroadcast(Internal::SwapchainResizeEventBroadcast{});
for(const auto& hook : m_events_hooks[window_id][event])
{
if(hook.fn)
+40 -37
View File
@@ -226,25 +226,34 @@ namespace mlx
void Texture::SetRegion(int x, int y, int w, int h, mlx_color* pixels) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) >= m_width || static_cast<std::uint32_t>(y) >= m_height)
return;
if(w < 0 || h < 0)
if(w < 0 || h < 0 || x < -w || y < -h
|| x >= static_cast<int>(m_width) || y >= static_cast<int>(m_height))
return;
if(!m_staging_buffer.has_value())
OpenCPUBuffer();
for(std::uint32_t i = 0, moving_x = x, moving_y = y;; i++, moving_x++)
const int
start_x = std::max<int>(x, 0),
start_y = std::max<int>(y, 0),
start_row = start_y * m_width,
start_i = (start_y - y) * w + (start_x - x),
end_x = std::min<int>(x + w, m_width),
end_y = std::min<int>(y + h, m_height),
end_row = end_y * m_width,
incr = (x + w) - end_x + (start_x - x);
for(int i = start_i, dx = start_x, row = start_row;; i++, dx++)
{
if(moving_x >= static_cast<std::uint32_t>(x + w) || moving_x >= m_width)
if(dx >= end_x)
{
moving_x = x;
moving_y++;
if(moving_y >= static_cast<std::uint32_t>(y + h) || moving_y >= m_height)
i += incr;
dx = start_x;
row += m_width;
if(row >= end_row)
break;
}
if constexpr(std::endian::native == std::endian::little)
m_staging_buffer->GetMap<mlx_color*>()[(moving_y * m_width) + moving_x] = ReverseColor(pixels[i]);
m_staging_buffer->GetMap<mlx_color*>()[row + dx] = ReverseColor(pixels[i]);
else
m_staging_buffer->GetMap<mlx_color*>()[(moving_y * m_width) + moving_x] = pixels[i];
m_staging_buffer->GetMap<mlx_color*>()[row + dx] = pixels[i];
}
m_has_been_modified = true;
}
@@ -252,23 +261,25 @@ namespace mlx
void Texture::SetLinearRegion(int x, int y, std::size_t len, mlx_color* pixels) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) >= m_width || static_cast<std::uint32_t>(y) >= m_height)
if(x >= static_cast<int>(m_width) || y >= static_cast<int>(m_height))
return;
if(!m_staging_buffer.has_value())
OpenCPUBuffer();
int
start = y * m_width + x,
dest_start = std::max<int>(start, 0),
src_start = dest_start - start,
dest_end = std::min<int>(start + len, m_width * m_height);
if constexpr(std::endian::native == std::endian::little)
{
for(std::size_t i = 0; i < len && (y * m_width) + x + i < m_width * m_height; i++)
m_staging_buffer->GetMap<mlx_color*>()[(y * m_width) + x + i] = ReverseColor(pixels[i]);
for(int i = dest_start, j = src_start; i < dest_end; i++, j++)
m_staging_buffer->GetMap<mlx_color*>()[i] = ReverseColor(pixels[j]);
}
else
{
std::size_t len_guard;
if((y * m_width + x + len) < m_width * m_height)
len_guard = len;
else
len_guard = len - (m_width * m_height - (y * m_width + x + len));
std::memcpy(&m_staging_buffer->GetMap<mlx_color*>()[(y * m_width) + x], pixels, len_guard);
std::memcpy(
&m_staging_buffer->GetMap<mlx_color*>()[dest_start],
&pixels[src_start], dest_end - dest_start);
}
m_has_been_modified = true;
}
@@ -289,23 +300,23 @@ namespace mlx
void Texture::GetRegion(int x, int y, int w, int h, mlx_color* dst) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) >= m_width || static_cast<std::uint32_t>(y) >= m_height)
if(w < 0 || h < 0 || x < 0 || y < 0 || static_cast<std::uint32_t>(x + w) >= m_width || static_cast<std::uint32_t>(y + h) >= m_height)
return;
if(!m_staging_buffer.has_value())
OpenCPUBuffer();
for(std::uint32_t i = 0, moving_x = x, moving_y = y;; i++, moving_x++)
for(std::uint32_t i = 0, dx = x, row = y * m_width;; i++, dx++)
{
if(moving_x >= static_cast<std::uint32_t>(x + w) || moving_x >= m_width)
if(dx >= m_width)
{
moving_x = x;
moving_y++;
if(moving_y >= static_cast<std::uint32_t>(y + h) || moving_y >= m_height)
dx = x;
row += m_width;
if(row >= m_height * m_width)
break;
}
if constexpr(std::endian::native == std::endian::little)
dst[i] = ReverseColor(m_staging_buffer->GetMap<mlx_color*>()[(moving_y * m_width) + moving_x]);
dst[i] = ReverseColor(m_staging_buffer->GetMap<mlx_color*>()[row + dx]);
else
dst[i] = m_staging_buffer->GetMap<mlx_color*>()[(moving_y * m_width) + moving_x];
dst[i] = m_staging_buffer->GetMap<mlx_color*>()[row + dx];
}
}
@@ -320,16 +331,8 @@ namespace mlx
processed_color.g = static_cast<std::uint8_t>(color.g * 255.f);
processed_color.b = static_cast<std::uint8_t>(color.b * 255.f);
processed_color.a = static_cast<std::uint8_t>(color.a * 255.f);
if(processed_color.r == 0 && processed_color.g == 0 && processed_color.b == 0)
std::memset(m_staging_buffer->GetMap(), processed_color.a, m_staging_buffer->GetSize());
else
{
for(std::size_t y = 0; y < m_height; y++)
{
for(std::size_t x = 0; x < m_width; x++)
m_staging_buffer->GetMap<mlx_color*>()[y * m_width + x] = processed_color;
}
}
for(std::size_t i = 0; i < m_width * m_height; i++)
m_staging_buffer->GetMap<mlx_color*>()[i] = processed_color;
}
}
+2 -2
View File
@@ -15,7 +15,7 @@ namespace mlx
Event What() const override { return Event::ResizeEventCode; }
};
}
std::string VulkanFormatName(VkFormat format)
{
#define STRINGIFY(x) case x: return #x
@@ -161,7 +161,7 @@ namespace mlx
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode && !m_resize)
if(event.What() == Event::SwapchainResizeEventCode && !m_resize)
m_resize = true;
};
EventBus::RegisterListener({ functor, "mlx_swapchain_" + std::to_string(reinterpret_cast<std::uintptr_t>(this)) });