Skip to content

Commit

Permalink
Create and delete Vulkan context to gather its capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
lhog committed Nov 27, 2022
1 parent d2541c7 commit e6ac54e
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 1 deletion.
7 changes: 7 additions & 0 deletions docker-build/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ ENV CCACHE_DIR=/ccache
ENV CCACHE_CONFIGPATH=/etc/ccache.conf
ENV PATH="/usr/lib/ccache:${PATH}"

# Install Vulkan SDK
RUN apt install wget; \
wget -q https://sdk.lunarg.com/sdk/download/latest/linux/vulkan-sdk.tar.gz; \
mkdir /vulkan-sdk && tar -xf vulkan-sdk.tar.gz --strip-components=1 -C /vulkan-sdk; \
rm -rf vulkan-sdk.tar.gz


COPY scripts /scripts
ENV PATH="/scripts:${PATH}"

Expand Down
2 changes: 2 additions & 0 deletions docker-build/scripts/02_configure.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ if [ "${PLATFORM}" == "linux-64" ]; then
elif [ "${PLATFORM}" == "windows-64" ]; then
EXTRA_CMAKE_ARGS+=(
-DMINGWLIBS=${LIBS_DIR}
-DVulkan_INCLUDE_DIR=/vulkan-sdk/x86_64/include
-DVulkan_LIBRARY=/vulkan-sdk/x86_64/lib
)
fi

Expand Down
1 change: 1 addition & 0 deletions docker-build/scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
source /vulkan-sdk/setup-env.sh
COMMAND=$1
shift

Expand Down
2 changes: 2 additions & 0 deletions rts/Rendering/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ set(sources_engine_Rendering
"${CMAKE_CURRENT_SOURCE_DIR}/GL/VAO.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/glExtra.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GL/myGL.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/VK/VkInit.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/VK/VkInfo.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GlobalRendering.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/GroundFlash.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/CommandDrawer.cpp"
Expand Down
5 changes: 4 additions & 1 deletion rts/Rendering/GlobalRendering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Rendering/GL/RenderBuffers.h"
#include "Rendering/GL/myGL.h"
#include "Rendering/GL/FBO.h"
#include "Rendering/VK/VkInfo.h"
#include "Rendering/UniformConstants.h"
#include "Rendering/Fonts/glFont.h"
#include "System/bitops.h"
Expand Down Expand Up @@ -623,11 +624,13 @@ void CGlobalRendering::KillSDL() const {
SDL_Quit();
}


void CGlobalRendering::PostInit() {
#ifndef HEADLESS
glewExperimental = true;
#endif

VkInfo::PrintInfo();

glewInit();
// glewInit sets GL_INVALID_ENUM, get rid of it
glGetError();
Expand Down
110 changes: 110 additions & 0 deletions rts/Rendering/VK/VkInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "VkInfo.h"
#include "VkInit.h"

#include "System/Log/ILog.h"
#include "fmt/format.h"

#ifndef HEADLESS
void VkInfo::PrintInfoImpl(const char* funcName)
{
LOG("[VkInfo::%s]", funcName);

const auto& vkc = VkCoreObjects::GetInstance();

LOG("\tInstance VK API version : %s", vkc.GetVulkanAPI().c_str());

LOG("\tFound the following VK devices:");
for (const auto& pd : vkc.GetPhysDevices()) {
const auto& prop = pd.getProperties();
LOG("\t\t%s (%s)", &prop.deviceName[0], vk::to_string(prop.deviceType).c_str());
}

{
const auto& prop = vkc.GetBestPhysDevice().getProperties();
LOG("\tSelected best device: %s", &prop.deviceName[0]);
LOG("\t\tDevice VK API version : %s", vkc.GetVulkanAPI(prop.apiVersion).c_str());
//prop.limits
}

const auto& instanceExtensions = vkc.GetInstanceExtensions();
const auto& phDeviceExtensions = vkc.GetPhysDeviceExtensions();

const bool mem2 =
vkc.HasExtension(instanceExtensions, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) &&
vkc.HasExtension(phDeviceExtensions, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);

std::array<uint32_t, 3> heapMemInfo = {0u, 0u, 0u}; //used, budget, total
if (mem2) {
const auto memoryProperties2 = vkc.GetBestPhysDevice().getMemoryProperties2<vk::PhysicalDeviceMemoryProperties2, vk::PhysicalDeviceMemoryBudgetPropertiesEXT>();
const auto& memoryProperties = memoryProperties2.get<vk::PhysicalDeviceMemoryProperties2>().memoryProperties;
const auto& memoryBudgetProperties = memoryProperties2.get<vk::PhysicalDeviceMemoryBudgetPropertiesEXT>();

for (uint32_t i = 0; i < memoryProperties.memoryHeapCount; ++i) {
if (!(memoryProperties.memoryHeaps[i].flags & vk::MemoryHeapFlagBits::eDeviceLocal))
continue;

heapMemInfo[0] += memoryBudgetProperties.heapUsage[i] / 1024 / 1024;
heapMemInfo[1] += memoryBudgetProperties.heapBudget[i] / 1024 / 1024;
heapMemInfo[2] += memoryProperties.memoryHeaps[i].size / 1024 / 1024;
}
}
else {
const auto memoryProperties = vkc.GetBestPhysDevice().getMemoryProperties();
for (uint32_t i = 0; i < memoryProperties.memoryHeapCount; ++i) {
if (!(memoryProperties.memoryHeaps[i].flags & vk::MemoryHeapFlagBits::eDeviceLocal))
continue;

heapMemInfo[2] += memoryProperties.memoryHeaps[i].size / 1024 / 1024;
}
}

const std::string memStr = fmt::format("{}/{}/{}",
heapMemInfo[0] > 0 ? std::to_string(heapMemInfo[0]) : "-",
heapMemInfo[1] > 0 ? std::to_string(heapMemInfo[1]) : "-",
heapMemInfo[2]
);

LOG("\t\tVRAM : %s MB (used/budget/total)", memStr.c_str());

static constexpr std::array requiredDeviceExtensions {
"VK_KHR_dedicated_allocation",
"VK_KHR_create_renderpass2",
"VK_KHR_draw_indirect_count",
"VK_KHR_imageless_framebuffer",
"VK_KHR_uniform_buffer_standard_layout",
"VK_EXT_descriptor_indexing",
"VK_EXT_shader_viewport_index_layer",
"VK_KHR_dynamic_rendering",
"VK_KHR_synchronization2",
"VK_EXT_extended_dynamic_state",
"VK_EXT_extended_dynamic_state2",
};

static constexpr size_t paddingMaxSize = 40;
for (const auto& rde : requiredDeviceExtensions) {
const std::string padding(paddingMaxSize - std::string_view(rde).size(), ' ');
LOG("\t\t%s%s : %i", rde, padding.c_str(), vkc.HasExtension(phDeviceExtensions, rde));
}

VkCoreObjects::KillInstance();
}
#else
void VkInfo::PrintInfoImpl(const char* funcName) {}
#endif



void VkInfo::PrintInfo()
{
#ifndef HEADLESS
#ifndef HAS_VULKAN
LOG("[VkInfo::%s] Compiled without VULKAN support", __func__);
#else
try {
PrintInfoImpl(__func__);
} catch (const std::exception& e) {
LOG("[VkInfo::%s] Runtime error: \"%s\"", __func__, e.what());
}
#endif
#endif
}
8 changes: 8 additions & 0 deletions rts/Rendering/VK/VkInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

class VkInfo {
public:
static void PrintInfo();
private:
static void PrintInfoImpl(const char* funcName);
};
86 changes: 86 additions & 0 deletions rts/Rendering/VK/VkInit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#ifdef HAS_VULKAN

#include <string_view>

#include "VkInit.h"
#include "fmt/format.h"

bool VkPhysicalDevicesCompare(const vk::PhysicalDevice& lhs, const vk::PhysicalDevice& rhs)
{
const auto lhsDiscrete = static_cast<uint8_t>(lhs.getProperties().deviceType == vk::PhysicalDeviceType::eDiscreteGpu);
const auto rhsDiscrete = static_cast<uint8_t>(rhs.getProperties().deviceType == vk::PhysicalDeviceType::eDiscreteGpu);

if (lhsDiscrete > rhsDiscrete) return true;
if (lhsDiscrete < rhsDiscrete) return false;

VkDeviceSize lhsMS = VkCoreObjects::GetVRAMSize(lhs);
VkDeviceSize rhsMS = VkCoreObjects::GetVRAMSize(rhs);

if (lhsMS > rhsMS) return true;
if (lhsMS < rhsMS) return false;

return false;
};

VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
VkCoreObjects::VkCoreObjects()
{
dl = std::make_unique<vk::DynamicLoader>();

PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl->getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);

// Determine what API version is available
apiVersion = vk::enumerateInstanceVersion();

vk::ApplicationInfo applicationInfo("spring", 1, "spring", 1, apiVersion);
vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo);
instance = vk::createInstance(instanceCreateInfo);
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);

instExtensionProperties = vk::enumerateInstanceExtensionProperties();

physicalDevices = instance.enumeratePhysicalDevices();
std::sort(physicalDevices.begin(), physicalDevices.end(), VkPhysicalDevicesCompare);

physicalDevice = physicalDevices.front();
pdevExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties();
}

std::string VkCoreObjects::GetVulkanAPI(uint32_t apiVersion)
{
return fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(apiVersion), VK_API_VERSION_MINOR(apiVersion), VK_API_VERSION_PATCH(apiVersion));
}

std::string VkCoreObjects::GetVulkanAPI() const
{
return GetVulkanAPI(apiVersion);
}

VkDeviceSize VkCoreObjects::GetVRAMSize(const vk::PhysicalDevice& phd)
{
VkDeviceSize memSize = 0;
const auto memProp = phd.getMemoryProperties();
for (auto hi = 0; hi < memProp.memoryHeapCount; ++hi) {
if (memProp.memoryHeaps[hi].flags & vk::MemoryHeapFlagBits::eDeviceLocal)
memSize += memProp.memoryHeaps[hi].size;
}

return memSize;
}

bool VkCoreObjects::HasExtension(const std::vector<vk::ExtensionProperties>& es, const char* e)
{
return std::find_if(es.begin(), es.end(),
[e](const auto& item) {
return std::string_view(item.extensionName).compare(e) == 0;
}
) != es.end();
}

VkCoreObjects::~VkCoreObjects()
{
instance.destroy();
}

#endif
50 changes: 50 additions & 0 deletions rts/Rendering/VK/VkInit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once
#ifdef HAS_VULKAN

#include <vector>
#include <memory>

#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
#include <vulkan/vulkan.hpp>

class VkCoreObjects {
public:
VkCoreObjects();
~VkCoreObjects();

const auto& GetInstanceExtensions() const { return instExtensionProperties; }
const auto& GetPhysDeviceExtensions() const { return pdevExtensionProperties; }
const auto& GetPhysDevices() const { return physicalDevices; }
const auto& GetBestPhysDevice() const { return physicalDevice; }

std::string GetVulkanAPI() const;
static std::string GetVulkanAPI(uint32_t apiVersion);

static VkDeviceSize GetVRAMSize(const vk::PhysicalDevice& phd);
static bool HasExtension(const std::vector<vk::ExtensionProperties>& es, const char* e);

static VkCoreObjects& GetInstance() {
if (!vkCoreObjects) {
vkCoreObjects = std::make_unique<VkCoreObjects>();
}
return *vkCoreObjects;
}
static void KillInstance() { vkCoreObjects = nullptr; }
private:
static inline std::unique_ptr<VkCoreObjects> vkCoreObjects = nullptr;

std::unique_ptr<vk::DynamicLoader> dl;

vk::Instance instance;
std::vector<vk::ExtensionProperties> instExtensionProperties;
std::vector<vk::ExtensionProperties> pdevExtensionProperties;

std::vector<vk::PhysicalDevice> physicalDevices;
vk::PhysicalDevice physicalDevice;

uint32_t apiVersion;

//static constexpr
};

#endif
5 changes: 5 additions & 0 deletions rts/builds/legacy/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ if("${SDL2_VERSION_STRING}" VERSION_LESS "2")
message(FATAL_ERROR "Found SDL v${SDL2_VERSION_STRING} while 2 is required!")
endif()

find_package(Vulkan)
if (Vulkan_FOUND)
list(APPEND engineIncludes ${Vulkan_INCLUDE_DIRS})
add_definitions(-DHAS_VULKAN)
endif (Vulkan_FOUND)

set(OpenGL_GL_PREFERENCE LEGACY)
find_package_static(OpenGL REQUIRED)
Expand Down

0 comments on commit e6ac54e

Please sign in to comment.