Memory budget and validation logs
parent
d5f1bba4d8
commit
3ea83d40ac
|
@ -12,9 +12,16 @@ constexpr VkDeviceSize MIN_ALLOC_SIZE = 1 << 28;
|
|||
const auto NO_DELETER = Allocator::MemoryDeleter(nullptr);
|
||||
Allocator::memory_ptr Allocator::GetNull() { return Allocator::memory_ptr(nullptr, NO_DELETER); }
|
||||
|
||||
Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info) : device(device) {
|
||||
vkGetPhysicalDeviceMemoryProperties(info.device, &properties);
|
||||
Allocator::Allocator(VkDevice device, const PhysicalDeviceInfo &info): physicalDevice(info.device), device(device) {
|
||||
if(info.hasMemoryBudget()) {
|
||||
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
|
||||
properties2.pNext = &budget;
|
||||
budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
|
||||
} else {
|
||||
LOG_W("No memory budget. Process may go out of memory.");
|
||||
}
|
||||
|
||||
updateProperties();
|
||||
{
|
||||
if (!info.queueIndices.transferFamily.has_value()) {
|
||||
LOG_W("No transfer queue family. Using graphics one");
|
||||
|
@ -183,10 +190,26 @@ Allocator::memory_ptr Allocator::createBuffers(const std::vector<buffer_requirem
|
|||
return memory;
|
||||
}
|
||||
|
||||
void Allocator::updateProperties() {
|
||||
if (hasBudget()) {
|
||||
vkGetPhysicalDeviceMemoryProperties2(physicalDevice, &properties2);
|
||||
#if LOG_TRACE
|
||||
LOG_T("Available heaps:")
|
||||
for (size_t i = 0; i < getProperties().memoryHeapCount; i++) {
|
||||
LOG_T('\t' << i << ": " << budget.heapUsage[i] << '/' << budget.heapBudget[i]);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &properties);
|
||||
}
|
||||
}
|
||||
Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkMemoryPropertyFlags properties) {
|
||||
// Search in existing allocations
|
||||
for (auto& alloc: allocations) {
|
||||
if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) && (this->properties.memoryTypes[alloc->memoryType].propertyFlags & properties) == properties && alloc->size > requirements.size) {
|
||||
if ((requirements.memoryTypeBits & (1 << alloc->memoryType)) &&
|
||||
(getProperties().memoryTypes[alloc->memoryType].propertyFlags & properties) == properties &&
|
||||
alloc->size > requirements.size
|
||||
) {
|
||||
VkDeviceSize start = 0;
|
||||
auto aligned = [&](VkDeviceSize offset) {
|
||||
if (offset % requirements.alignment == 0)
|
||||
|
@ -222,7 +245,8 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM
|
|||
allocInfo.allocationSize = requirements.size;
|
||||
allocInfo.memoryTypeIndex = memIdx.value();
|
||||
} else {
|
||||
LOG_E("No suitable memory heap under budget");
|
||||
LOG_E("No suitable memory heap within memory budget");
|
||||
LOG_D(requirements.memoryTypeBits << ' ' << properties << ' ' << requirements.size);
|
||||
return GetNull();
|
||||
}
|
||||
|
||||
|
@ -233,7 +257,7 @@ Allocator::memory_ptr Allocator::allocate(VkMemoryRequirements requirements, VkM
|
|||
}
|
||||
|
||||
void *ptr = nullptr;
|
||||
if ((this->properties.memoryTypes[allocInfo.memoryTypeIndex].propertyFlags & HOST_EASILY_WRITABLE) == HOST_EASILY_WRITABLE) {
|
||||
if ((getProperties().memoryTypes[allocInfo.memoryTypeIndex].propertyFlags & HOST_EASILY_WRITABLE) == HOST_EASILY_WRITABLE) {
|
||||
vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &ptr);
|
||||
}
|
||||
|
||||
|
@ -270,30 +294,35 @@ void Allocator::copyBuffer(buffer_info src, buffer_info dst, VkDeviceSize size)
|
|||
vkResetCommandBuffer(transferBuffer, 0);
|
||||
}
|
||||
|
||||
std::optional<uint32_t> Allocator::findMemory(uint32_t typeFilter, VkMemoryPropertyFlags requirement, VkDeviceSize size) const {
|
||||
std::optional<uint32_t> Allocator::findMemory(uint32_t typeFilter, VkMemoryPropertyFlags requirement, VkDeviceSize size) {
|
||||
updateProperties();
|
||||
#if LOG_TRACE
|
||||
LOG_T("Available memory:");
|
||||
for (uint32_t i = 0; i < properties.memoryTypeCount; i++) {
|
||||
LOG_T('\t' << i << ": " << ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "local " : "")
|
||||
<< ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "visible " : "")
|
||||
<< ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "coherent " : "")
|
||||
<< ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "cached " : "")
|
||||
<< ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) ? "lazy " : "")
|
||||
<< ((properties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) ? "protected " : "")
|
||||
<< properties.memoryHeaps[properties.memoryTypes[i].heapIndex].size);
|
||||
for (uint32_t i = 0; i < getProperties().memoryTypeCount; i++) {
|
||||
LOG_T('\t' << i << ": "
|
||||
<< getProperties().memoryTypes[i].heapIndex << ' '
|
||||
<< ((getProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ? "local " : "")
|
||||
<< ((getProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ? "visible " : "")
|
||||
<< ((getProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) ? "coherent " : "")
|
||||
<< ((getProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ? "cached " : "")
|
||||
<< ((getProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) ? "lazy " : "")
|
||||
<< ((getProperties().memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_PROTECTED_BIT) ? "protected " : "")
|
||||
<< getProperties().memoryHeaps[getProperties().memoryTypes[i].heapIndex].size);
|
||||
}
|
||||
#endif
|
||||
for (uint32_t i = 0; i < properties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) && (properties.memoryTypes[i].propertyFlags & requirement) == requirement) {
|
||||
for (uint32_t i = 0; i < getProperties().memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) && (getProperties().memoryTypes[i].propertyFlags & requirement) == requirement) {
|
||||
VkDeviceSize usage = size;
|
||||
for(const auto& alloc: allocations) {
|
||||
if(alloc->memoryType == i)
|
||||
usage += alloc->size;
|
||||
}
|
||||
VkDeviceSize budget = properties.memoryHeaps[properties.memoryTypes[i].heapIndex].size;
|
||||
//TODO: use memory budjet extension
|
||||
if(budget >= usage) {
|
||||
const auto heapIndex = getProperties().memoryTypes[i].heapIndex;
|
||||
const VkDeviceSize heapSize = getProperties().memoryHeaps[heapIndex].size;
|
||||
if (heapSize >= usage && (!hasBudget() || budget.heapBudget[heapIndex] >= budget.heapUsage[heapIndex] + size)) {
|
||||
return i;
|
||||
} else {
|
||||
LOG_T("Out of budget " << usage << '/' << heapSize << " : " << budget.heapUsage[heapIndex] + size << '/' << budget.heapBudget[heapIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,10 @@ public:
|
|||
static memory_ptr GetNull();
|
||||
|
||||
private:
|
||||
std::optional<uint32_t> findMemory(uint32_t, VkMemoryPropertyFlags, VkDeviceSize size = 0) const;
|
||||
std::optional<uint32_t> findMemory(uint32_t, VkMemoryPropertyFlags, VkDeviceSize size = 0);
|
||||
constexpr bool hasBudget() const { return properties2.pNext != nullptr; }
|
||||
constexpr const VkPhysicalDeviceMemoryProperties &getProperties() const { return hasBudget() ? properties2.memoryProperties : properties; }
|
||||
void updateProperties();
|
||||
|
||||
struct Allocation {
|
||||
Allocation(VkDevice, VkDeviceMemory, VkDeviceSize, uint32_t, void *ptr);
|
||||
|
@ -79,8 +82,11 @@ private:
|
|||
std::vector<area> areas;
|
||||
};
|
||||
|
||||
VkDevice device;
|
||||
VkPhysicalDeviceMemoryProperties properties;
|
||||
VkPhysicalDevice const physicalDevice;
|
||||
VkDevice const device;
|
||||
VkPhysicalDeviceMemoryProperties properties{};
|
||||
VkPhysicalDeviceMemoryProperties2 properties2{};
|
||||
VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
|
||||
|
||||
VkQueue transferQueue;
|
||||
VkCommandPool transferPool;
|
||||
|
|
|
@ -65,4 +65,12 @@ VkSurfaceFormatKHR PhysicalDeviceInfo::getFormat() const {
|
|||
|
||||
LOG_W("Using suboptimal surface format");
|
||||
return swapDetails.formats[0];
|
||||
}
|
||||
#include <string.h>
|
||||
bool PhysicalDeviceInfo::hasMemoryBudget() const {
|
||||
for (auto extension: optionalExtensions) {
|
||||
if (strcmp(extension, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -29,11 +29,13 @@ struct PhysicalDeviceInfo {
|
|||
swapDetails(SwapChainSupportDetails::Query(device, surface)), queueIndices(QueueFamilyIndices::Query(device, surface)) { }
|
||||
|
||||
VkSurfaceFormatKHR getFormat() const;
|
||||
bool hasMemoryBudget() const;
|
||||
|
||||
GLFWwindow *window;
|
||||
VkPhysicalDevice device = VK_NULL_HANDLE;
|
||||
VkSurfaceKHR surface;
|
||||
SwapChainSupportDetails swapDetails;
|
||||
QueueFamilyIndices queueIndices;
|
||||
std::vector<const char *> optionalExtensions;
|
||||
};
|
||||
}
|
|
@ -15,13 +15,35 @@
|
|||
using namespace render::vk;
|
||||
|
||||
constexpr auto LOAD_DEVICE = true;
|
||||
#if LOG_DEBUG
|
||||
constexpr auto VALIDATION_LAYER = true;
|
||||
#else
|
||||
constexpr auto VALIDATION_LAYER = false;
|
||||
#endif
|
||||
|
||||
void set_current_extent(VkSurfaceCapabilitiesKHR &capabilities, GLFWwindow *ptr);
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugValidationCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
||||
void *pUserData);
|
||||
|
||||
Renderer::Renderer(VkInstance instance, VkDevice device, const PhysicalDeviceInfo& info, const renderOptions& opt):
|
||||
options(opt), instance(instance), surface(info.surface), device(device),
|
||||
physicalInfo(std::make_unique<PhysicalDeviceInfo>(info)) {
|
||||
if constexpr(VALIDATION_LAYER) {
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
createInfo.pfnUserCallback = debugValidationCallback;
|
||||
createInfo.pUserData = nullptr;
|
||||
|
||||
if (vkCreateDebugUtilsMessengerEXT(instance, &createInfo, ALLOC, &debugMessenger) != VK_SUCCESS) {
|
||||
LOG_E("Failed to redirect validation errors");
|
||||
}
|
||||
}
|
||||
|
||||
set_current_extent(physicalInfo->swapDetails.capabilities, physicalInfo->window);
|
||||
|
||||
allocator = std::make_unique<Allocator>(device, *physicalInfo.get());
|
||||
|
@ -67,6 +89,9 @@ Renderer::~Renderer() {
|
|||
|
||||
vkDestroyDevice(device, ALLOC);
|
||||
vkDestroySurfaceKHR(instance, surface, ALLOC);
|
||||
if constexpr(VALIDATION_LAYER) {
|
||||
vkDestroyDebugUtilsMessengerEXT(instance, debugMessenger, ALLOC);
|
||||
}
|
||||
vkDestroyInstance(instance, ALLOC);
|
||||
}
|
||||
|
||||
|
@ -99,6 +124,37 @@ void set_current_extent(VkSurfaceCapabilitiesKHR &capabilities, GLFWwindow* ptr)
|
|||
std::max(capabilities.minImageExtent.width, std::min<uint32_t>(capabilities.maxImageExtent.width, windowSize.first)),
|
||||
std::max(capabilities.minImageExtent.height, std::min<uint32_t>(capabilities.maxImageExtent.height, windowSize.second))};
|
||||
};
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL debugValidationCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData)
|
||||
{
|
||||
switch (messageSeverity) {
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||
LOG_E("[VK] " << pCallbackData->pMessage);
|
||||
break;
|
||||
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||
LOG_W("[VK] " << pCallbackData->pMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_I("[VK] " << pCallbackData->pMessage);
|
||||
break;
|
||||
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
||||
LOG_D("[VK] " << pCallbackData->pMessage);
|
||||
break;
|
||||
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
||||
LOG_T("[VK] " << pCallbackData->pMessage);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
bool Renderer::Load(Window& window, const renderOptions& opt) {
|
||||
Window::CreateInfo windowInfo;
|
||||
|
@ -136,23 +192,33 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
vkEnumerateInstanceExtensionProperties(nullptr, &availableExtensionCount, availableExtensions.data());
|
||||
|
||||
#if LOG_TRACE
|
||||
LOG_T("Available extensions:");
|
||||
LOG_T("Available instance extensions:");
|
||||
for (const auto &extension : availableExtensions) {
|
||||
LOG_T('\t' << extension.extensionName << " : " << extension.specVersion);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto hasExtension = [&availableExtensions](const char *extension) {
|
||||
return std::any_of(availableExtensions.begin(), availableExtensions.end(), [&extension](const VkExtensionProperties &ex) { return strcmp(ex.extensionName, extension) == 0; });
|
||||
};
|
||||
|
||||
uint32_t glfwExtensionCount = 0;
|
||||
const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||
extensions.reserve(glfwExtensionCount);
|
||||
for (uint32_t i = 0; i < glfwExtensionCount; i++) {
|
||||
if (std::none_of(availableExtensions.begin(), availableExtensions.end(), [&](const VkExtensionProperties &ex) { return strcmp(ex.extensionName, glfwExtensions[i]) == 0; })) {
|
||||
if (!hasExtension(glfwExtensions[i])) {
|
||||
LOG_E("Missing required glfw extension " << glfwExtensions[i]);
|
||||
return false;
|
||||
}
|
||||
extensions.push_back(glfwExtensions[i]);
|
||||
}
|
||||
|
||||
if constexpr (VALIDATION_LAYER) {
|
||||
if (hasExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
} else {
|
||||
LOG_W("Debug utils extension unavailable");
|
||||
}
|
||||
}
|
||||
}
|
||||
createInfo.enabledExtensionCount = extensions.size();
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
@ -181,11 +247,6 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
} else {
|
||||
LOG_W("Validation layer unavailable");
|
||||
}
|
||||
if (hasLayer(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
|
||||
layers.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
} else {
|
||||
LOG_W("Debug utils layer unavailable");
|
||||
}
|
||||
}
|
||||
}
|
||||
createInfo.enabledLayerCount = layers.size();
|
||||
|
@ -213,7 +274,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
}
|
||||
|
||||
PhysicalDeviceInfo physicalInfo;
|
||||
std::vector<const char *> requiredExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
const std::vector<const char *> requiredExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
const std::vector<const char *> optionalExtensions = {VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME};
|
||||
{
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
|
@ -232,8 +294,9 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
|
||||
if (!deviceFeatures.geometryShader)
|
||||
continue;
|
||||
auto infos = PhysicalDeviceInfo(window.getPtr(), device, surface);
|
||||
|
||||
//FIXME: if (!deviceFeatures.geometryShader) continue;
|
||||
|
||||
{
|
||||
uint32_t availableExtensionsCount;
|
||||
|
@ -241,12 +304,24 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
std::vector<VkExtensionProperties> availableExtensions(availableExtensionsCount);
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &availableExtensionsCount, availableExtensions.data());
|
||||
|
||||
if (std::any_of(requiredExtensions.begin(), requiredExtensions.end(), [&](const char *required) {
|
||||
return std::none_of(availableExtensions.begin(), availableExtensions.end(), [&](const VkExtensionProperties &ex) {
|
||||
return strcmp(ex.extensionName, required) == 0;
|
||||
});
|
||||
}))
|
||||
#if LOG_TRACE
|
||||
LOG_T("Available device extensions:");
|
||||
for (const auto &extension : availableExtensions) {
|
||||
LOG_T('\t' << extension.extensionName << " : " << extension.specVersion);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto hasExtension = [&availableExtensions](const char *extension) {
|
||||
return std::any_of(availableExtensions.begin(), availableExtensions.end(), [&extension](const VkExtensionProperties &ex) { return strcmp(ex.extensionName, extension) == 0; });
|
||||
};
|
||||
|
||||
if (std::any_of(requiredExtensions.begin(), requiredExtensions.end(), [&](const char *required) { return !hasExtension(required); }))
|
||||
continue;
|
||||
|
||||
for (auto extension: optionalExtensions) {
|
||||
if (hasExtension(extension))
|
||||
infos.optionalExtensions.push_back(extension);
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
|
@ -255,7 +330,6 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
//TODO: check others limits
|
||||
|
||||
auto infos = PhysicalDeviceInfo(window.getPtr(), device, surface);
|
||||
if (!infos.queueIndices.isComplete())
|
||||
continue;
|
||||
if (infos.queueIndices.isOptimal())
|
||||
|
@ -299,6 +373,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
//TODO:
|
||||
|
||||
std::vector<const char*> extensions(requiredExtensions);
|
||||
extensions.insert(extensions.end(), physicalInfo.optionalExtensions.begin(), physicalInfo.optionalExtensions.end());
|
||||
VkDeviceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
|
@ -306,8 +382,8 @@ bool Renderer::Load(Window& window, const renderOptions& opt) {
|
|||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
createInfo.enabledLayerCount = layers.size();
|
||||
createInfo.ppEnabledLayerNames = layers.data();
|
||||
createInfo.enabledExtensionCount = requiredExtensions.size();
|
||||
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
|
||||
createInfo.enabledExtensionCount = extensions.size();
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
if (vkCreateDevice(physicalInfo.device, &createInfo, ALLOC, &device) != VK_SUCCESS) {
|
||||
LOG_E("Failed to bind graphic device");
|
||||
|
|
|
@ -42,6 +42,7 @@ private:
|
|||
renderOptions options;
|
||||
|
||||
VkInstance instance;
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
VkSurfaceKHR surface;
|
||||
VkDevice device;
|
||||
|
||||
|
|
Loading…
Reference in New Issue