Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
pull_request:

concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
build:
strategy:
Expand Down Expand Up @@ -41,10 +45,9 @@ jobs:
cmake \
g++ \
clang \
libxinerama-dev \
libxcursor-dev \
xorg-dev \
libglu1-mesa-dev \
libvulkan1 \
mesa-vulkan-drivers \
vulkan-tools \
pkg-config

- name: Install dependencies (macOS)
Expand Down Expand Up @@ -81,7 +84,7 @@ jobs:
if (!(Test-Path "vcpkg\vcpkg.exe")) { cd vcpkg; .\bootstrap-vcpkg.bat; cd .. }

- name: Configure
run: cmake --preset ${{ matrix.configure_preset }}
run: cmake --preset ${{ matrix.configure_preset }} -DQUARK_HEADLESS=ON -DVCPKG_MANIFEST_FEATURES=headless

- name: Build
run: cmake --build --preset ${{ matrix.configure_preset }}
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(QuarkOptions)
include(QuarkFeatures)

find_package(Vulkan REQUIRED)
if(NOT Vulkan_FOUND)
Expand All @@ -17,9 +18,12 @@ if(NOT Vulkan_FOUND)
)
endif()

find_package(glfw3 CONFIG REQUIRED)
find_package(tl-expected CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)

if(NOT QUARK_HEADLESS)
find_package(glfw3 CONFIG REQUIRED)
endif()

add_subdirectory(src)
29 changes: 21 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
CONFIG ?= debug
HEADLESS ?= OFF

UNAME_S := $(shell uname -s 2>/dev/null)
UNAME_M := $(shell uname -m 2>/dev/null)
Expand All @@ -23,6 +24,14 @@ else
$(error Unknown CONFIG '$(CONFIG)'. Use one of: debug release asan-ubsan tsan release-lto debug-gcc debug-clang)
endif

ifeq ($(HEADLESS),ON)
HEADLESS_SUFFIX := -headless
else ifeq($(HEADLESS),OFF)
HEADLESS_SUFFIX :=
else
$(error Unknown HEADLESS '$(HEADLESS)'. Use ON or OFF)
endif

ifeq ($(UNAME_S),Darwin)
ifeq ($(UNAME_M),arm64)
CMAKE_CONFIGURE_PRESET := macos-arm64-$(SUFFIX)
Expand All @@ -31,31 +40,31 @@ ifeq ($(UNAME_S),Darwin)
else
$(error Unsupported macOS arch '$(UNAME_M)')
endif
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)$(HEADLESS_SUFFIX)

else ifeq ($(UNAME_S),Linux)
ifndef LINUX_TOOLCHAIN
LINUX_TOOLCHAIN := gcc
endif
CMAKE_CONFIGURE_PRESET := linux-x64-$(LINUX_TOOLCHAIN)-$(SUFFIX)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)$(HEADLESS_SUFFIX)

else
# Windows (i.e. Git Bash/MSYS) often reports uname -s like MINGW64_NT-*
# For native Windows usage, recommend running from a shell where `cmake` works.
ifneq (,$(findstring MINGW,$(UNAME_S)))
CMAKE_CONFIGURE_PRESET := windows-x64-msvc-$(SUFFIX)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)$(HEADLESS_SUFFIX)
else ifneq (,$(findstring MSYS,$(UNAME_S)))
CMAKE_CONFIGURE_PRESET := windows-x64-msvc-$(SUFFIX)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)$(HEADLESS_SUFFIX)
else ifneq (,$(findstring CYGWIN,$(UNAME_S)))
CMAKE_CONFIGURE_PRESET := windows-x64-msvc-$(SUFFIX)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)$(HEADLESS_SUFFIX)
else
# If uname isn't available, assume Windows.
CMAKE_CONFIGURE_PRESET := windows-x64-msvc-$(SUFFIX)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)
BUILD_DIR := build/$(CMAKE_CONFIGURE_PRESET)$(HEADLESS_SUFFIX)
endif

ifeq ($(SUFFIX),asan-ubsan)
Expand All @@ -82,6 +91,8 @@ else
VCPKG_TRIPLET := x64-windows
endif



.PHONY: deps vcpkg-install configure build run clean bench-noop bench-touch

### testing this for non-gh actions
Expand Down Expand Up @@ -144,7 +155,10 @@ vcpkg-install: deps
./vcpkg/vcpkg install --triplet $(VCPKG_TRIPLET)

configure:
cmake --preset $(CMAKE_CONFIGURE_PRESET)
cmake --preset $(CMAKE_CONFIGURE_PRESET) \
-DQUARK_HEADLESS=$(HEADLESS) \
-DVCPKG_MANIFEST_FEATURES=window
-B $(BUILD_DIR)
./scripts/sync_compile_commands.sh $(BUILD_DIR)

build: configure
Expand All @@ -155,4 +169,3 @@ run: build

clean:
rm -rf build

9 changes: 9 additions & 0 deletions cmake/QuarkFeatures.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
option(QUARK_HEADLESS
"Build Quark without window/swapchain presentation support" OFF)

add_library(quark_features INTERFACE)
add_library(quark::features ALIAS quark_features)

target_compile_definitions(
quark_features INTERFACE $<$<BOOL:${QUARK_HEADLESS}>:QUARK_HEADLESS=1>
$<$<NOT:$<BOOL:${QUARK_HEADLESS}>>:QUARK_HEADLESS=0>)
5 changes: 5 additions & 0 deletions include/quark/vk/device/details/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class Device final {
return present_queue_;
}

[[nodiscard]] bool has_present_queu() const noexcept {
return present_queue_ != VK_NULL_HANDLE;
}

[[nodiscard]] uint32_t graphics_queue_family_index() const noexcept {
return graphics_queue_family_index_;
}
Expand All @@ -65,6 +69,7 @@ class Device final {
VkPhysicalDevice physical_device{VK_NULL_HANDLE};
uint32_t graphics_queue_family_index{0};
uint32_t present_queue_family_index{0};
bool has_present_queue{false};
};

static util::Result<DeviceSelection>
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ add_library(quark::headers::core ALIAS quark_headers_core)
target_link_libraries(quark_headers_core INTERFACE quark::build_settings
fmt::fmt)

target_link_libraries(quark_build_settings INTERFACE quark::features)

add_library(quark_headers_vk INTERFACE)
add_library(quark::headers::vk ALIAS quark_headers_vk)
target_link_libraries(quark_headers_vk INTERFACE quark::headers::core
Expand Down
55 changes: 37 additions & 18 deletions src/backend/vulkan/device/device.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <fmt/format.h>
#include <quark/vk/device/details/device.hpp>
#include <quark/vk/device/details/device_feature_chain_builder.hpp>
#include <quark/vk/diagnostic_prelude.hpp>
Expand All @@ -17,9 +18,6 @@ util::Status Device::create(const Device::CreateInfo &ci) {
QUARK_ENSURE(ci.instance != VK_NULL_HANDLE,
QUARK_ERR(util::Errc::InvalidArg,
"Cannot create Vulkan device with null instance"));
QUARK_ENSURE(ci.surface != VK_NULL_HANDLE,
QUARK_ERR(util::Errc::InvalidArg,
"Cannot create Vulkan device with null surface"));

alloc_ = ci.allocator;

Expand All @@ -38,8 +36,11 @@ util::Status Device::create(const Device::CreateInfo &ci) {
capabilities_.enabled_features = 0;

constexpr float queue_priority{1.0F};
const std::set<uint32_t> unique_queue_families{graphics_queue_family_index_,
present_queue_family_index_};
std::set<uint32_t> unique_queue_families{graphics_queue_family_index_};

if (selection.has_present_queue) {
unique_queue_families.insert(present_queue_family_index_);
}

std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
queue_create_infos.reserve(unique_queue_families.size());
Expand Down Expand Up @@ -81,7 +82,13 @@ util::Status Device::create(const Device::CreateInfo &ci) {
device_ = out;

vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &graphics_queue_);
vkGetDeviceQueue(device_, present_queue_family_index_, 0, &present_queue_);

if (selection.has_present_queue) {
vkGetDeviceQueue(device_, present_queue_family_index_, 0, &present_queue_);
} else {
present_queue_ = VK_NULL_HANDLE;
present_queue_family_index_ = graphics_queue_family_index_;
}

QUARK_OK();
}
Expand All @@ -105,8 +112,8 @@ util::Result<Device::DeviceSelection> Device::pick_physical_device_(
const std::vector<const char *> &required_extensions) {
QUARK_ENSURE(instance != VK_NULL_HANDLE,
QUARK_ERR(util::Errc::InvalidArg, "instance is null"));
QUARK_ENSURE(surface != VK_NULL_HANDLE,
QUARK_ERR(util::Errc::InvalidArg, "surface is null"));

const bool has_surface = surface != VK_NULL_HANDLE;

uint32_t device_count{0};
QUARK_VK_TRY(vkEnumeratePhysicalDevices(instance, &device_count,
Expand All @@ -120,10 +127,6 @@ util::Result<Device::DeviceSelection> Device::pick_physical_device_(
vkEnumeratePhysicalDevices(instance, &device_count, devices.data()));

std::optional<DeviceSelection> fallback;
auto enumerate = [&](VkPhysicalDevice physical_device)
-> util::Result<std::vector<VkExtensionProperties>> {
return enumerate_device_extensions_(physical_device);
};

for (const VkPhysicalDevice &physical_device : devices) {
const auto graphics_queue_family_index =
Expand All @@ -132,14 +135,23 @@ util::Result<Device::DeviceSelection> Device::pick_physical_device_(
continue;
}

const auto present_queue_family_index =
find_present_queue_family_or_error_(physical_device, surface);
if (!present_queue_family_index.has_value()) {
continue;
uint32_t present_queue_family_index = *graphics_queue_family_index;
bool has_present_queue = false;

if (has_surface) {
const auto present_result =
find_present_queue_family_or_error_(physical_device, surface);

if (!present_result.has_value()) {
continue;
}

present_queue_family_index = *present_result;
has_present_queue = true;
}

std::vector<VkExtensionProperties> props;
QUARK_TRY_ASSIGN(props, enumerate(physical_device));
QUARK_TRY_ASSIGN(props, enumerate_device_extensions_(physical_device));

bool ok_exts = true;
for (const char *name : required_extensions) {
Expand All @@ -148,6 +160,7 @@ util::Result<Device::DeviceSelection> Device::pick_physical_device_(
break;
}
}

if (!ok_exts) {
continue;
}
Expand All @@ -158,7 +171,8 @@ util::Result<Device::DeviceSelection> Device::pick_physical_device_(
const DeviceSelection selection{
.physical_device = physical_device,
.graphics_queue_family_index = *graphics_queue_family_index,
.present_queue_family_index = *present_queue_family_index,
.present_queue_family_index = present_queue_family_index,
.has_present_queue = has_present_queue,
};

if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
Expand Down Expand Up @@ -294,6 +308,11 @@ Device::find_graphics_queue_family_or_error_(VkPhysicalDevice physical_device) {
util::Result<uint32_t>
Device::find_present_queue_family_or_error_(VkPhysicalDevice physical_device,
VkSurfaceKHR surface) {
QUARK_ENSURE(physical_device != VK_NULL_HANDLE,
QUARK_ERR(util::Errc::InvalidArg, "physical_device is null"));
QUARK_ENSURE(surface != VK_NULL_HANDLE,
QUARK_ERR(util::Errc::InvalidArg, "surface is null"));

uint32_t queue_family_count{0};
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
/*pQueueFamilyProperties=*/nullptr);
Expand Down
Loading
Loading