Related
I'm trying to import a host memory as a staging buffer in Vulkan.
In the future, the plan is to use a shared memory as staging vertex buffer (in the host). But I can't manage to successfully import a previously allocated memory into vulkan.
The return of vkAllocateMemory is VK_ERROR_OUT_OF_DEVICE_MEMORY.
Here is my code:
void createMallocedBuffer(VkPhysicalDevice const& physicalDevice,
VkDevice const& device,
void * data,
VkBuffer & buffer,
VkDeviceMemory& bufferMemory )
{
VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemHostProp;
externalMemHostProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
externalMemHostProp.pNext = nullptr;
VkPhysicalDeviceProperties physicalDeviceProps;
VkPhysicalDeviceProperties2 physicalDeviceProps2;
physicalDeviceProps2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProps2.pNext = &externalMemHostProp;
physicalDeviceProps2.properties = physicalDeviceProps;
vkGetPhysicalDeviceProperties2(physicalDevice, &physicalDeviceProps2);
data = malloc(externalMemHostProp.minImportedHostPointerAlignment);
VkExternalMemoryHandleTypeFlagBits externalMemoryFlagBits {
VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT
};
VkMemoryHostPointerPropertiesEXT pointersProps {
.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
.pNext = nullptr,
};
vkGetMemoryHostPointerPropertiesEXT(device,
externalMemoryFlagBits,
data,
&pointersProps);
VkExternalMemoryBufferCreateInfo externalMemCreateInfo {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
.pNext = nullptr,
.handleTypes = externalMemoryFlagBits,
};
VkBufferUsageFlags bufferUsage {
VK_BUFFER_USAGE_TRANSFER_SRC_BIT
};
VkBufferCreateInfo bufferInfo {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = &externalMemCreateInfo,
.flags = 0,
.size = externalMemHostProp.minImportedHostPointerAlignment,
.usage = bufferUsage,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
if (vkCreateBuffer(device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS)
{
throw std::runtime_error("failed to create buffer!");
}
VkMemoryHostPointerPropertiesEXT memoryHostPointerProperties {
.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT,
};
if (auto result = vkGetMemoryHostPointerPropertiesEXT(device, externalMemoryFlagBits, data, &memoryHostPointerProperties);
result != VK_SUCCESS)
{
// printError(result);
}
VkMemoryPropertyFlags memProperties {
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
};
VkImportMemoryHostPointerInfoEXT importHostPointerInfo {
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT,
.pNext = nullptr,
.handleType = externalMemoryFlagBits,
.pHostPointer = data,
};
VkMemoryRequirements memRequirements;
vkGetBufferMemoryRequirements(device, buffer, &memRequirements);
auto memTypeIndex = findMemoryType(physicalDevice, memRequirements.memoryTypeBits, memProperties);
VkMemoryAllocateInfo allocInfo {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = &importHostPointerInfo,
.allocationSize = externalMemHostProp.minImportedHostPointerAlignment,
.memoryTypeIndex = memTypeIndex,
};
if (auto result = vkAllocateMemory(device, &allocInfo, nullptr, &bufferMemory);
result != VK_SUCCESS)
{
// printError(result);
throw std::runtime_error("failed to allocate buffer memory!");
}
vkBindBufferMemory(device, buffer, bufferMemory, 0);
}
uint32_t findMemoryType(VkPhysicalDevice const& physicalDevice,
uint32_t const typeFilter,
VkMemoryPropertyFlags const& properties )
{
VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
for (uint32_t i = 0; i < memProperties.memoryTypeCount; ++i)
{
auto const typeSelect = (typeFilter & (1 << i));
auto const flagSelect = (memProperties.memoryTypes[i].propertyFlags & properties);
if (typeSelect && (flagSelect == properties))
{
return i;
}
}
throw std::runtime_error("failed to find suitable memory type!");
}
I'm learning Vulkan following vulkan-tutorial.com.
I'm stuck because I can't figure out why I'm getting this error when creating the graphics pipeline.
VUID-VkPipelineShaderStageCreateInfo-module-parameter(ERROR / SPEC): msgNum: 0 - Invalid VkShaderModule Object 0x70000000007. The Vulkan spec states: module must be a valid VkShaderModule handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-module-parameter)
Objects: 1
[0] 0x70000000007, type: 15, name: NULL
VUID-VkPipelineShaderStageCreateInfo-module-parameter(ERROR / SPEC): msgNum: 0 - Invalid VkShaderModule Object 0x80000000008. The Vulkan spec states: module must be a valid VkShaderModule handle (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkPipelineShaderStageCreateInfo-module-parameter)
Objects: 1
[0] 0x80000000008, type: 15, name: NULL
This is how I create the shader modules:
auto createShaderModule = [](const char* fileName)
{
int len;
char* data = readBinFile(len, fileName);
VkShaderModuleCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
info.codeSize = len;
info.pCode = (u32*)data;
VkShaderModule module;
const VkResult res = vkCreateShaderModule(vk.device, &info, nullptr, &module);
if(res != VK_SUCCESS) {
printf("Error: could not create vertex shader module\n");
exit(-1);
}
delete[] data;
return module;
};
VkShaderModule vertShadModule = createShaderModule(SHADERS_PATH"/simple.vert.glsl.spv");
VkShaderModule fragShadModule = createShaderModule(SHADERS_PATH"/simple.frag.glsl.spv");
auto createStage = [](VkShaderStageFlagBits stage, VkShaderModule module)
{
VkPipelineShaderStageCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
info.stage = stage;
info.module = module;
info.pName = "main";
info.pSpecializationInfo = nullptr; // allows to specify values for shader constants
return info;
};
const VkPipelineShaderStageCreateInfo stagesInfos[] = {
createStage(VK_SHADER_STAGE_VERTEX_BIT, vertShadModule),
createStage(VK_SHADER_STAGE_FRAGMENT_BIT, fragShadModule)
};
As you can see, I'm checking that the shader modules where created ok (VK_SUCCESS). But still the validation layers say that the modules are invalid.
This is the whole code:
#include <stdio.h>
#include <vector>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vulkan/vulkan.h>
typedef const char* const ConstStr;
typedef uint8_t u8;
typedef uint32_t u32;
typedef uint64_t u64;
GLFWwindow* window;
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
struct VulkanData
{
VkInstance inst;
VkSurfaceKHR surface;
VkPhysicalDevice physicalDevice;
VkDevice device;
u32 graphicsQueueFamily, presentationQueueFamily;
VkQueue graphicsQueue;
VkQueue presentationQueue;
VkSwapchainKHR swapchain;
VkImageView swapchainImageViews[2];
VkRenderPass renderPass;
VkPipeline pipeline;
} vk;
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkanDebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData) {
printf("%s\n", pCallbackData->pMessage);
return VK_FALSE;
}
void initVulkan()
{
{ // create vulkan instance
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pNext = nullptr;
appInfo.pApplicationName = "hello";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "hello_engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
VkInstanceCreateInfo instInfo = {};
instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instInfo.pNext = nullptr;
instInfo.flags = 0;
instInfo.pApplicationInfo = &appInfo;
static ConstStr layers[] = {
#if !defined(NDEBUG)
"VK_LAYER_KHRONOS_validation"
#endif
};
instInfo.enabledLayerCount = std::size(layers);
instInfo.ppEnabledLayerNames = layers;
u32 numGlfwExtensions;
ConstStr* glfwExtensions = glfwGetRequiredInstanceExtensions(&instInfo.enabledExtensionCount);
std::vector<const char*> extensions;
extensions.reserve(numGlfwExtensions + 1);
for(u32 i = 0; i < numGlfwExtensions; i++)
extensions.push_back(glfwExtensions[i]);
#ifndef NDEBUG
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
instInfo.ppEnabledExtensionNames = glfwGetRequiredInstanceExtensions(&instInfo.enabledExtensionCount);
if (vkCreateInstance(&instInfo, nullptr, &vk.inst) != VK_SUCCESS) {
printf("Error creating vulkan instance\n");
exit(-1);
}
}
// create window surface
if(glfwCreateWindowSurface(vk.inst, window, nullptr, &vk.surface) != VK_SUCCESS) {
printf("Error: can't create window surface\n");
exit(-1);
}
{ // pick physical device
u32 numPhysicalDevices;
vkEnumeratePhysicalDevices(vk.inst, &numPhysicalDevices, nullptr);
std::vector<VkPhysicalDevice> physicalDevices(numPhysicalDevices);
if(numPhysicalDevices == 0) {
printf("Error: there are no devices supporting Vulkan\n");
exit(-1);
}
vkEnumeratePhysicalDevices(vk.inst, &numPhysicalDevices, &physicalDevices[0]);
auto compareProps = [](
const VkPhysicalDeviceProperties& propsA,
const VkPhysicalDeviceMemoryProperties& memPropsA,
const VkPhysicalDeviceProperties& propsB,
const VkPhysicalDeviceMemoryProperties& memPropsB) -> bool
{
auto calcDeviceTypeScore = [](VkPhysicalDeviceType a) -> u8 {
switch(a) {
case VK_PHYSICAL_DEVICE_TYPE_CPU: return 1;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 2;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 3;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 4;
default: return 0;
}
};
const u8 scoreA = calcDeviceTypeScore(propsA.deviceType);
const u8 scoreB = calcDeviceTypeScore(propsB.deviceType);
if(scoreA != scoreB)
return scoreA < scoreB;
auto calcMem = [](const VkPhysicalDeviceMemoryProperties& a) -> u64
{
u64 mem = 0;
for(u32 i = 0; i < a.memoryHeapCount; i++) {
if(a.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
mem = std::max(mem, a.memoryHeaps[i].size);
}
return mem;
};
u32 memA = calcMem(memPropsA);
u32 memB = calcMem(memPropsB);
return memA < memB;
};
VkPhysicalDeviceProperties bestProps;
vkGetPhysicalDeviceProperties(physicalDevices[0], &bestProps);
VkPhysicalDeviceMemoryProperties bestMemProps;
vkGetPhysicalDeviceMemoryProperties(physicalDevices[0], &bestMemProps);
u32 bestI = 0;
for(u32 i = 1; i < numPhysicalDevices; i++) {
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memProps;
vkGetPhysicalDeviceProperties(physicalDevices[i], &props);
vkGetPhysicalDeviceMemoryProperties(physicalDevices[i], &memProps);
if(compareProps(bestProps, bestMemProps, props, memProps)) {
bestProps = props;
bestMemProps = memProps;
bestI = i;
}
}
vk.physicalDevice = physicalDevices[bestI];
}
{ // create logical device
u32 numQueueFamilies;
vkGetPhysicalDeviceQueueFamilyProperties(vk.physicalDevice, &numQueueFamilies, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilyProps(numQueueFamilies);
vkGetPhysicalDeviceQueueFamilyProperties(vk.physicalDevice, &numQueueFamilies, &queueFamilyProps[0]);
vk.graphicsQueueFamily = numQueueFamilies;
vk.presentationQueueFamily = numQueueFamilies;
for(u32 i = 0; i < numQueueFamilies; i++) {
if(queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
vk.graphicsQueueFamily = i;
VkBool32 supportPresentation;
vkGetPhysicalDeviceSurfaceSupportKHR(vk.physicalDevice, i, vk.surface, &supportPresentation);
if(supportPresentation)
vk.presentationQueueFamily = i;
}
if(vk.graphicsQueueFamily == numQueueFamilies) {
printf("Error: there is no queue that supports graphics\n");
exit(-1);
}
if(vk.presentationQueueFamily == numQueueFamilies) {
printf("Error: there is no queue that supports presentation\n");
exit(-1);
}
u32 queueFamilyInds[2] = {vk.graphicsQueueFamily};
u32 numQueues;
if(vk.graphicsQueueFamily == vk.presentationQueueFamily) {
numQueues = 1;
}
else {
numQueues = 2;
queueFamilyInds[1] = vk.graphicsQueueFamily;
}
const float queuePriorities[] = {1.f};
VkDeviceQueueCreateInfo queueCreateInfos[2] = {};
for(u32 i = 0; i < numQueues; i++)
{
queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfos[i].queueFamilyIndex = queueFamilyInds[i];
queueCreateInfos[i].queueCount = 1;
queueCreateInfos[i].pQueuePriorities = queuePriorities;
}
VkDeviceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
info.queueCreateInfoCount = numQueues;
info.pQueueCreateInfos = queueCreateInfos;
info.enabledLayerCount = 0;
info.ppEnabledLayerNames = nullptr;
ConstStr deviceExtensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
info.enabledExtensionCount = std::size(deviceExtensions);
info.ppEnabledExtensionNames = deviceExtensions;
const VkResult deviceCreatedOk = vkCreateDevice(vk.physicalDevice, &info, nullptr, &vk.device);
if(deviceCreatedOk != VK_SUCCESS) {
printf("Error: couldn't create device\n");
exit(-1);
}
vkGetDeviceQueue(vk.device, vk.graphicsQueueFamily, 0, &vk.graphicsQueue);
vkGetDeviceQueue(vk.device, vk.presentationQueueFamily, 0, &vk.presentationQueue);
// queues
// https://community.khronos.org/t/guidelines-for-selecting-queues-and-families/7222
// https://www.reddit.com/r/vulkan/comments/aara8f/best_way_for_selecting_queuefamilies/
// https://stackoverflow.com/questions/37575012/should-i-try-to-use-as-many-queues-as-possible
}
{ // crete swapchain
VkSurfaceCapabilitiesKHR surfaceCpabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk.physicalDevice, vk.surface, &surfaceCpabilities);
VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = vk.surface;
createInfo.minImageCount = 2;
createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; // TODO: I think this format has mandatory support but I'm not sure
createInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
createInfo.imageExtent = surfaceCpabilities.currentExtent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 1;
createInfo.pQueueFamilyIndices = &vk.presentationQueueFamily;
createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
createInfo.clipped = VK_FALSE;
//createInfo.oldSwapchain = ; // this can be used to recycle the old swapchain when resizing the window
vkCreateSwapchainKHR(vk.device, &createInfo, nullptr, &vk.swapchain);
}
{ // create image views of the swapchain
u32 imageCount;
VkImage images[2];
vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &imageCount, nullptr);
assert(imageCount == 2);
vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &imageCount, images);
for(u32 i = 0; i < 2; i++)
{
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = images[0];
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = VK_FORMAT_B8G8R8A8_SRGB;
// info.components = ; // channel swizzling VK_COMPONENT_SWIZZLE_IDENTITY is 0
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 1;
vkCreateImageView(vk.device, &info, nullptr, &vk.swapchainImageViews[i]);
}
}
}
#define SHADERS_PATH "shaders"
char* readBinFile(int& len, const char* fileName)
{
FILE* file = fopen(fileName, "rb");
fseek(file, 0, SEEK_END);
len = ftell(file);
rewind(file);
char* txt = new char[len];
fread(txt, len, 1, file);
fclose(file);
return txt;
}
void createTheGraphicsPipeline()
{
auto createShaderModule = [](const char* fileName)
{
int len;
char* data = readBinFile(len, fileName);
VkShaderModuleCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
info.codeSize = len;
info.pCode = (u32*)data;
VkShaderModule module;
const VkResult res = vkCreateShaderModule(vk.device, &info, nullptr, &module);
if(res != VK_SUCCESS) {
printf("Error: could not create vertex shader module\n");
exit(-1);
}
delete[] data;
return module;
};
VkShaderModule vertShadModule = createShaderModule(SHADERS_PATH"/simple.vert.glsl.spv");
VkShaderModule fragShadModule = createShaderModule(SHADERS_PATH"/simple.frag.glsl.spv");
auto createStage = [](VkShaderStageFlagBits stage, VkShaderModule module)
{
VkPipelineShaderStageCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
info.stage = stage;
info.module = module;
info.pName = "main";
info.pSpecializationInfo = nullptr; // allows to specify values for shader constants
return info;
};
const VkPipelineShaderStageCreateInfo stagesInfos[] = {
createStage(VK_SHADER_STAGE_VERTEX_BIT, vertShadModule),
createStage(VK_SHADER_STAGE_FRAGMENT_BIT, fragShadModule)
};
VkPipelineVertexInputStateCreateInfo vertInputInfo = {};
vertInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertInputInfo.vertexBindingDescriptionCount = 0;
vertInputInfo.pVertexBindingDescriptions = nullptr;
vertInputInfo.vertexAttributeDescriptionCount = 0;
vertInputInfo.pVertexAttributeDescriptions = nullptr;
VkPipelineInputAssemblyStateCreateInfo assemblyInfo = {};
assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
assemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
assemblyInfo.primitiveRestartEnable = VK_FALSE;
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = WINDOW_WIDTH;
viewport.height = WINDOW_HEIGHT;
viewport.minDepth = 0;
viewport.maxDepth = 1;
VkRect2D scissor;
scissor.offset = {0, 0};
scissor.extent = {WINDOW_WIDTH, WINDOW_HEIGHT};
VkPipelineViewportStateCreateInfo viewportInfo = {};
viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportInfo.viewportCount = 1;
viewportInfo.pViewports = &viewport;
viewportInfo.scissorCount = 1;
viewportInfo.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizerInfo = {};
rasterizerInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizerInfo.depthClampEnable = VK_FALSE; // enabling will clamp depth instead of discarding which can be useful when rendering shadowmaps
rasterizerInfo.rasterizerDiscardEnable = VK_FALSE; // if enable discards all geometry (could be useful for transformfeedback)
rasterizerInfo.polygonMode = VK_POLYGON_MODE_FILL;
rasterizerInfo.lineWidth = 1.f;
rasterizerInfo.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizerInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizerInfo.depthBiasEnable = VK_FALSE; // useful for shadow mapping
VkPipelineMultisampleStateCreateInfo multisampleInfo = {}; // multisampling: it works by combining the fragment shader results of multiple polygons that rasterize to the same pixel
multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleInfo.sampleShadingEnable = VK_FALSE;
multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
//VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {};
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_G_BIT;
colorBlendAttachment.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendInfo = {};
colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendInfo.attachmentCount = 1;
colorBlendInfo.pAttachments = &colorBlendAttachment;
const VkDynamicState dynamicStates[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicStateInfo = {};
dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateInfo.dynamicStateCount = 2;
dynamicStateInfo.pDynamicStates = dynamicStates;
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
VkPipelineLayout pipelineLayout;
vkCreatePipelineLayout(vk.device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
vkDestroyShaderModule(vk.device, fragShadModule, nullptr);
vkDestroyShaderModule(vk.device, vertShadModule, nullptr);
// -- create the renderPass ---
VkAttachmentDescription attachmentDesc = {};
attachmentDesc.format = VK_FORMAT_B8G8R8A8_SRGB;
attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // clear before rendering
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // store the result after rendering
attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // we don't care. This doesn't guarantee that the contents of th eimage will be preserved, but that's not a problem since we are going to clear it anyways
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0; // the index in the attachemntDescs array (we only have one)
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // this is an output attachment so we use this enum for best performance
VkSubpassDescription subpassDesc = {};
subpassDesc.colorAttachmentCount = 1;
subpassDesc.pColorAttachments = &colorAttachmentRef; // the index of the attachement in this array is referenced in the shader with "layout(location = 0) out vec4 o_color"
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &attachmentDesc;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpassDesc;
if(vkCreateRenderPass(vk.device, &renderPassInfo, nullptr, &vk.renderPass) != VK_SUCCESS) {
printf("Error creating the renderPass\n");
exit(-1);
}
// -- finally create the pipeline
VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = stagesInfos;
pipelineInfo.pVertexInputState = &vertInputInfo;
pipelineInfo.pInputAssemblyState = &assemblyInfo;
pipelineInfo.pViewportState = &viewportInfo;
pipelineInfo.pRasterizationState = &rasterizerInfo;
pipelineInfo.pMultisampleState = &multisampleInfo;
pipelineInfo.pDepthStencilState = nullptr;
pipelineInfo.pColorBlendState = &colorBlendInfo;
pipelineInfo.pDynamicState = &dynamicStateInfo;
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = vk.renderPass; // render pass describing the enviroment in which the pipeline will be used
// the pipeline must only be used with a render pass compatilble with this one
pipelineInfo.subpass = 0; // index of the subpass in the render pass where this pipeline will be used
//pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // you can derive from another pipeline
//pipelineInfo.basePipelineIndex = -1;
if(vkCreateGraphicsPipelines(vk.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &vk.pipeline) != VK_SUCCESS) {
printf("Error creating the graphics piepeline\n");
exit(-1);
}
}
int main()
{
printf("hello vulkan\n");
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // explicitly tell GLFW not to create an OpenGL context
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "hello vulkan", nullptr, nullptr);
initVulkan();
createTheGraphicsPipeline();
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
}
simple.vert.glsl:
#version 450
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
);
const vec3 colors[3] = vec3[](
vec3(1, 0, 0),
vec3(0, 1, 0),
vec3(0, 0, 1)
);
layout (location = 0)out vec3 v_color;
void main()
{
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
v_color = colors[gl_VertexIndex];
}
simple.frag.glsl
#version 450
layout(location = 0) in vec3 v_color;
layout(location = 0) out vec4 o_color;
void main() {
o_color = vec4(v_color, 1.0);
}
I finally found the problem: I was destroying the shader modules too early. Looks like you have to keep the shader modules alive ultil after you have created the pipeline.
This is the fixed code
#include <stdio.h>
#include <string.h>
#include <vector>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <vulkan/vulkan.h>
typedef const char* const ConstStr;
typedef uint8_t u8;
typedef uint32_t u32;
typedef uint64_t u64;
GLFWwindow* window;
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
struct VulkanData
{
VkInstance inst;
VkSurfaceKHR surface;
VkPhysicalDevice physicalDevice;
VkDevice device;
u32 graphicsQueueFamily, presentationQueueFamily;
VkQueue graphicsQueue;
VkQueue presentationQueue;
VkSwapchainKHR swapchain;
VkImageView swapchainImageViews[2];
VkRenderPass renderPass;
VkPipeline pipeline;
} vk;
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkanDebugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData) {
printf("%s\n", pCallbackData->pMessage);
return VK_FALSE;
}
void initVulkan()
{
{ // create vulkan instance
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pNext = nullptr;
appInfo.pApplicationName = "hello";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "hello_engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
static ConstStr layers[] = {
#if !defined(NDEBUG)
"VK_LAYER_KHRONOS_validation",
//"VK_LAYER_LUNARG_api_dump",
#endif
};
#if !defined(NDEBUG)
u32 numSupportedLayers;
vkEnumerateInstanceLayerProperties(&numSupportedLayers, nullptr);
std::vector<VkLayerProperties> supportedLayers(numSupportedLayers);
vkEnumerateInstanceLayerProperties(&numSupportedLayers, &supportedLayers[0]);
for(ConstStr layer : layers) {
bool supported = false;
for(const auto& supportedLayer : supportedLayers) {
if(strcmp(supportedLayer.layerName, layer) == 0) {
supported = true;
break;
}
}
if(!supported) {
printf("Layer %s is not supported\n", layer);
//assert(false);
}
}
#endif
VkInstanceCreateInfo instInfo = {};
instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instInfo.pApplicationInfo = &appInfo;
instInfo.enabledLayerCount = std::size(layers);
instInfo.ppEnabledLayerNames = layers;
u32 numGlfwExtensions;
ConstStr* glfwExtensions = glfwGetRequiredInstanceExtensions(&numGlfwExtensions);
std::vector<const char*> extensions;
extensions.reserve(numGlfwExtensions + 1);
for(u32 i = 0; i < numGlfwExtensions; i++)
extensions.push_back(glfwExtensions[i]);
#ifndef NDEBUG
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
instInfo.enabledExtensionCount = extensions.size();
instInfo.ppEnabledExtensionNames = extensions.data();
if (vkCreateInstance(&instInfo, nullptr, &vk.inst) != VK_SUCCESS) {
printf("Error creating vulkan instance\n");
exit(-1);
}
}
// create window surface
if(glfwCreateWindowSurface(vk.inst, window, nullptr, &vk.surface) != VK_SUCCESS) {
printf("Error: can't create window surface\n");
exit(-1);
}
{ // pick physical device
u32 numPhysicalDevices;
vkEnumeratePhysicalDevices(vk.inst, &numPhysicalDevices, nullptr);
std::vector<VkPhysicalDevice> physicalDevices(numPhysicalDevices);
if(numPhysicalDevices == 0) {
printf("Error: there are no devices supporting Vulkan\n");
exit(-1);
}
vkEnumeratePhysicalDevices(vk.inst, &numPhysicalDevices, &physicalDevices[0]);
auto compareProps = [](
const VkPhysicalDeviceProperties& propsA,
const VkPhysicalDeviceMemoryProperties& memPropsA,
const VkPhysicalDeviceProperties& propsB,
const VkPhysicalDeviceMemoryProperties& memPropsB) -> bool
{
auto calcDeviceTypeScore = [](VkPhysicalDeviceType a) -> u8 {
switch(a) {
case VK_PHYSICAL_DEVICE_TYPE_CPU: return 1;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 2;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 3;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 4;
default: return 0;
}
};
const u8 scoreA = calcDeviceTypeScore(propsA.deviceType);
const u8 scoreB = calcDeviceTypeScore(propsB.deviceType);
if(scoreA != scoreB)
return scoreA < scoreB;
auto calcMem = [](const VkPhysicalDeviceMemoryProperties& a) -> u64
{
u64 mem = 0;
for(u32 i = 0; i < a.memoryHeapCount; i++) {
if(a.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
mem = std::max(mem, a.memoryHeaps[i].size);
}
return mem;
};
u32 memA = calcMem(memPropsA);
u32 memB = calcMem(memPropsB);
return memA < memB;
};
VkPhysicalDeviceProperties bestProps;
vkGetPhysicalDeviceProperties(physicalDevices[0], &bestProps);
VkPhysicalDeviceMemoryProperties bestMemProps;
vkGetPhysicalDeviceMemoryProperties(physicalDevices[0], &bestMemProps);
u32 bestI = 0;
for(u32 i = 1; i < numPhysicalDevices; i++) {
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memProps;
vkGetPhysicalDeviceProperties(physicalDevices[i], &props);
vkGetPhysicalDeviceMemoryProperties(physicalDevices[i], &memProps);
if(compareProps(bestProps, bestMemProps, props, memProps)) {
bestProps = props;
bestMemProps = memProps;
bestI = i;
}
}
vk.physicalDevice = physicalDevices[bestI];
}
{ // create logical device
u32 numQueueFamilies;
vkGetPhysicalDeviceQueueFamilyProperties(vk.physicalDevice, &numQueueFamilies, nullptr);
std::vector<VkQueueFamilyProperties> queueFamilyProps(numQueueFamilies);
vkGetPhysicalDeviceQueueFamilyProperties(vk.physicalDevice, &numQueueFamilies, &queueFamilyProps[0]);
vk.graphicsQueueFamily = numQueueFamilies;
vk.presentationQueueFamily = numQueueFamilies;
for(u32 i = 0; i < numQueueFamilies; i++) {
if(queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
vk.graphicsQueueFamily = i;
VkBool32 supportPresentation;
vkGetPhysicalDeviceSurfaceSupportKHR(vk.physicalDevice, i, vk.surface, &supportPresentation);
if(supportPresentation)
vk.presentationQueueFamily = i;
}
if(vk.graphicsQueueFamily == numQueueFamilies) {
printf("Error: there is no queue that supports graphics\n");
exit(-1);
}
if(vk.presentationQueueFamily == numQueueFamilies) {
printf("Error: there is no queue that supports presentation\n");
exit(-1);
}
u32 queueFamilyInds[2] = {vk.graphicsQueueFamily};
u32 numQueues;
if(vk.graphicsQueueFamily == vk.presentationQueueFamily) {
numQueues = 1;
}
else {
numQueues = 2;
queueFamilyInds[1] = vk.graphicsQueueFamily;
}
const float queuePriorities[] = {1.f};
VkDeviceQueueCreateInfo queueCreateInfos[2] = {};
for(u32 i = 0; i < numQueues; i++)
{
queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfos[i].queueFamilyIndex = queueFamilyInds[i];
queueCreateInfos[i].queueCount = 1;
queueCreateInfos[i].pQueuePriorities = queuePriorities;
}
VkDeviceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
info.queueCreateInfoCount = numQueues;
info.pQueueCreateInfos = queueCreateInfos;
info.enabledLayerCount = 0;
info.ppEnabledLayerNames = nullptr;
ConstStr deviceExtensions[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
info.enabledExtensionCount = std::size(deviceExtensions);
info.ppEnabledExtensionNames = deviceExtensions;
const VkResult deviceCreatedOk = vkCreateDevice(vk.physicalDevice, &info, nullptr, &vk.device);
if(deviceCreatedOk != VK_SUCCESS) {
printf("Error: couldn't create device\n");
exit(-1);
}
vkGetDeviceQueue(vk.device, vk.graphicsQueueFamily, 0, &vk.graphicsQueue);
vkGetDeviceQueue(vk.device, vk.presentationQueueFamily, 0, &vk.presentationQueue);
// queues
// https://community.khronos.org/t/guidelines-for-selecting-queues-and-families/7222
// https://www.reddit.com/r/vulkan/comments/aara8f/best_way_for_selecting_queuefamilies/
// https://stackoverflow.com/questions/37575012/should-i-try-to-use-as-many-queues-as-possible
}
{ // crete swapchain
VkSurfaceCapabilitiesKHR surfaceCpabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk.physicalDevice, vk.surface, &surfaceCpabilities);
VkSwapchainCreateInfoKHR createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
createInfo.surface = vk.surface;
createInfo.minImageCount = 2;
createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; // TODO: I think this format has mandatory support but I'm not sure
createInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
createInfo.imageExtent = surfaceCpabilities.currentExtent;
createInfo.imageArrayLayers = 1;
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 1;
createInfo.pQueueFamilyIndices = &vk.presentationQueueFamily;
createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
createInfo.clipped = VK_FALSE;
//createInfo.oldSwapchain = ; // this can be used to recycle the old swapchain when resizing the window
vkCreateSwapchainKHR(vk.device, &createInfo, nullptr, &vk.swapchain);
}
{ // create image views of the swapchain
u32 imageCount;
VkImage images[2];
vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &imageCount, nullptr);
assert(imageCount == 2);
vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &imageCount, images);
for(u32 i = 0; i < 2; i++)
{
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = images[0];
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = VK_FORMAT_B8G8R8A8_SRGB;
// info.components = ; // channel swizzling VK_COMPONENT_SWIZZLE_IDENTITY is 0
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 1;
vkCreateImageView(vk.device, &info, nullptr, &vk.swapchainImageViews[i]);
}
}
}
#define SHADERS_PATH "shaders"
char* readBinFile(int& len, const char* fileName)
{
FILE* file = fopen(fileName, "rb");
if(!file)
return nullptr;
fseek(file, 0, SEEK_END);
len = ftell(file);
rewind(file);
char* txt = new char[len];
fread(txt, len, 1, file);
fclose(file);
return txt;
}
VkShaderModule createShaderModule(const char* fileName)
{
int len;
char* data = readBinFile(len, fileName);
if(!data) {
printf("Error loading shader spir-v\n");
exit(-1);
}
VkShaderModuleCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
info.codeSize = len;
info.pCode = (u32*)data;
VkShaderModule module;
const VkResult res = vkCreateShaderModule(vk.device, &info, nullptr, &module);
if(res != VK_SUCCESS) {
printf("Error: could not create vertex shader module\n");
exit(-1);
}
delete[] data;
return module;
}
VkPipelineShaderStageCreateInfo makeStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule module)
{
VkPipelineShaderStageCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
info.stage = stage;
info.module = module;
info.pName = "main";
info.pSpecializationInfo = nullptr; // allows to specify values for shader constants
return info;
}
void createTheGraphicsPipeline()
{
VkShaderModule vertShadModule = createShaderModule(SHADERS_PATH"/simple.vert.glsl.spv");
VkShaderModule fragShadModule = createShaderModule(SHADERS_PATH"/simple.frag.glsl.spv");
const VkPipelineShaderStageCreateInfo stagesInfos[] = {
makeStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertShadModule),
makeStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragShadModule)
};
VkPipelineVertexInputStateCreateInfo vertInputInfo = {};
vertInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertInputInfo.vertexBindingDescriptionCount = 0;
vertInputInfo.pVertexBindingDescriptions = nullptr;
vertInputInfo.vertexAttributeDescriptionCount = 0;
vertInputInfo.pVertexAttributeDescriptions = nullptr;
VkPipelineInputAssemblyStateCreateInfo assemblyInfo = {};
assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
assemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
assemblyInfo.primitiveRestartEnable = VK_FALSE;
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = WINDOW_WIDTH;
viewport.height = WINDOW_HEIGHT;
viewport.minDepth = 0;
viewport.maxDepth = 1;
VkRect2D scissor;
scissor.offset = {0, 0};
scissor.extent = {WINDOW_WIDTH, WINDOW_HEIGHT};
VkPipelineViewportStateCreateInfo viewportInfo = {};
viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportInfo.viewportCount = 1;
viewportInfo.pViewports = &viewport;
viewportInfo.scissorCount = 1;
viewportInfo.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizerInfo = {};
rasterizerInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizerInfo.depthClampEnable = VK_FALSE; // enabling will clamp depth instead of discarding which can be useful when rendering shadowmaps
rasterizerInfo.rasterizerDiscardEnable = VK_FALSE; // if enable discards all geometry (could be useful for transformfeedback)
rasterizerInfo.polygonMode = VK_POLYGON_MODE_FILL;
rasterizerInfo.lineWidth = 1.f;
rasterizerInfo.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizerInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizerInfo.depthBiasEnable = VK_FALSE; // useful for shadow mapping
VkPipelineMultisampleStateCreateInfo multisampleInfo = {}; // multisampling: it works by combining the fragment shader results of multiple polygons that rasterize to the same pixel
multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleInfo.sampleShadingEnable = VK_FALSE;
multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
//VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {};
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_G_BIT;
colorBlendAttachment.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendInfo = {};
colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
//colorBlendInfo.logicOpEnable = VK_FALSE;
//colorBlendInfo.logicOp = VK_LOGIC_OP_COPY;
colorBlendInfo.attachmentCount = 1;
colorBlendInfo.pAttachments = &colorBlendAttachment;
//const VkDynamicState dynamicStates[] = {
// VK_DYNAMIC_STATE_VIEWPORT,
// VK_DYNAMIC_STATE_SCISSOR
//};
//VkPipelineDynamicStateCreateInfo dynamicStateInfo = {};
//dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
//dynamicStateInfo.dynamicStateCount = 2;
//dynamicStateInfo.pDynamicStates = dynamicStates;
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
VkPipelineLayout pipelineLayout;
vkCreatePipelineLayout(vk.device, &pipelineLayoutInfo, nullptr, &pipelineLayout);
// -- create the renderPass ---
VkAttachmentDescription attachmentDesc = {};
attachmentDesc.format = VK_FORMAT_B8G8R8A8_SRGB;
attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attachmentDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; // clear before rendering
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; // store the result after rendering
attachmentDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // we don't care. This doesn't guarantee that the contents of th eimage will be preserved, but that's not a problem since we are going to clear it anyways
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef = {};
colorAttachmentRef.attachment = 0; // the index in the attachemntDescs array (we only have one)
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // this is an output attachment so we use this enum for best performance
VkSubpassDescription subpassDesc = {};
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.colorAttachmentCount = 1;
subpassDesc.pColorAttachments = &colorAttachmentRef; // the index of the attachement in this array is referenced in the shader with "layout(location = 0) out vec4 o_color"
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &attachmentDesc;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpassDesc;
if(vkCreateRenderPass(vk.device, &renderPassInfo, nullptr, &vk.renderPass) != VK_SUCCESS) {
printf("Error creating the renderPass\n");
exit(-1);
}
// -- finally create the pipeline
VkGraphicsPipelineCreateInfo pipelineInfo = {};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = stagesInfos;
pipelineInfo.pVertexInputState = &vertInputInfo;
pipelineInfo.pInputAssemblyState = &assemblyInfo;
pipelineInfo.pViewportState = &viewportInfo;
pipelineInfo.pRasterizationState = &rasterizerInfo;
pipelineInfo.pMultisampleState = &multisampleInfo;
pipelineInfo.pDepthStencilState = nullptr;
pipelineInfo.pColorBlendState = &colorBlendInfo;
//pipelineInfo.pDynamicState = &dynamicStateInfo;
pipelineInfo.layout = pipelineLayout;
pipelineInfo.renderPass = vk.renderPass; // render pass describing the enviroment in which the pipeline will be used
// the pipeline must only be used with a render pass compatilble with this one
pipelineInfo.subpass = 0; // index of the subpass in the render pass where this pipeline will be used
//pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // you can derive from another pipeline
//pipelineInfo.basePipelineIndex = -1;
getchar();
if(vkCreateGraphicsPipelines(vk.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &vk.pipeline) != VK_SUCCESS) {
printf("Error creating the graphics piepeline\n");
exit(-1);
}
vkDestroyShaderModule(vk.device, fragShadModule, nullptr);
vkDestroyShaderModule(vk.device, vertShadModule, nullptr);
}
int main()
{
printf("hello vulkan\n");
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // explicitly tell GLFW not to create an OpenGL context
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "hello vulkan", nullptr, nullptr);
initVulkan();
createTheGraphicsPipeline();
while(!glfwWindowShouldClose(window))
{
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
}
This question already has answers here:
When and why will a compiler initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?
(9 answers)
What are the debug memory fill patterns in Visual Studio C++ and Windows?
(3 answers)
Closed 1 year ago.
Header
#include <iostream>
#define GLFW_INCLUDE_VULKAN
#include "GLFW\glfw3.h"
#include "PhysicalDeviceVK.h"
#define CATCH(value) if(value != VK_SUCCESS){ __debugbreak;}
class DeviceVK
{
private:
/**
* #return VkPhysicalDevice Get the best physical device.
*/
VkPhysicalDevice getPhysicalDevice(VkInstance instance);
/**
* #return uint32_t Get the index of the best queue family.
*/
uint32_t getQueueFamily(std::vector<VkQueueFamilyProperties> queueFamilies);
/**
* #return VkDeviceCreateInfo create the device create info.
*/
VkDeviceCreateInfo createDeviceCreateInfo();
public:
VkDevice device = nullptr;
VkQueue queue = nullptr;
PhysicalDeviceVK physicalDevice;
uint32_t queueIndex = NULL;
DeviceVK(VkInstance instance, VkSurfaceKHR surface);
DeviceVK() {}
};
C++ File
#include "DeviceVK.h"
DeviceVK::DeviceVK(VkInstance instance, VkSurfaceKHR surface)
{
VkPhysicalDevice bestGPU = getPhysicalDevice(instance);
this->physicalDevice = PhysicalDeviceVK(bestGPU);
VkDeviceCreateInfo deviceCreateInfo = createDeviceCreateInfo();
CATCH(vkCreateDevice(bestGPU, &deviceCreateInfo, nullptr, &this->device));
vkGetDeviceQueue(this->device, this->queueIndex, 1, &this->queue);
this->physicalDevice.debug(surface);
}
VkPhysicalDevice DeviceVK::getPhysicalDevice(VkInstance instance)
{
uint32_t amountOfGraphicCards = 0;
vkEnumeratePhysicalDevices(instance, &amountOfGraphicCards, nullptr);
VkPhysicalDevice* physicalDevices = new VkPhysicalDevice[amountOfGraphicCards];
CATCH(vkEnumeratePhysicalDevices(instance, &amountOfGraphicCards, physicalDevices));
int bestGPU = 0, maxHeap = 0;
for (int i = 0; i < amountOfGraphicCards; i++)
{
PhysicalDeviceVK physicalDevice(physicalDevices[i]);
VkPhysicalDeviceMemoryProperties memoryProperties = physicalDevice.getPhysicalDeviceMemoryProperties();
auto heapsPointer = memoryProperties.memoryHeaps;
auto heaps = std::vector<VkMemoryHeap>(heapsPointer, heapsPointer + memoryProperties.memoryHeapCount);
for (const auto& heap : heaps)
{
if (heap.flags & VkMemoryHeapFlagBits::VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
{
if (maxHeap < heap.size)
{
maxHeap = heap.size;
bestGPU = i;
}
}
}
}
VkPhysicalDevice bestDevice = physicalDevices[bestGPU];
return bestDevice;
}
uint32_t DeviceVK::getQueueFamily(std::vector<VkQueueFamilyProperties> queueFamilies)
{
return ((uint32_t)0);
}
VkDeviceCreateInfo DeviceVK::createDeviceCreateInfo()
{
std::vector<VkQueueFamilyProperties> queueFamilies = this->physicalDevice.getQueueFamilyProperties();
this->queueIndex = getQueueFamily(queueFamilies);
VkDeviceQueueCreateInfo deviceQueueCreateInfo;
deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
deviceQueueCreateInfo.pNext = nullptr;
deviceQueueCreateInfo.flags = 0;
deviceQueueCreateInfo.queueFamilyIndex = this->queueIndex;
deviceQueueCreateInfo.queueCount = queueFamilies.size();
const float queuePriorityValue = 1.0f;
deviceQueueCreateInfo.pQueuePriorities = &queuePriorityValue;
queueFamilies.clear();
VkPhysicalDeviceFeatures deviceFeatures = {};
const std::vector<const char*> deviceExtensions =
{
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
VkDeviceCreateInfo deviceCreateInfo;
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
deviceCreateInfo.pNext = nullptr;
deviceCreateInfo.flags = 0;
deviceCreateInfo.queueCreateInfoCount = 1;
deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
deviceCreateInfo.enabledLayerCount = 0;
deviceCreateInfo.ppEnabledLayerNames = nullptr;
deviceCreateInfo.enabledExtensionCount = deviceExtensions.size();
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
return deviceCreateInfo;
}
Here I call the class
void VulkanGraphic::createDevice()
{
this->deviceVK = DeviceVK(this->instance, this->surface);
}
Every time in run this program, it crashes because of a
0xC0000005: Access violation when reading at position 0xDDDDDDDD.
I also tried deleting the last two lines, where the error appears. But it actually says, that the program crashes at the End of the constructor, where a empty line is.
I'm using Vulkan and GLFW
The error happens
Also when I'm removing the lines...
I'm starting a game engine with Vulkan and SDL2. My program is crashing in a very specific part of my code. I'm really new in the Vulkan API and i have tried several modifications with no success. If someone could help me, here I give the full code and the part that I think it is crashing.
// GE_Base.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <vulkan/vulkan.h>
#include <SDL.h>
#include <glm.hpp>
#include <SDL_vulkan.h>
#include "GE_code_class.h"
#define WIDTH 1280
#define HEIGHT 720
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
SDL_Quit();
return -1;
}
SDL_Window * window = SDL_CreateWindow("GE_Base", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT, SDL_WINDOW_VULKAN);
////////////////////////////////
//VULKAN SETUP
const char* instanceExtensionNames[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
};
VkApplicationInfo ai = {};
ai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
ai.pNext = nullptr;
ai.pApplicationName = "SDL Vulkan";
ai.applicationVersion = 1;
ai.pEngineName = "SDLV";
ai.engineVersion = 1;
ai.apiVersion = VK_MAKE_VERSION(1, 0, 3);
VkInstanceCreateInfo ici = {};
ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
ici.pNext = nullptr;
ici.flags = 0;
ici.pApplicationInfo = &ai;
ici.enabledLayerCount = 0;
ici.ppEnabledLayerNames = nullptr;
ici.enabledExtensionCount = 0;
ici.ppEnabledExtensionNames = nullptr;
VkInstance instance;
vkCreateInstance(&ici, nullptr, &instance);
//CHECK PHYSICAL DEVICE (GRAFIC CARD)
VK_DEFINE_HANDLE(VkPhysicalDevice);
uint32_t deviceCount = 1;
VkPhysicalDevice gpu;
//VkPhysicalDevice *physical_devices = (VkPhysicalDevice*)malloc(sizeof(deviceCount));
VkPhysicalDevice *physical_devices = (VkPhysicalDevice*)malloc(sizeof(deviceCount));
vkEnumeratePhysicalDevices(instance, &deviceCount, physical_devices);
gpu = physical_devices[0];
//CHECK QUEUE FAMILIES
uint32_t graphics_queue_node_index;
/*if (queue_props->queueCount <= 0) queue_props->queueCount = 1;*/
uint32_t amountOfFamilies = 0;
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &amountOfFamilies, NULL);
VkQueueFamilyProperties *queue_props = new VkQueueFamilyProperties[amountOfFamilies];
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &amountOfFamilies, queue_props);
assert(queue_props->queueCount >= 1);
VkPhysicalDeviceFeatures features;
vkGetPhysicalDeviceFeatures(gpu, &features);
uint32_t graphicsQueueNodeIndex = UINT32_MAX;
unsigned int i;
for (i = 0; i < queue_props->queueCount; i++) {
if ((queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
if (graphicsQueueNodeIndex == UINT32_MAX)
graphicsQueueNodeIndex = i;
}
}
graphics_queue_node_index = graphicsQueueNodeIndex;
//LOGICAL DEVICE
VkDevice device;
float queue_priorities[1] = { 0.0 };
VkDeviceQueueCreateInfo q;
q.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
q.pNext = nullptr,
q.queueFamilyIndex = graphics_queue_node_index,
q.queueCount = 1,
q.pQueuePriorities = queue_priorities;
graphicsQueueNodeIndex = 2000;
graphics_queue_node_index = graphicsQueueNodeIndex;
//CREATE & INSTANTIATE DEVICE
VkDeviceCreateInfo d;
d.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
d.pNext = nullptr,
d.queueCreateInfoCount = 1,
d.pQueueCreateInfos = &q,
d.enabledLayerCount = 1,
d.ppEnabledLayerNames = nullptr,
d.enabledExtensionCount = 1,
d.ppEnabledExtensionNames = (const char *const *) instanceExtensionNames,
d.pEnabledFeatures = nullptr;
vkCreateDevice(gpu, &d, nullptr, &device);
//SURFACE WINDOW
VkSurfaceKHR surface;
SDL_Vulkan_CreateSurface(window, (SDL_vulkanInstance)&ici, (SDL_vulkanSurface*)&surface);
//PRESENTATION QUEU
VkBool32 *supportsPresent = new VkBool32[queue_props->queueCount];
vkGetPhysicalDeviceSurfaceSupportKHR(gpu, queue_props->queueCount, surface, &supportsPresent[i]);
graphics_queue_node_index = graphicsQueueNodeIndex;
//QUEUE
VK_DEFINE_HANDLE(VkQueue)
VkQueue queu_;
vkGetDeviceQueue(device, graphics_queue_node_index, queue_props->queueCount, &queu_);
////////////////////////////////
GE_class *engine;
engine = new GE_class();
engine->Init(1280, 720);
bool quit_app = false;
while (!quit_app) {
SDL_Event eve;
while (SDL_PollEvent(&eve)) {
switch (eve.type) {
case SDL_WINDOWEVENT:
if (eve.window.event == SDL_WINDOWEVENT_RESIZED) {
}
break;
case SDL_QUIT:
quit_app = true;
break;
}
}
//double currentTime = (double)SDL_GetTicks() / 1000.0;
//GLrender(currentTime);
//double currentTime = (double) SDL_GetTicks() / 1000.0;
//myRenderCode(currentTime);
//SDL_GL_SwapWindow(window);
/*vkQueuePresentKHR()*/
}
//SDL_DestroyWindow(window);
//SDL_Quit();
return 0;
}
VkQueue queu_;
vkGetDeviceQueue(device, graphics_queue_node_index, queue_props-queueCount, &queu_);
These are the lines that I think it's crashing. I guess in the previous lines I did
something wrong or I'm not initializing some variable. I'm not really sure.
The value of graphics_queue_node_index is 2000 when you call vkGetDeviceQueue. That's most likely not a valid queue index.
VkDeviceQueueCreateInfo q;
// ...
q.queueFamilyIndex = graphics_queue_node_index,
// ...
graphicsQueueNodeIndex = 2000;
graphics_queue_node_index = graphicsQueueNodeIndex;
// ...
vkGetPhysicalDeviceSurfaceSupportKHR(gpu, queue_props->queueCount, surface, &supportsPresent[i]);
graphics_queue_node_index = graphicsQueueNodeIndex; // redundant?
// ...
vkGetDeviceQueue(device, graphics_queue_node_index, queue_props->queueCount, &queu_);
I'm trying to clear the the screen with a color, but I'm always getting an error
"Cannot submit cmd buffer using image (...) with layout VK_IMAGE_LAYOUT_UNDEFINED when first use is VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL.
And Actully i tried to modify some undefine values to depth_stenci_attachment optimal, but The only thing is I get is more of these errors. So is there a field,that is incorrectly filled, or I forget to fill?
So here is my full main.cpp Because I have no idea where the error could be.
#include<stdio.h>
#include<string.h>
#include<vector>
#define DEBUG
#ifdef _WIN32
#define VK_USE_PLATFORM_WIN32_KHR
#endif
#define KNOCH_JULIA 42
#include"window.h"
using namespace std;
#ifdef DEBUG
#include<iostream>
using namespace std;
VkDebugReportCallbackEXT report;
void init_debug(vulkan *vulk);
PFN_vkCreateDebugReportCallbackEXT fvkCreateDebugReportCallbackEXT = VK_NULL_HANDLE;
PFN_vkDestroyDebugReportCallbackEXT fvkDestroyDebugReportCallbackEXT = VK_NULL_HANDLE;
VKAPI_ATTR VkBool32 VKAPI_CALL callback(VkDebugReportFlagsEXT flag, VkDebugReportObjectTypeEXT obj_t, uint64_t src_obj, size_t loc, int32_t msg_code, const char* layer_pref, const char* msg, void* user_data) {
switch (flag) {
case VK_DEBUG_REPORT_ERROR_BIT_EXT:
cout<<"error!"<<" "<< flag<<" source:"<<src_obj<<"location: "<<loc<<": "<< msg<<endl;
break;
case VK_DEBUG_REPORT_WARNING_BIT_EXT:
cout << "warning!" << obj_t << ": " << msg << endl;
break;
}
return false;
}
void init_debug(vulkan *vulk) {
fvkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(vulk->inst, "vkCreateDebugReportCallbackEXT");
fvkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(vulk->inst, "vkDestroyDebugReportCallbackEXT");
if (nullptr == fvkCreateDebugReportCallbackEXT || nullptr == fvkDestroyDebugReportCallbackEXT) {
exit(-5);
}
VkDebugReportCallbackCreateInfoEXT info = {};
info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
info.pfnCallback = callback;
info.pNext = nullptr;
info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT;
fvkCreateDebugReportCallbackEXT(vulk->inst, &info, nullptr, &report);
}
#endif
FILE *fileptr;
void initInstance(vulkan *vulk){
vector<char*> ext;
ext.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
ext.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.apiVersion = VK_MAKE_VERSION(1, 0, 39);
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 1);
app_info.pApplicationName = "szar";
app_info.pEngineName = "yayitstarts";
app_info.pNext = nullptr;
VkInstanceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
#ifdef DEBUG
vector<char*>layers;
layers.push_back("VK_LAYER_LUNARG_object_tracker");
layers.push_back("VK_LAYER_LUNARG_core_validation");
layers.push_back("VK_LAYER_LUNARG_parameter_validation");
//layers.push_back("VK_LAYER_LUNARG_vktrace");
layers.push_back("VK_LAYER_LUNARG_swapchain");
layers.push_back("VK_LAYER_LUNARG_image");
ext.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
#endif
#ifdef DEBUG
info.enabledLayerCount = layers.size();
info.ppEnabledLayerNames = layers.data();
#else
info.enabledLayerCount = 0;
info.ppEnabledLayerNames = nullptr;
#endif
info.pApplicationInfo = &app_info;
info.enabledExtensionCount = ext.size();
info.ppEnabledExtensionNames = ext.data();
info.flags = 0;
info.pNext = nullptr;
vkCreateInstance(&info, nullptr, &(vulk->inst));
}
void getGPU(vulkan *vulk) {
uint32_t dev_c=0;
vkEnumeratePhysicalDevices(vulk->inst,&dev_c,nullptr);
VkPhysicalDevice *gpus=(VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice)*dev_c);
vkEnumeratePhysicalDevices(vulk->inst, &dev_c, gpus);
vulk->gpu = gpus[0];
}
void createDevice(vulkan *vulk) {
VkPhysicalDeviceFeatures features;
vkGetPhysicalDeviceFeatures(vulk->gpu, &features);
float prior[] = { 1.0f };
uint32_t prop_c;
vkGetPhysicalDeviceQueueFamilyProperties(vulk->gpu, &prop_c, nullptr);
VkQueueFamilyProperties *props = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties)*prop_c);
vkGetPhysicalDeviceQueueFamilyProperties(vulk->gpu, &prop_c, props);
uint32_t index = -1;
for (int i = 0; i < prop_c; i++) {
VkBool32 supported;
vkGetPhysicalDeviceSurfaceSupportKHR(vulk->gpu, i, vulk->surface_struct.surface, &supported);
if (props[i].queueFlags&VK_QUEUE_GRAPHICS_BIT&&supported) {
index = i;
}
}
if (index == -1) {
printf("no graphic queue family found");
exit(-1);
}
#ifdef DEBUG
uint32_t count;
vkEnumerateInstanceLayerProperties(&count, nullptr);
vector<VkLayerProperties>layers_access(count);
vkEnumerateInstanceLayerProperties(&count, layers_access.data());
for (int i = 0; i < count; i++) {
printf("%s\n", layers_access[i].layerName);
}
uint32_t dev_count;
vkEnumerateDeviceLayerProperties(vulk->gpu, &dev_count, nullptr);
vector<VkLayerProperties>layers_access_dev(count);
vkEnumerateDeviceLayerProperties(vulk->gpu, &dev_count, layers_access.data());
for (int i = 0; i < dev_count; i++) {
printf("dev: %s\n", layers_access_dev[i].layerName);
}
#endif
vulk->queue_fam_ind = index;
int queue_count=1;
vector<char*> ext;
ext.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
#ifdef DEBUG
vector<char*> layers;
layers.push_back("VK_LAYER_LUNARG_object_tracker");
layers.push_back("VK_LAYER_LUNARG_core_validation");
#endif
VkDeviceQueueCreateInfo queue_info = {};
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info.pQueuePriorities = prior;
queue_info.queueCount = queue_count;
queue_info.queueFamilyIndex = index;
queue_info.flags = 0;
queue_info.pNext = nullptr;
VkDeviceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
#ifdef DEBUG
info.enabledLayerCount = layers.size();
info.ppEnabledLayerNames = layers.data();
#else
info.enabledLayerCount = 0;
info.ppEnabledLayerNames = nullptr;
#endif
info.pEnabledFeatures = &features;
info.enabledExtensionCount = ext.size();
info.ppEnabledExtensionNames = ext.data();
info.pQueueCreateInfos = &queue_info;
info.queueCreateInfoCount = 1;
info.pNext = nullptr;
if (VK_SUCCESS != vkCreateDevice(vulk->gpu, &info, nullptr, &(vulk->device))) {
exit(-1);
}
vulk->queue = (VkQueue*)malloc(sizeof(VkQueue)*queue_count);
vkGetDeviceQueue(vulk->device, index, 0, &(vulk->queue[0]));
}
void createSwapchain(vulkan *vulk) {
VkSurfaceCapabilitiesKHR capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulk->gpu, vulk->surface_struct.surface,&capabilities);
uint32_t format_c;
vkGetPhysicalDeviceSurfaceFormatsKHR(vulk->gpu, vulk->surface_struct.surface, &format_c, nullptr);
VkSurfaceFormatKHR *formats = (VkSurfaceFormatKHR*)malloc(sizeof(VkSurfaceFormatKHR)*format_c);
vkGetPhysicalDeviceSurfaceFormatsKHR(vulk->gpu, vulk->surface_struct.surface, &format_c, formats);
uint32_t pres_mode_c;
vkGetPhysicalDeviceSurfacePresentModesKHR(vulk->gpu, vulk->surface_struct.surface, &pres_mode_c, nullptr);
VkPresentModeKHR *pres_modes = (VkPresentModeKHR*)malloc(sizeof(VkPresentModeKHR)*pres_mode_c);
vkGetPhysicalDeviceSurfacePresentModesKHR(vulk->gpu, vulk->surface_struct.surface, &pres_mode_c, pres_modes);
int pres_mode_i = 0;
for (int i = 0; i < pres_mode_c; i++) {
if (pres_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
pres_mode_i = i;
}
}
vulk->surface_struct.extent = capabilities.currentExtent;
vulk->image.color_format= formats[0].format;
VkSwapchainCreateInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
info.clipped = VK_TRUE;
info.compositeAlpha = (VkCompositeAlphaFlagBitsKHR)capabilities.supportedCompositeAlpha;
info.flags = 0;
info.imageArrayLayers=1;
info.imageColorSpace = formats[0].colorSpace;
info.imageExtent = capabilities.currentExtent;
info.imageFormat = formats[0].format;
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
info.minImageCount = capabilities.minImageCount;
info.oldSwapchain =VK_NULL_HANDLE;
info.pNext = nullptr;
info.pQueueFamilyIndices =&(vulk->queue_fam_ind);
info.presentMode = pres_modes[pres_mode_i];
info.preTransform = capabilities.currentTransform;
info.queueFamilyIndexCount = 1;
info.surface = vulk->surface_struct.surface;
VkResult not_VK_SUCCESS = vkCreateSwapchainKHR(vulk->device, &info, nullptr, &(vulk->swapchain_struct.swapchain));
if (not_VK_SUCCESS != VK_SUCCESS) {
exit(-1);
}
vulk->swapchain_struct.format = formats[0].format;
}
void createImages(vulkan *vulk,Memory *depth_img_memory) {
uint32_t img_c;
vkGetSwapchainImagesKHR(vulk->device, vulk->swapchain_struct.swapchain, &img_c, nullptr);
vulk->image.color_images = (VkImage*)malloc(sizeof(VkImage)*img_c);
vkGetSwapchainImagesKHR(vulk->device, vulk->swapchain_struct.swapchain, &img_c, vulk->image.color_images);
vulk->image_c = img_c;
vulk->image.depth_images = (VkImage*)malloc(sizeof(VkImage));
vulk->image.color_image_views=(VkImageView*)malloc(sizeof(VkImageView)*img_c);
vulk->image.depth_image_views=(VkImageView*)malloc(sizeof(VkImageView));
VkComponentMapping mapping = {};
mapping.r = VK_COMPONENT_SWIZZLE_R;
mapping.g = VK_COMPONENT_SWIZZLE_G;
mapping.b = VK_COMPONENT_SWIZZLE_B;
mapping.a = VK_COMPONENT_SWIZZLE_A;
vulk->image.color_range = (VkImageSubresourceRange*)malloc(sizeof(VkImageSubresourceRange)*img_c);
VkImageSubresourceRange range = {};
range.aspectMask =VK_IMAGE_ASPECT_COLOR_BIT;
range.baseArrayLayer = 0;
range.baseMipLevel = 0;
range.layerCount = 1;
range.levelCount = 1;
for (int i = 0; i < img_c; i++) {
VkImageViewCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.components = mapping;
info.flags = 0;
info.format = vulk->swapchain_struct.format;
info.image = (vulk->image.color_images)[i];
info.pNext = nullptr;
info.subresourceRange = range;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
vulk->image.color_range[i] = range;
vkCreateImageView(vulk->device, &info, nullptr, &(vulk->image.color_image_views)[i]);
}
vulk->image.depth_range = (VkImageSubresourceRange*)malloc(sizeof(VkImageSubresourceRange));
vulk->image.depth_range[0] = range;
vector<VkFormat> depth_formats{
VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_D32_SFLOAT,
VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_D16_UNORM_S8_UINT,
VK_FORMAT_D16_UNORM
};
VkFormat depth_format;
for (int i = 0; i < depth_formats.size(); i++) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(vulk->gpu, depth_formats[i], &props);
if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
depth_format = depth_formats[i];
break;
}
}
vulk->image.depth_format = depth_format;
VkImageCreateInfo img_info = {};
img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
img_info.arrayLayers = 1;
img_info.extent.width = vulk->surface_struct.extent.width;
img_info.extent.height = vulk->surface_struct.extent.height;
img_info.extent.depth = 1;
img_info.flags = 0;
img_info.format = depth_format;
img_info.imageType = VK_IMAGE_TYPE_2D;
img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
img_info.mipLevels = 1;
img_info.pNext = nullptr;
img_info.pQueueFamilyIndices = &(vulk->queue_fam_ind);
img_info.queueFamilyIndexCount = 1;
img_info.samples = VK_SAMPLE_COUNT_1_BIT;
img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
img_info.tiling = VK_IMAGE_TILING_OPTIMAL;
img_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if (VK_SUCCESS!=vkCreateImage(vulk->device, &img_info, nullptr, &(vulk->image.depth_images)[0])) {
printf("It not works");
}
VkMemoryRequirements req;
vkGetImageMemoryRequirements(vulk->device, (vulk->image.depth_images)[0], &req);
vkGetPhysicalDeviceMemoryProperties(vulk->gpu, &(depth_img_memory->props));
uint32_t mem_index=-2;
for (int i = 0; i < depth_img_memory->props.memoryTypeCount; i++) {
if (req.memoryTypeBits & (1 << i)) {
if ((depth_img_memory->props.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
mem_index = i;
break;
}
}
}
if (mem_index == -2) {
printf("no supported memorytype");
exit(-2);
}
VkMemoryAllocateInfo mem_info = {};
mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
mem_info.pNext = nullptr;
mem_info.allocationSize = req.size;
mem_info.memoryTypeIndex = mem_index;
vkAllocateMemory(vulk->device, &mem_info, nullptr, &(depth_img_memory->dev_mem));
vkBindImageMemory(vulk->device, (vulk->image.depth_images)[0], depth_img_memory->dev_mem, 0);
VkComponentMapping mapping_d = {
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
};
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
VkImageViewCreateInfo img_view_info_d = {};
img_view_info_d.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
img_view_info_d.components = mapping_d;
img_view_info_d.flags = 0;
img_view_info_d.format = depth_format;
img_view_info_d.image = (vulk->image.depth_images)[0];
img_view_info_d.pNext = nullptr;
img_view_info_d.subresourceRange = range;
img_view_info_d.viewType = VK_IMAGE_VIEW_TYPE_2D;
if (VK_SUCCESS != vkCreateImageView(vulk->device, &img_view_info_d, nullptr, &(vulk->image.depth_image_views)[0])) {
printf("huge pile of shit!!!");
exit(-1);
}
}
void createCommandPool(vulkan vulk,cmd_pool *pool, uint32_t cmd_buff_c) {
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT|VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
info.pNext = nullptr;
info.queueFamilyIndex = vulk.queue_fam_ind;
vkCreateCommandPool(vulk.device, &info, nullptr, &(pool->pool));
pool->cmd_buff_c = cmd_buff_c;
pool->cmd_buffs = (VkCommandBuffer*)malloc(sizeof(VkCommandBuffer) * cmd_buff_c);
VkCommandBufferAllocateInfo cmd_info = {};
cmd_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmd_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmd_info.commandPool = pool->pool;
cmd_info.commandBufferCount = cmd_buff_c ;
cmd_info.pNext = nullptr;
vkAllocateCommandBuffers(vulk.device, &cmd_info, pool->cmd_buffs);
}
VkClearValue *clear;
void createFramebuffer(vulkan *vulk,VkExtent2D extent) {
vulk->fbo = (VkFramebuffer*)malloc(sizeof(VkFramebuffer)*vulk->image_c);
for (int i = 0; i < vulk->image_c; i++) {
VkImageView *img_views = (VkImageView*)malloc(sizeof(VkImageView) * 2);
img_views[0] = vulk->image.color_image_views[i];
img_views[1] = vulk->image.depth_image_views[0];
VkFramebufferCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.attachmentCount = 2;
info.pAttachments = img_views;
info.width = extent.height;
info.height = extent.width;
info.layers = 1;
info.renderPass = vulk->render_pass;
info.flags = 0;
info.pNext = nullptr;
if (VK_SUCCESS != vkCreateFramebuffer(vulk->device, &info, nullptr, &(vulk->fbo[i]))) {
printf("could not create framebuffer");
}
}
}
VkSemaphore *semaphores;
void createSemaphore(vulkan *vulk ,VkSemaphore *semaphore) {
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
vkCreateSemaphore(vulk->device, &info, nullptr, semaphore);
}
void createRenderPass(vulkan *vulk) {
VkAttachmentDescription *descr = (VkAttachmentDescription*)malloc(sizeof(VkAttachmentDescription) * 2);
VkAttachmentDescription color_descr = {};
color_descr.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
color_descr.format = vulk->image.color_format;
color_descr.samples = VK_SAMPLE_COUNT_1_BIT;
color_descr.initialLayout= VK_IMAGE_LAYOUT_UNDEFINED;
color_descr.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color_descr.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_descr.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_descr.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color_descr.flags = 0;
VkAttachmentDescription depth_descr = {};
depth_descr.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_descr.format = vulk->image.depth_format;
depth_descr.samples = VK_SAMPLE_COUNT_1_BIT;
depth_descr.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depth_descr.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depth_descr.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depth_descr.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depth_descr.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depth_descr.flags = 0;
*descr = color_descr;
*(descr + 1) = depth_descr;
VkAttachmentReference color_ref = {};
color_ref.attachment = 0;
color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depth_ref = {};
depth_ref.attachment = 1;
depth_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subp_descr = {};
subp_descr.colorAttachmentCount = 1;
subp_descr.pColorAttachments=&color_ref;
subp_descr.pDepthStencilAttachment = &depth_ref;
subp_descr.inputAttachmentCount = 0;
subp_descr.pInputAttachments = nullptr;
subp_descr.preserveAttachmentCount = 0;
subp_descr.pPreserveAttachments = nullptr;
subp_descr.pResolveAttachments = nullptr;
subp_descr.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subp_descr.flags = 0;
VkRenderPassCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount = 2;
info.pAttachments = descr;
info.dependencyCount = 0;
info.pDependencies = VK_NULL_HANDLE;
info.subpassCount = 1;
info.pSubpasses = &subp_descr;
info.flags = 0;
info.pNext = nullptr;
if (VK_SUCCESS != vkCreateRenderPass(vulk->device, &info, nullptr, &(vulk->render_pass))) {
printf("Could not create render pass.");
}
}
VkFence fence;
void createFences(vulkan *vulk) {
VkFenceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
vkCreateFence(vulk->device, &info, nullptr, &fence);
}
int main(int argc,char** argv) {
vulkan vulk;
Memory depth_memory;
cmd_pool pool;
initInstance(&vulk);
getGPU(&vulk);
Window window = Window();
window.open(&vulk);
createDevice(&vulk);
VkViewport viewport = {};
viewport.width = window.extent.width;
viewport.height = window.extent.height;
viewport.x = 0;
viewport.y = 0;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
init_debug(&vulk);
createSwapchain(&vulk);
createImages(&vulk, &depth_memory);
createRenderPass(&vulk);
createFramebuffer(&vulk,window.extent);
semaphores= (VkSemaphore*) malloc(sizeof(VkSemaphore)*2);
createSemaphore(&vulk, &semaphores[0]);
createSemaphore(&vulk, &semaphores[1]);
createFences(&vulk);
createCommandPool(vulk,&pool,2);
uint32_t img_pres;
VkResult result;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.pImageIndices = &img_pres;
info.pResults = &result;
info.swapchainCount = 1;
info.pSwapchains = &vulk.swapchain_struct.swapchain;
info.waitSemaphoreCount =0;
info.pWaitSemaphores = nullptr;
info.pNext = nullptr;
VkCommandBufferBeginInfo beg = {};
beg.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beg.pInheritanceInfo = nullptr;
beg.pNext = nullptr;
beg.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
VkClearValue val[2];
val[1] = { 0.0f,1.0f,1.0f,1.0f };
val[0] = { 0.0f,0 };
VkRenderPassBeginInfo render = {};
render.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render.clearValueCount = 2;
render.framebuffer = vulk.fbo[0];
render.pClearValues = val;
render.pNext = nullptr;
render.renderArea.offset = { 0,0 };
render.renderArea.extent = { window.extent.height, window.extent.width };
render.renderPass = vulk.render_pass;
vkBeginCommandBuffer(pool.cmd_buffs[0], &beg);
vkCmdBeginRenderPass(pool.cmd_buffs[0], &render, VK_SUBPASS_CONTENTS_INLINE);
vkCmdEndRenderPass(pool.cmd_buffs[0]);
vkEndCommandBuffer(pool.cmd_buffs[0]);
VkRenderPassBeginInfo render_2 = {};
render_2.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_2.clearValueCount = 2;
render_2.framebuffer = vulk.fbo[1];
render_2.pClearValues = val;
render_2.pNext = nullptr;
render_2.renderArea = { 0,0,window.extent.height,window.extent.width };
render_2.renderPass = vulk.render_pass;
vkBeginCommandBuffer(pool.cmd_buffs[1], &beg);
vkCmdBeginRenderPass(pool.cmd_buffs[1], &render_2, VK_SUBPASS_CONTENTS_INLINE);
vkCmdEndRenderPass(pool.cmd_buffs[1]);
vkEndCommandBuffer(pool.cmd_buffs[1]);
VkSubmitInfo sub = {};
sub.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
sub.commandBufferCount = 1;
sub.pNext = nullptr;
sub.pSignalSemaphores = nullptr;
sub.pWaitDstStageMask = nullptr;
sub.pWaitSemaphores = nullptr;
sub.signalSemaphoreCount = 0;
sub.waitSemaphoreCount = 0;
VkResult res=VK_ERROR_DEVICE_LOST;
sub.pCommandBuffers = &pool.cmd_buffs[0];
vkQueueSubmit(vulk.queue[0], 1, &sub, VK_NULL_HANDLE);
sub.pCommandBuffers = &pool.cmd_buffs[1];
vkQueueSubmit(vulk.queue[0], 1, &sub, VK_NULL_HANDLE);
while (window.running) {
if (VK_SUCCESS != vkAcquireNextImageKHR(vulk.device, vulk.swapchain_struct.swapchain, UINT64_MAX, VK_NULL_HANDLE, fence, &img_pres)) {
return -2;
}
vkWaitForFences(vulk.device, 1, &fence, VK_TRUE, UINT64_MAX);
vkResetFences(vulk.device, 1, &fence);vkQueueWaitIdle(vulk.queue[0]);
sub.pCommandBuffers = &pool.cmd_buffs[img_pres];
if (res == vkQueueSubmit(vulk.queue[0], 1, &sub, VK_NULL_HANDLE)) {
printf("img: %d\n",res);
}
cout << hex << vulk.image.depth_images[0] << endl;
vkQueuePresentKHR(vulk.queue[0], &info);
window.run();
}
return 0;
}
1) Update your SDK. There is even no VK_LAYER_LUNARG_image layer since 1.0.42.0. And you know, there was probably a bunchload of bugfixes.
2) You are enabling layers in wrong order. Use the VK_LAYER_LUNARG_standard_validation meta-layer instead of doing it manually (also avoids problem in 1 trying to use obsoleted layer).
3) I see many errors in your code. Layers do not necessarily have full coverage yet (and another uncought error may cause to show another error down the road that does not make sense without the context).
E.g. no synchronization (your semaphores are unused there), many memory leaks (due to C style programming), assuming there will be at least two swapchain images, not checking VkResults...
4) I cannot reproduce it with your code. Firstly I get a problem with having only one swapchain image and the code not expecting it (mentioned in 3). After fixing that I get error about vkAcquireNextImageKHR getting more images than allowed (driver layer bug if using VkPresentInfoKHR::pResults). Workarounding that I get no error messages.
I haven't checked your code exhaustively, but the renderpass says that both attachments are initially in UNDEFINED layout, transition to COLOR_ATTACHMENT_OPTIMAL/DEPTH_STENCIL_ATTACHMENT_OPTIMAL, and then finally to PRESENT_SRC/DEPTH_STENCIL_ATTACHMENT_OPTIMAL. That seems correct, and the validation layers appear to be ignoring the renderpass initialLayout settings. If you're seeing this on the most recent version of the SDK, please file a bug at https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers.