mirror of
https://github.com/seekrs/MacroLibX.git
synced 2026-01-11 14:43:34 +00:00
143 headless mode (#150)
This commit is contained in:
78
.github/workflows/tests.yml
vendored
git.filemode.normal_file
78
.github/workflows/tests.yml
vendored
git.filemode.normal_file
@@ -0,0 +1,78 @@
|
|||||||
|
name: Unit tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- '.gitignore'
|
||||||
|
- 'LICENSE'
|
||||||
|
- 'README.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-24.04]
|
||||||
|
arch: [x86_64]
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
if: "!contains(github.event.head_commit.message, 'ci skip')"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: NcStudios/VulkanCI@v1.0
|
||||||
|
|
||||||
|
- name: Install system dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y install mesa-common-dev clang libsdl2-2.0-0 libsdl2-dev build-essential libvulkan-dev
|
||||||
|
|
||||||
|
# Build the lib
|
||||||
|
- name: Build MacroLibX
|
||||||
|
run: make -j DEBUG=true
|
||||||
|
|
||||||
|
# Force xmake to a specific folder (for cache)
|
||||||
|
- name: Set xmake env
|
||||||
|
run: echo "XMAKE_GLOBALDIR=${{ runner.workspace }}/xmake-global" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Install xmake
|
||||||
|
- name: Setup xmake
|
||||||
|
if: ${{ matrix.confs.plat != 'mingw' }}
|
||||||
|
uses: xmake-io/github-action-setup-xmake@v1
|
||||||
|
with:
|
||||||
|
xmake-version: latest
|
||||||
|
actions-cache-folder: .xmake-cache-W${{ steps.cache_key.outputs.key }}
|
||||||
|
|
||||||
|
# Update xmake repository (in order to have the file that will be cached)
|
||||||
|
- name: Update xmake repository
|
||||||
|
run: xmake repo --update
|
||||||
|
|
||||||
|
# Fetch xmake dephash
|
||||||
|
- name: Retrieve dependencies hash
|
||||||
|
id: dep_hash
|
||||||
|
run: echo "hash=$(xmake l utils.ci.packageskey)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Install unit tester
|
||||||
|
run: git clone https://github.com/seekrs/MacroUnitTest.git ../MacroUnitTest
|
||||||
|
|
||||||
|
# Setup compilation mode and install project dependencies
|
||||||
|
- name: Configure xmake and install dependencies
|
||||||
|
run: |
|
||||||
|
cd ../MacroUnitTest
|
||||||
|
xmake config --toolchain=clang --ccache=n --yes
|
||||||
|
|
||||||
|
# Save dependencies
|
||||||
|
- name: Save cached xmake dependencies
|
||||||
|
if: ${{ !steps.restore-depcache.outputs.cache-hit }}
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
with:
|
||||||
|
path: ${{ env.XMAKE_GLOBALDIR }}/.xmake/packages
|
||||||
|
key: ${{ steps.restore-depcache.outputs.cache-primary-key }}
|
||||||
|
|
||||||
|
- name: Build and run unit tester
|
||||||
|
run: |
|
||||||
|
cd ../MacroUnitTest
|
||||||
|
xmake run MacroUnitTest --headless --path="${{ runner.workspace }}/MacroLibX/libmlx.so"
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/windows.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/windows.yml/badge.svg"></a>
|
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/windows.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/windows.yml/badge.svg"></a>
|
||||||
</div>
|
</div>
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://github.com/seekrs/MacroLibX/actions/workflows/tests.yml"><img src="https://github.com/seekrs/MacroLibX/actions/workflows/tests.yml/badge.svg"></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
###### MacroLibX, a rewrite of 42 School's MiniLibX using SDL2 and Vulkan.
|
###### MacroLibX, a rewrite of 42 School's MiniLibX using SDL2 and Vulkan.
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ namespace mlx
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UUID();
|
UUID();
|
||||||
UUID(std::uint64_t uuid);
|
inline operator std::uint64_t() const noexcept { return m_uuid; }
|
||||||
|
|
||||||
inline operator std::uint64_t() const { return m_uuid; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::uint64_t m_uuid;
|
std::uint64_t m_uuid;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace mlx
|
|||||||
MLX_PROFILE_FUNCTION();
|
MLX_PROFILE_FUNCTION();
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
|
||||||
m_drop_sdl_responsability = SDL_WasInit(SDL_INIT_VIDEO);
|
m_drop_sdl_responsability = SDL_WasInit(SDL_INIT_VIDEO) || std::getenv("MLX_HEADLESS_MODE") != nullptr;
|
||||||
if(m_drop_sdl_responsability) // is case the mlx is running in a sandbox like MacroUnitTester where SDL is already init
|
if(m_drop_sdl_responsability) // is case the mlx is running in a sandbox like MacroUnitTester where SDL is already init
|
||||||
return;
|
return;
|
||||||
SDL_SetMemoryFunctions(MemManager::Get().Malloc, MemManager::Get().Calloc, MemManager::Get().Realloc, MemManager::Get().Free);
|
SDL_SetMemoryFunctions(MemManager::Get().Malloc, MemManager::Get().Calloc, MemManager::Get().Realloc, MemManager::Get().Free);
|
||||||
|
|||||||
@@ -7,7 +7,14 @@ namespace mlx
|
|||||||
static std::random_device random_device;
|
static std::random_device random_device;
|
||||||
static std::mt19937_64 engine(random_device());
|
static std::mt19937_64 engine(random_device());
|
||||||
static std::uniform_int_distribution<std::uint64_t> uniform_distribution;
|
static std::uniform_int_distribution<std::uint64_t> uniform_distribution;
|
||||||
|
static std::unordered_set<std::uint64_t> registry;
|
||||||
|
|
||||||
UUID::UUID() : m_uuid(uniform_distribution(engine)) {}
|
UUID::UUID()
|
||||||
UUID::UUID(std::uint64_t uuid) : m_uuid(uuid) {}
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
m_uuid = uniform_distribution(engine);
|
||||||
|
} while(registry.contains(m_uuid));
|
||||||
|
registry.emplace(m_uuid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace mlx
|
|||||||
|
|
||||||
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
|
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
|
||||||
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
||||||
kvfCopyBufferToBuffer(cmd, m_buffer, buffer.Get(), m_size);
|
kvfCopyBufferToBuffer(cmd, m_buffer, buffer.Get(), m_size, 0, 0);
|
||||||
kvfEndCommandBuffer(cmd);
|
kvfEndCommandBuffer(cmd);
|
||||||
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
|
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
|
||||||
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
|
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
|
||||||
|
|||||||
@@ -87,15 +87,24 @@ namespace mlx
|
|||||||
kvfSetValidationErrorCallback(&ValidationErrorCallback);
|
kvfSetValidationErrorCallback(&ValidationErrorCallback);
|
||||||
kvfSetValidationWarningCallback(&WarningCallback);
|
kvfSetValidationWarningCallback(&WarningCallback);
|
||||||
|
|
||||||
|
std::vector<const char*> instance_extensions;
|
||||||
|
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||||
|
std::unique_ptr<Window> window;
|
||||||
|
|
||||||
|
bool is_headless = std::getenv("MLX_HEADLESS_MODE") != nullptr;
|
||||||
|
|
||||||
|
if(!is_headless)
|
||||||
|
{
|
||||||
mlx_window_create_info info{};
|
mlx_window_create_info info{};
|
||||||
info.title = "";
|
info.title = "";
|
||||||
info.width = 1;
|
info.width = 1;
|
||||||
info.height = 1;
|
info.height = 1;
|
||||||
Window window(&info, true);
|
window = std::make_unique<Window>(&info, true);
|
||||||
std::vector<const char*> instance_extensions = window.GetRequiredVulkanInstanceExtentions();
|
instance_extensions = window->GetRequiredVulkanInstanceExtentions();
|
||||||
#ifdef MLX_PLAT_MACOS
|
#ifdef MLX_PLAT_MACOS
|
||||||
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
m_instance = kvfCreateInstance(instance_extensions.data(), instance_extensions.size());
|
m_instance = kvfCreateInstance(instance_extensions.data(), instance_extensions.size());
|
||||||
DebugLog("Vulkan: instance created");
|
DebugLog("Vulkan: instance created");
|
||||||
@@ -103,24 +112,33 @@ namespace mlx
|
|||||||
loader->LoadInstance(m_instance);
|
loader->LoadInstance(m_instance);
|
||||||
LoadKVFInstanceVulkanFunctionPointers();
|
LoadKVFInstanceVulkanFunctionPointers();
|
||||||
|
|
||||||
VkSurfaceKHR surface = window.CreateVulkanSurface(m_instance);
|
if(!is_headless)
|
||||||
|
{
|
||||||
|
surface = window->CreateVulkanSurface(m_instance);
|
||||||
m_physical_device = kvfPickGoodDefaultPhysicalDevice(m_instance, surface);
|
m_physical_device = kvfPickGoodDefaultPhysicalDevice(m_instance, surface);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_physical_device = kvfPickGoodPhysicalDevice(m_instance, VK_NULL_HANDLE, nullptr, 0);
|
||||||
|
|
||||||
|
Verify(m_physical_device != VK_NULL_HANDLE, "Could not find a suitable physical device");
|
||||||
|
|
||||||
// just for style
|
// just for style
|
||||||
VkPhysicalDeviceProperties props;
|
VkPhysicalDeviceProperties props;
|
||||||
vkGetPhysicalDeviceProperties(m_physical_device, &props);
|
vkGetPhysicalDeviceProperties(m_physical_device, &props);
|
||||||
DebugLog("Vulkan: physical device picked '%'", props.deviceName);
|
DebugLog("Vulkan: physical device picked '%'", props.deviceName);
|
||||||
|
|
||||||
const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
|
std::vector<const char*> device_extensions;
|
||||||
|
if(!is_headless)
|
||||||
|
device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
VkPhysicalDeviceFeatures features{};
|
VkPhysicalDeviceFeatures features{};
|
||||||
vkGetPhysicalDeviceFeatures(m_physical_device, &features);
|
vkGetPhysicalDeviceFeatures(m_physical_device, &features);
|
||||||
m_device = kvfCreateDevice(m_physical_device, device_extensions, sizeof(device_extensions) / sizeof(device_extensions[0]), &features);
|
m_device = kvfCreateDevice(m_physical_device, device_extensions.data(), device_extensions.size(), &features);
|
||||||
DebugLog("Vulkan: logical device created");
|
DebugLog("Vulkan: logical device created");
|
||||||
|
|
||||||
loader->LoadDevice(m_device);
|
loader->LoadDevice(m_device);
|
||||||
LoadKVFDeviceVulkanFunctionPointers();
|
LoadKVFDeviceVulkanFunctionPointers();
|
||||||
|
|
||||||
|
if(surface != VK_NULL_HANDLE)
|
||||||
vkDestroySurfaceKHR(m_instance, surface, nullptr);
|
vkDestroySurfaceKHR(m_instance, surface, nullptr);
|
||||||
|
|
||||||
VkAllocationCallbacks callbacks;
|
VkAllocationCallbacks callbacks;
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ namespace mlx
|
|||||||
{
|
{
|
||||||
static inline PFN_vkVoidFunction vkGetInstanceProcAddrStub(Handle context, const char* name)
|
static inline PFN_vkVoidFunction vkGetInstanceProcAddrStub(Handle context, const char* name)
|
||||||
{
|
{
|
||||||
|
bool is_headless = std::getenv("MLX_HEADLESS_MODE") != nullptr;
|
||||||
|
if(is_headless && std::string_view(name).find("KHR") != std::string_view::npos)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
PFN_vkVoidFunction function = RenderCore::Get().vkGetInstanceProcAddr(static_cast<VkInstance>(context), name);
|
PFN_vkVoidFunction function = RenderCore::Get().vkGetInstanceProcAddr(static_cast<VkInstance>(context), name);
|
||||||
if(!function)
|
if(!function)
|
||||||
FatalError("Vulkan Loader: could not load '%'", name);
|
FatalError("Vulkan Loader: could not load '%'", name);
|
||||||
@@ -37,6 +41,10 @@ namespace mlx
|
|||||||
|
|
||||||
static inline PFN_vkVoidFunction vkGetDeviceProcAddrStub(Handle context, const char* name)
|
static inline PFN_vkVoidFunction vkGetDeviceProcAddrStub(Handle context, const char* name)
|
||||||
{
|
{
|
||||||
|
bool is_headless = std::getenv("MLX_HEADLESS_MODE") != nullptr;
|
||||||
|
if(is_headless && std::string_view(name).find("KHR") != std::string_view::npos)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
PFN_vkVoidFunction function = RenderCore::Get().vkGetDeviceProcAddr(static_cast<VkDevice>(context), name);
|
PFN_vkVoidFunction function = RenderCore::Get().vkGetDeviceProcAddr(static_cast<VkDevice>(context), name);
|
||||||
if(!function)
|
if(!function)
|
||||||
FatalError("Vulkan Loader: could not load '%'", name);
|
FatalError("Vulkan Loader: could not load '%'", name);
|
||||||
|
|||||||
3
third_party/kvf.h
vendored
3
third_party/kvf.h
vendored
@@ -1475,9 +1475,6 @@ int32_t __kvfScorePhysicalDevice(VkPhysicalDevice device, VkSurfaceKHR surface,
|
|||||||
if(device_props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
if(device_props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||||
score += 1000;
|
score += 1000;
|
||||||
|
|
||||||
if(!device_features.geometryShader)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
score += device_props.limits.maxImageDimension2D;
|
score += device_props.limits.maxImageDimension2D;
|
||||||
score += device_props.limits.maxBoundDescriptorSets;
|
score += device_props.limits.maxBoundDescriptorSets;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
-- Global settings
|
-- Global settings
|
||||||
|
|
||||||
add_requires("libsdl", { configs = { sdlmain = false } })
|
add_requires("libsdl2", { configs = { sdlmain = false } })
|
||||||
|
|
||||||
add_rules("mode.debug", "mode.release", "mode.releasedbg")
|
add_rules("mode.debug", "mode.release", "mode.releasedbg")
|
||||||
set_languages("cxx20", "c11")
|
set_languages("cxx20", "c11")
|
||||||
@@ -63,7 +63,7 @@ target("mlx")
|
|||||||
|
|
||||||
add_files("runtime/Sources/**.cpp")
|
add_files("runtime/Sources/**.cpp")
|
||||||
|
|
||||||
add_packages("libsdl")
|
add_packages("libsdl2")
|
||||||
|
|
||||||
if is_mode("debug") then
|
if is_mode("debug") then
|
||||||
add_defines("DEBUG")
|
add_defines("DEBUG")
|
||||||
@@ -98,5 +98,5 @@ target("Test")
|
|||||||
|
|
||||||
add_defines("SDL_MAIN_HANDLED")
|
add_defines("SDL_MAIN_HANDLED")
|
||||||
|
|
||||||
add_packages("libsdl")
|
add_packages("libsdl2")
|
||||||
target_end()
|
target_end()
|
||||||
|
|||||||
Reference in New Issue
Block a user