diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-04-27 01:16:21 +0200 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-04-27 01:16:21 +0200 |
commit | e02f9fd89b059919baf3a8d8bf8b783470976a27 (patch) | |
tree | 6bb16cce1231dba9b0eab5f43ceb7c5d86f8e7cb | |
parent | 08eece258ceff7824250454906bff013a7303c28 (diff) |
Some work on Vulkan initialization
-rw-r--r-- | .clang-tidy | 1 | ||||
-rw-r--r-- | deimos/core/allocator.h | 21 | ||||
-rw-r--r-- | deimos/core/base.h | 19 | ||||
-rw-r--r-- | deimos/core/log.cpp | 8 | ||||
-rw-r--r-- | deimos/core/status.h | 14 | ||||
-rw-r--r-- | deimos/core/std.h | 1 | ||||
-rw-r--r-- | deimos/core/temp_allocator.cpp | 12 | ||||
-rw-r--r-- | deimos/vulkan/BUILD | 2 | ||||
-rw-r--r-- | deimos/vulkan/vulkan.h | 4 | ||||
-rw-r--r-- | deimos/vulkan/vulkan_bootstrap_functions.inc | 3 | ||||
-rw-r--r-- | deimos/vulkan/vulkan_entry_functions.inc | 1 | ||||
-rw-r--r-- | deimos/vulkan/vulkan_instance_functions.inc | 6 | ||||
-rw-r--r-- | deimos/vulkan/vulkan_loader.cpp | 18 | ||||
-rw-r--r-- | main/main.cpp | 119 |
14 files changed, 202 insertions, 27 deletions
diff --git a/.clang-tidy b/.clang-tidy index be78fe7..3cedbdc 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -26,3 +26,4 @@ Checks: - "-*-noexcept-move-operations"
- "-*-bounds-array-to-pointer-decay"
- "-*-no-array-decay"
+ - "-*-signed-bitwise"
diff --git a/deimos/core/allocator.h b/deimos/core/allocator.h index 26374bd..5afb824 100644 --- a/deimos/core/allocator.h +++ b/deimos/core/allocator.h @@ -125,6 +125,27 @@ public: }
Free(t, sizeof(T), source_location);
}
+
+ template<typename T>
+ gsl::owner<Span<T>> NewArray(int64_t count, const SourceLocation& source_location = {})
+ requires std::is_default_constructible_v<T>
+ {
+ Expects(count > 0);
+
+ auto* raw = Allocate((int64_t)sizeof(T) * count, source_location);
+ if constexpr (std::is_trivially_default_constructible_v<T>)
+ {
+ MemoryZero(raw, (int64_t)sizeof(T) * count);
+ }
+ else
+ {
+ for (int64_t i = 0; i < count; ++i)
+ {
+ new((T*)raw + i) T{};
+ }
+ }
+ return Span<T>{ (T*)raw, count };
+ }
};
class AllocatorApi
diff --git a/deimos/core/base.h b/deimos/core/base.h index 5cd3a40..70958a5 100644 --- a/deimos/core/base.h +++ b/deimos/core/base.h @@ -5,7 +5,13 @@ #define deimos_StaticAssert(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
-#define deimos_Panic(MSG) do { __builtin_trap(); } while (0)
+[[noreturn]]
+inline void deimos_Trap()
+{
+ __builtin_trap();
+}
+
+#define deimos_Panic(MSG) do { deimos_Trap(); } while (0)
#define deimos_NO_COPY(TYPE) \
TYPE(const TYPE&) = delete; \
@@ -78,6 +84,11 @@ constexpr void MemoryCopy(void* dst, const void* src, int64_t size) __builtin_memcpy(dst, src, (size_t)size);
}
+inline void MemoryZero(void* dst, int64_t size)
+{
+ __builtin_memset(dst, 0, (size_t)size);
+}
+
template<typename T, int64_t N>
constexpr int64_t ArraySize(const T (&)[N]) { return N; }
@@ -117,6 +128,12 @@ public: constexpr T* end() const { return m_begin + m_size; } // NOLINT
constexpr int64_t size() const { return m_size; }
constexpr bool empty() const { return m_size == 0; }
+
+ constexpr T& operator[](int64_t i) const
+ {
+ Expects(i >= 0 && i < m_size);
+ return m_begin[i]; // NOLINT
+ }
};
template<typename T>
diff --git a/deimos/core/log.cpp b/deimos/core/log.cpp index e05c360..b8e7805 100644 --- a/deimos/core/log.cpp +++ b/deimos/core/log.cpp @@ -35,10 +35,12 @@ public: m_writer(os_console_api, OsConsoleType::kStdOut)
{}
- void Log(LogSeverity severity, const SourceLocation& location, StringView msg) override
+ void Log(LogSeverity severity, const SourceLocation& /* location */, StringView msg) override
{
- Format(&m_writer, "$[ $ ] $:$: $\033[0m\n", SeverityToColor(severity),
- SeverityToStr(severity), location.file, location.line, msg);
+ // Format(&m_writer, "$[ $ ] $:$: $\033[0m\n", SeverityToColor(severity),
+ // SeverityToStr(severity), location.file, location.line, msg);
+ Format(&m_writer, "$[ $ ] $\033[0m\n", SeverityToColor(severity),
+ SeverityToStr(severity), msg);
}
};
diff --git a/deimos/core/status.h b/deimos/core/status.h index 912d4c8..8141dad 100644 --- a/deimos/core/status.h +++ b/deimos/core/status.h @@ -147,18 +147,18 @@ public: StatusOr(const Status& status) : m_status{status} // NOLINT
{
+ Expects(!m_status.ok());
if (m_status.ok())
{
- deimos_Panic("Cannot construct a StatusOr from OK");
m_status = InternalError("StatusOr constructed from OK");
}
}
StatusOr(Status&& status) : m_status{std::move(status)} // NOLINT
{
+ Expects(!m_status.ok());
if (m_status.ok())
{
- deimos_Panic("Cannot construct a StatusOr from OK");
m_status = InternalError("StatusOr constructed from OK");
}
}
@@ -229,6 +229,16 @@ public: }
constexpr bool ok() const { return m_status.ok(); }
+
+ constexpr StatusCode code() const { return m_status.code(); }
+
+ constexpr const Status& status() const { return m_status; }
+
+ constexpr const T& value() const & { Expects(m_status.ok()); return m_value; }
+
+ constexpr T& value() & { Expects(m_status.ok()); return m_value; }
+
+ constexpr T&& value() && { Expects(m_status.ok()); return std::move(m_value); }
friend void DeimosFormat(IWriter* writer, const StatusOr<T>& status)
{
diff --git a/deimos/core/std.h b/deimos/core/std.h index 47f161a..27b5bc4 100644 --- a/deimos/core/std.h +++ b/deimos/core/std.h @@ -26,6 +26,7 @@ template<typename T> concept unsigned_integral = integral<T> && __is_unsigned(T) template<typename T> constexpr bool is_trivially_destructible_v = __is_trivially_destructible(T);
template<typename T, typename... Args> constexpr bool is_constructible_v = __is_constructible(T, Args...);
template<typename T> constexpr bool is_default_constructible_v = __is_constructible(T);
+template<typename T> constexpr bool is_trivially_default_constructible_v = __is_trivially_constructible(T);
template<typename T> constexpr bool is_copy_constructible_v = __is_constructible(T, const T&);
template<typename T> constexpr bool is_move_constructible_v = __is_constructible(T, T&&);
template<typename T> constexpr bool is_copy_assignable_v = __is_assignable(T, const T&);
diff --git a/deimos/core/temp_allocator.cpp b/deimos/core/temp_allocator.cpp index d2b7900..99ee630 100644 --- a/deimos/core/temp_allocator.cpp +++ b/deimos/core/temp_allocator.cpp @@ -35,7 +35,6 @@ public: if (new_current > m_reserve_end)
{
deimos_Panic("Ran out of temporary memory");
- return nullptr;
}
if (new_current > m_commit_end)
@@ -73,15 +72,8 @@ public: {
void* rewind_base = std::bit_cast<void*>(tag.tag);
Expects(rewind_base >= m_base && rewind_base <= m_commit_end);
-
- if (rewind_base < m_current)
- {
- m_current = rewind_base;
- }
- else
- {
- deimos_Panic("Invalid temporary allocator rewind");
- }
+ Expects(rewind_base <= m_current);
+ m_current = rewind_base;
}
};
diff --git a/deimos/vulkan/BUILD b/deimos/vulkan/BUILD index a773fa1..8f0a79e 100644 --- a/deimos/vulkan/BUILD +++ b/deimos/vulkan/BUILD @@ -5,7 +5,9 @@ cc_library( ],
srcs = [
"vulkan_loader.cpp",
+ "vulkan_bootstrap_functions.inc",
"vulkan_entry_functions.inc",
+ "vulkan_instance_functions.inc",
],
deps = [
"//deimos/core",
diff --git a/deimos/vulkan/vulkan.h b/deimos/vulkan/vulkan.h index 48d53b3..4315230 100644 --- a/deimos/vulkan/vulkan.h +++ b/deimos/vulkan/vulkan.h @@ -20,7 +20,9 @@ class ApiRegistry; struct VulkanApi
{
#define FN(NAME) PFN_vk##NAME NAME{};
+#include "deimos/vulkan/vulkan_bootstrap_functions.inc"
#include "deimos/vulkan/vulkan_entry_functions.inc"
+#include "deimos/vulkan/vulkan_instance_functions.inc"
#undef FN
};
@@ -34,6 +36,8 @@ public: static constexpr IdName kApiName{"deimos::VulkanLoaderApi"};
virtual VulkanApi* LoadEntry() = 0;
+
+ virtual void LoadInstance(VulkanApi*, VkInstance) = 0;
};
void RegisterVulkanLoaderApi(ApiRegistry*);
diff --git a/deimos/vulkan/vulkan_bootstrap_functions.inc b/deimos/vulkan/vulkan_bootstrap_functions.inc new file mode 100644 index 0000000..a69c5a6 --- /dev/null +++ b/deimos/vulkan/vulkan_bootstrap_functions.inc @@ -0,0 +1,3 @@ +// NOLINTBEGIN
+FN(GetInstanceProcAddr)
+// NOLINTEND
diff --git a/deimos/vulkan/vulkan_entry_functions.inc b/deimos/vulkan/vulkan_entry_functions.inc index fe5f9ea..761cb0f 100644 --- a/deimos/vulkan/vulkan_entry_functions.inc +++ b/deimos/vulkan/vulkan_entry_functions.inc @@ -1,4 +1,3 @@ // NOLINTBEGIN
-FN(GetInstanceProcAddr)
FN(CreateInstance)
// NOLINTEND
diff --git a/deimos/vulkan/vulkan_instance_functions.inc b/deimos/vulkan/vulkan_instance_functions.inc new file mode 100644 index 0000000..34535ad --- /dev/null +++ b/deimos/vulkan/vulkan_instance_functions.inc @@ -0,0 +1,6 @@ +// NOLINTBEGIN
+FN(EnumeratePhysicalDevices)
+FN(GetPhysicalDeviceProperties2)
+FN(GetPhysicalDeviceQueueFamilyProperties)
+FN(DestroyInstance)
+// NOLINTEND
diff --git a/deimos/vulkan/vulkan_loader.cpp b/deimos/vulkan/vulkan_loader.cpp index ddd5cf0..0760c67 100644 --- a/deimos/vulkan/vulkan_loader.cpp +++ b/deimos/vulkan/vulkan_loader.cpp @@ -31,16 +31,32 @@ public: else
{
deimos_Panic("Couldn't load Vulkan DLL");
- return nullptr;
}
}
VulkanApi* api = m_allocator->New<VulkanApi>();
+
#define FN(NAME) api->NAME = (PFN_vk##NAME)os_api->dll->GetSymbol(m_vulkan_dll, "vk" #NAME);
+#include "deimos/vulkan/vulkan_bootstrap_functions.inc"
+#undef FN
+
+#define FN(NAME) api->NAME = (PFN_vk##NAME)api->GetInstanceProcAddr(VK_NULL_HANDLE, "vk" #NAME);
#include "deimos/vulkan/vulkan_entry_functions.inc"
#undef FN
+
return api;
}
+
+ void LoadInstance(VulkanApi* api, VkInstance instance) override
+ {
+ Expects(api != nullptr);
+ Expects(instance != VK_NULL_HANDLE);
+ Expects(api->GetInstanceProcAddr != nullptr);
+
+#define FN(NAME) api->NAME = (PFN_vk##NAME)api->GetInstanceProcAddr(instance, "vk" #NAME);
+#include "deimos/vulkan/vulkan_instance_functions.inc"
+#undef FN
+ }
};
void RegisterVulkanLoaderApi(ApiRegistry* registry)
diff --git a/main/main.cpp b/main/main.cpp index ca1e063..34d0276 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -7,6 +7,9 @@ using namespace deimos;
static LogApi* log_api;
+static TempAllocatorApi* temp_api;
+
+static const VkAllocationCallbacks* kVkAlloc = nullptr;
[[nodiscard]]
StatusOr<VkInstance> CreateInstance(VulkanApi* vk)
@@ -26,6 +29,7 @@ StatusOr<VkInstance> CreateInstance(VulkanApi* vk) "VK_KHR_win32_surface",
};
+ // @Todo Select layers & extensions based on config
const char* layers[]{
"VK_LAYER_KHRONOS_validation",
"VK_LAYER_LUNARG_monitor",
@@ -43,7 +47,7 @@ StatusOr<VkInstance> CreateInstance(VulkanApi* vk) };
VkInstance instance{};
- const VkResult res = vk->CreateInstance(&create_info, nullptr, &instance);
+ const VkResult res = vk->CreateInstance(&create_info, kVkAlloc, &instance);
if (res != VK_SUCCESS)
{
return InternalError("vkCreateInstance failed");
@@ -52,21 +56,118 @@ StatusOr<VkInstance> CreateInstance(VulkanApi* vk) return instance;
}
+StatusOr<VkPhysicalDevice> FindPhysicalDevice(VulkanApi* vk, VkInstance instance)
+{
+ auto temp_alloc = temp_api->Acquire();
+
+ uint32_t physical_device_count = 0;
+ vk->EnumeratePhysicalDevices(instance, &physical_device_count, nullptr);
+ if (physical_device_count == 0)
+ {
+ return InternalError("No Vulkan device found");
+ }
+
+ log_api->LogInfo("Found $ physical devices", physical_device_count);
+
+ auto devices = temp_alloc.allocator().NewArray<VkPhysicalDevice>(physical_device_count);
+ vk->EnumeratePhysicalDevices(instance, &physical_device_count, devices.data());
+
+ // @Todo Physical device selection
+ return devices[0];
+}
+
+StatusOr<uint32_t> FindQueueFamily(VulkanApi* vk, VkPhysicalDevice device)
+{
+ auto temp_alloc = temp_api->Acquire();
+
+ uint32_t queue_family_count = 0;
+ vk->GetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr);
+ if (queue_family_count == 0)
+ {
+ return InternalError("No queue on this physical device??");
+ }
+
+ log_api->LogInfo("Physical device has $ queue families", queue_family_count);
+
+ auto queue_families = temp_alloc.allocator().NewArray<VkQueueFamilyProperties>(queue_family_count);
+ vk->GetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.data());
+
+ for (uint32_t index = 0; index < queue_family_count; ++index)
+ {
+ const auto& prps = queue_families[index];
+ if ((prps.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0 && (prps.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0)
+ {
+ return index;
+ }
+ }
+
+ return InternalError("Couldn't find a suitable queue");
+}
+
+Status InitializeVulkan(ApiRegistry* api_registry)
+{
+ RegisterVulkanLoaderApi(api_registry);
+ auto* loader_api = api_registry->Get<VulkanLoaderApi>();
+ auto* vk = loader_api->LoadEntry();
+
+ VkInstance instance{};
+ {
+ StatusOr<VkInstance> s = CreateInstance(vk);
+ if (!s.ok()) { return s.status(); }
+ instance = s.value();
+ log_api->LogInfo("Vulkan instance created");
+ }
+
+ loader_api->LoadInstance(vk, instance);
+
+ VkPhysicalDevice physical_device{};
+ {
+ StatusOr<VkPhysicalDevice> s = FindPhysicalDevice(vk, instance);
+ if (!s.ok()) { return s.status(); }
+ physical_device = s.value();
+ }
+
+ {
+
+ VkPhysicalDeviceVulkan12Properties prps12{};
+ prps12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES;
+ prps12.pNext = nullptr;
+
+ VkPhysicalDeviceProperties2 prps{};
+ prps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ prps.pNext = &prps12;
+
+ vk->GetPhysicalDeviceProperties2(physical_device, &prps);
+ log_api->LogInfo("Vulkan device: $", prps.properties.deviceName);
+ log_api->LogInfo("Vulkan driver: $, $", prps12.driverName, prps12.driverInfo);
+ }
+
+ uint32_t queue_family = 0;
+ {
+ StatusOr<uint32_t> s = FindQueueFamily(vk, physical_device);
+ if (!s.ok()) { return s.status(); }
+ queue_family = s.value();
+ }
+
+ log_api->LogInfo("Vulkan queue family: $", queue_family);
+
+ vk->DestroyInstance(instance, kVkAlloc);
+ return {};
+}
+
int main(int /* argc */, char* /* argv */[])
{
auto* api_registry = InitializeGlobalApiRegistry();
log_api = api_registry->Get<LogApi>();
- log_api->LogInfo("Base APIs registered"); - - RegisterVulkanLoaderApi(api_registry); - auto* vulkan_loader_api = api_registry->Get<VulkanLoaderApi>(); - auto* vk = vulkan_loader_api->LoadEntry();
+ temp_api = api_registry->Get<TempAllocatorApi>();
+ log_api->LogInfo("Base APIs registered");
- const StatusOr<VkInstance> s = CreateInstance(vk);
+ const Status s = InitializeVulkan(api_registry);
if (!s.ok())
{
- log_api->LogError("$", s);
- }
+ log_api->LogError("Vulkan initializaiton error: $", s);
+ } + log_api->LogInfo("OK");
|