mirror of
https://github.com/seekrs/MacroLibX.git
synced 2026-09-03 00:00:00 +02:00
Merge branch 'master' into indev
This commit is contained in:
@@ -19,9 +19,10 @@ namespace mlx
|
|||||||
|
|
||||||
enum class Event
|
enum class Event
|
||||||
{
|
{
|
||||||
ResizeEventCode = 56,
|
ResizeEventCode = 1,
|
||||||
FrameBeginEventCode = 57,
|
SwapchainResizeEventCode,
|
||||||
FatalErrorEventCode = 168,
|
FrameBeginEventCode,
|
||||||
|
FatalErrorEventCode,
|
||||||
|
|
||||||
EndEnum
|
EndEnum
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
#ifndef __MLX_FPS__
|
#ifndef __MLX_FPS__
|
||||||
#define __MLX_FPS__
|
#define __MLX_FPS__
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace mlx
|
namespace mlx
|
||||||
{
|
{
|
||||||
|
typedef std::chrono::steady_clock fps_clock;
|
||||||
|
|
||||||
class FpsManager
|
class FpsManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FpsManager() = default;
|
FpsManager() = default;
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
bool Update();
|
void WaitUntilNextFrame();
|
||||||
inline void SetMaxFPS(std::uint32_t fps) noexcept { m_max_fps = fps; m_ns = 1000000000.0 / fps; }
|
inline void SetMaxFPS(std::uint32_t fps) noexcept { m_target_delta = fps_clock::duration(std::chrono::seconds(1)) / fps;}
|
||||||
|
|
||||||
~FpsManager() = default;
|
~FpsManager() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_ns = 1000000000.0 / 1'337'000.0;
|
fps_clock::time_point m_current_time;
|
||||||
std::int64_t m_fps_before = 0;
|
fps_clock::time_point m_target_time;
|
||||||
std::int64_t m_fps_now = 0;
|
fps_clock::time_point m_last_time_record;
|
||||||
std::int64_t m_timer = 0;
|
fps_clock::duration m_delta_time = fps_clock::duration().zero();
|
||||||
std::uint32_t m_max_fps = 1'337'000;
|
fps_clock::duration m_target_delta = fps_clock::duration().zero();
|
||||||
std::uint32_t m_fps_elapsed_time = 0;
|
fps_clock::duration m_sleep_margin = std::chrono::microseconds(200);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace mlx
|
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();
|
MLX_PROFILE_FUNCTION();
|
||||||
std::srand(std::time(nullptr));
|
std::srand(std::time(nullptr));
|
||||||
@@ -33,8 +33,7 @@ namespace mlx
|
|||||||
|
|
||||||
while(m_in.IsRunning())
|
while(m_in.IsRunning())
|
||||||
{
|
{
|
||||||
if(!m_fps.Update())
|
m_fps.WaitUntilNextFrame();
|
||||||
continue;
|
|
||||||
|
|
||||||
m_in.FetchInputs();
|
m_in.FetchInputs();
|
||||||
|
|
||||||
|
|||||||
@@ -45,10 +45,9 @@ extern "C"
|
|||||||
void mlx_set_fps_goal(mlx_context mlx, int fps)
|
void mlx_set_fps_goal(mlx_context mlx, int fps)
|
||||||
{
|
{
|
||||||
MLX_CHECK_APPLICATION_POINTER(mlx);
|
MLX_CHECK_APPLICATION_POINTER(mlx);
|
||||||
if(fps < 0)
|
if(fps <= 0)
|
||||||
mlx::Error("You cannot set a negative FPS cap (nice try)");
|
fps = -1;
|
||||||
else
|
mlx->app->SetFPSCap(static_cast<std::uint32_t>(fps));
|
||||||
mlx->app->SetFPSCap(static_cast<std::uint32_t>(fps));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mlx_destroy_context(mlx_context mlx)
|
void mlx_destroy_context(mlx_context mlx)
|
||||||
@@ -313,14 +312,14 @@ extern "C"
|
|||||||
mlx::Error("Font loader: filepath is NULL");
|
mlx::Error("Font loader: filepath is NULL");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path file(filepath);
|
std::filesystem::path file(filepath);
|
||||||
if (std::strcmp(filepath, "default") != 0 && !std::filesystem::exists(file))
|
if (std::strcmp(filepath, "default") != 0 && !std::filesystem::exists(file))
|
||||||
{
|
{
|
||||||
mlx::Error("TTF loader: unable to find file '%'", filepath);
|
mlx::Error("TTF loader: unable to find file '%'", filepath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(std::strcmp(filepath, "default") != 0)
|
if(std::strcmp(filepath, "default") != 0)
|
||||||
{
|
{
|
||||||
if(file.extension() != ".ttf" && file.extension() != ".tte")
|
if(file.extension() != ".ttf" && file.extension() != ".tte")
|
||||||
@@ -350,7 +349,7 @@ extern "C"
|
|||||||
mlx::Error("Font loader: filepath is NULL");
|
mlx::Error("Font loader: filepath is NULL");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path file(filepath);
|
std::filesystem::path file(filepath);
|
||||||
if (std::strcmp(filepath, "default") != 0 && !std::filesystem::exists(file))
|
if (std::strcmp(filepath, "default") != 0 && !std::filesystem::exists(file))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,30 +1,37 @@
|
|||||||
#include <PreCompiled.h>
|
#include <PreCompiled.h>
|
||||||
#include <Core/Fps.h>
|
#include <Core/Fps.h>
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace mlx
|
namespace mlx
|
||||||
{
|
{
|
||||||
void FpsManager::Init()
|
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_current_time = fps_clock::now();
|
||||||
m_fps_before = m_timer;
|
m_target_time = m_current_time + m_target_delta;
|
||||||
m_fps_now = m_timer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FpsManager::Update()
|
void FpsManager::WaitUntilNextFrame()
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
m_current_time = fps_clock::now();
|
||||||
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(m_current_time < m_target_time)
|
||||||
|
|
||||||
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_fps_before += m_ns;
|
std::this_thread::sleep_until(m_target_time - m_sleep_margin);
|
||||||
return true;
|
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));
|
else if (m_target_time < m_current_time - m_target_delta * 4)
|
||||||
return false;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ namespace mlx
|
|||||||
{
|
{
|
||||||
namespace Internal
|
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())
|
if(!m_events_hooks.contains(window_id) || m_events_hooks[window_id][event].empty())
|
||||||
return;
|
return;
|
||||||
if(event == MLX_WINDOW_EVENT && code == 8)
|
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])
|
for(const auto& hook : m_events_hooks[window_id][event])
|
||||||
{
|
{
|
||||||
if(hook.fn)
|
if(hook.fn)
|
||||||
|
|||||||
@@ -226,25 +226,34 @@ namespace mlx
|
|||||||
void Texture::SetRegion(int x, int y, int w, int h, mlx_color* pixels) noexcept
|
void Texture::SetRegion(int x, int y, int w, int h, mlx_color* pixels) noexcept
|
||||||
{
|
{
|
||||||
MLX_PROFILE_FUNCTION();
|
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 < -w || y < -h
|
||||||
return;
|
|| x >= static_cast<int>(m_width) || y >= static_cast<int>(m_height))
|
||||||
if(w < 0 || h < 0)
|
|
||||||
return;
|
return;
|
||||||
if(!m_staging_buffer.has_value())
|
if(!m_staging_buffer.has_value())
|
||||||
OpenCPUBuffer();
|
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;
|
i += incr;
|
||||||
moving_y++;
|
dx = start_x;
|
||||||
if(moving_y >= static_cast<std::uint32_t>(y + h) || moving_y >= m_height)
|
row += m_width;
|
||||||
|
if(row >= end_row)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if constexpr(std::endian::native == std::endian::little)
|
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
|
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;
|
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
|
void Texture::SetLinearRegion(int x, int y, std::size_t len, mlx_color* pixels) noexcept
|
||||||
{
|
{
|
||||||
MLX_PROFILE_FUNCTION();
|
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;
|
return;
|
||||||
if(!m_staging_buffer.has_value())
|
if(!m_staging_buffer.has_value())
|
||||||
OpenCPUBuffer();
|
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)
|
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++)
|
for(int i = dest_start, j = src_start; i < dest_end; i++, j++)
|
||||||
m_staging_buffer->GetMap<mlx_color*>()[(y * m_width) + x + i] = ReverseColor(pixels[i]);
|
m_staging_buffer->GetMap<mlx_color*>()[i] = ReverseColor(pixels[j]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::size_t len_guard;
|
std::memcpy(
|
||||||
if((y * m_width + x + len) < m_width * m_height)
|
&m_staging_buffer->GetMap<mlx_color*>()[dest_start],
|
||||||
len_guard = len;
|
&pixels[src_start], dest_end - dest_start);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
m_has_been_modified = true;
|
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
|
void Texture::GetRegion(int x, int y, int w, int h, mlx_color* dst) noexcept
|
||||||
{
|
{
|
||||||
MLX_PROFILE_FUNCTION();
|
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;
|
return;
|
||||||
if(!m_staging_buffer.has_value())
|
if(!m_staging_buffer.has_value())
|
||||||
OpenCPUBuffer();
|
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;
|
dx = x;
|
||||||
moving_y++;
|
row += m_width;
|
||||||
if(moving_y >= static_cast<std::uint32_t>(y + h) || moving_y >= m_height)
|
if(row >= m_height * m_width)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if constexpr(std::endian::native == std::endian::little)
|
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
|
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.g = static_cast<std::uint8_t>(color.g * 255.f);
|
||||||
processed_color.b = static_cast<std::uint8_t>(color.b * 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);
|
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)
|
for(std::size_t i = 0; i < m_width * m_height; i++)
|
||||||
std::memset(m_staging_buffer->GetMap(), processed_color.a, m_staging_buffer->GetSize());
|
m_staging_buffer->GetMap<mlx_color*>()[i] = processed_color;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace mlx
|
|||||||
Event What() const override { return Event::ResizeEventCode; }
|
Event What() const override { return Event::ResizeEventCode; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VulkanFormatName(VkFormat format)
|
std::string VulkanFormatName(VkFormat format)
|
||||||
{
|
{
|
||||||
#define STRINGIFY(x) case x: return #x
|
#define STRINGIFY(x) case x: return #x
|
||||||
@@ -161,7 +161,7 @@ namespace mlx
|
|||||||
|
|
||||||
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
|
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;
|
m_resize = true;
|
||||||
};
|
};
|
||||||
EventBus::RegisterListener({ functor, "mlx_swapchain_" + std::to_string(reinterpret_cast<std::uintptr_t>(this)) });
|
EventBus::RegisterListener({ functor, "mlx_swapchain_" + std::to_string(reinterpret_cast<std::uintptr_t>(this)) });
|
||||||
|
|||||||
Reference in New Issue
Block a user