Related
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();
}
I'm making a vulkan renderer and when I try to create a logical device it throws the following exception on vkCreateDevice only in debug mode:
Exception thrown at 0x00007FFBA327A34B (vulkan-1.dll) in Game.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.
Here's the code (By the way this was made mostly following the vulkan-tutorial.com tutorial):
bool FindQueueFamilies(VkPhysicalDevice device, uint32_t* indices)
{
bool found = false;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
VkQueueFamilyProperties queueFamilies[512];
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies);
for (uint32_t i = 0; i < queueFamilyCount; i++)
{
const auto& queueFamily = queueFamilies[i];
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
if (indices != nullptr)
{
*indices = i;
}
found = true;
}
}
if (!found)
{
Loggers::Error("Didn't find queue family!");
}
return found;
}
...
void* RenderDevice::CreateVulkan(void* physicalDevice)
{
//Logical device
uint32_t indices = 0;
FindQueueFamilies(*((VkPhysicalDevice*)physicalDevice), &indices);
float queuePriority = 1.0f;
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.pNext = nullptr;
queueCreateInfo.flags = 0;
queueCreateInfo.queueFamilyIndex = indices;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
VkPhysicalDeviceFeatures deviceFeatures{};
VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.queueCreateInfoCount = 1;
createInfo.pQueueCreateInfos = &queueCreateInfo;
createInfo.enabledExtensionCount = deviceExtensionsCount;
createInfo.ppEnabledExtensionNames = deviceExtensions;
createInfo.pEnabledFeatures = &deviceFeatures;
VkDevice device;
if (vkCreateDevice(*((VkPhysicalDevice*)physicalDevice), &createInfo, nullptr, &device) != VK_SUCCESS)
{
Loggers::Error("failed to create logical device!");
}
VkQueue graphicsQueue;
vkGetDeviceQueue(device, indices, 0, &graphicsQueue);
return &device;
}
To me it looks like you meant physicalDevice instead of *((VkPhysicalDevice*)physicalDevice), since that's what vulkan-turorial.com uses and that's also what I use in my rendered. Was that your problem? Also keep in mind that access violations can be caused by bad pointers.
Environment:
Ubuntu 16.04 (x64)
C++
ffmpeg
Use-case
Multiple MPEG-TS fragments are rapidly decoded ( numerous every sec )
The format of the TS fragments is dynamic and can't be known ahead of time
The first A/V frames of each fragment are needed to be extracted
Problem statement
The code bellow successfully decodes A/V, BUT, has a huge memory leak ( MBytes/sec )
According to the docs seems all memory is freed as it should ( does it... ? )
Why do I get this huge mem leak, what am I missing in the following code snap ?
struct MEDIA_TYPE {
ffmpeg::AVMediaType eType;
union {
struct {
ffmpeg::AVPixelFormat colorspace;
int width, height;
float fFPS;
} video;
struct : WAVEFORMATEX {
short sSampleFormat;
} audio;
} format;
};
struct FRAME {
enum { MAX_PALNES = 3 + 1 };
int iStrmId;
int64_t pts; // Duration in 90Khz clock resolution
uint8_t** ppData; // Null terminated
int32_t* pStride;// Zero terminated
};
HRESULT ProcessTS(IN Operation op, IN uint8_t* pTS, IN uint32_t uiBytes, bool(*cb)(IN const MEDIA_TYPE& mt, IN FRAME& frame, IN PVOID pCtx), IN PVOID pCbCtx)
{
uiBytes -= uiBytes % 188;// align to 188 packet size
struct CONTEXT {
uint8_t* pTS;
uint32_t uiBytes;
int32_t iPos;
} ctx = { pTS, uiBytes, 0 };
LOGTRACE(TSDecoder, "ProcessTS(%d, 0x%.8x, %d, 0x%.8x, 0x%.8x), this=0x%.8x\r\n", (int)op, pTS, uiBytes, cb, pCbCtx, this);
ffmpeg::AVFormatContext* pFmtCtx = 0;
if (0 == (pFmtCtx = ffmpeg::avformat_alloc_context()))
return E_OUTOFMEMORY;
ffmpeg::AVIOContext* pIoCtx = ffmpeg::avio_alloc_context(pTS, uiBytes, 0, &ctx
, [](void *opaque, uint8_t *buf, int buf_size)->int {
auto pCtx = (CONTEXT*)opaque;
int size = pCtx->uiBytes;
if (pCtx->uiBytes - pCtx->iPos < buf_size)
size = pCtx->uiBytes - pCtx->iPos;
if (size > 0) {
memcpy(buf, pCtx->pTS + pCtx->iPos, size);
pCtx->iPos += size;
}
return size;
}
, 0
, [](void* opaque, int64_t offset, int whence)->int64_t {
auto pCtx = (CONTEXT*)opaque;
switch (whence)
{
case SEEK_SET:
pCtx->iPos = offset;
break;
case SEEK_CUR:
pCtx->iPos += offset;
break;
case SEEK_END:
pCtx->iPos = pCtx->uiBytes - offset;
break;
case AVSEEK_SIZE:
return pCtx->uiBytes;
}
return pCtx->iPos;
});
pFmtCtx->pb = pIoCtx;
int iRet = ffmpeg::avformat_open_input(&pFmtCtx, "fakevideo.ts", m_pInputFmt, 0);
if (ERROR_SUCCESS != iRet) {
assert(false);
pFmtCtx = 0;// a user-supplied AVFormatContext will be freed on failure.
return E_FAIL;
}
struct DecodeContext {
ffmpeg::AVStream* pStream;
ffmpeg::AVCodec* pDecoder;
int iFramesProcessed;
};
HRESULT hr = S_OK;
int iStreamsProcessed = 0;
bool bVideoFound = false;
int64_t ptsLast = 0;
int64_t dtsLast = 0;
auto pContext = (DecodeContext*)alloca(sizeof(DecodeContext) * pFmtCtx->nb_streams);
for (unsigned int i = 0; i < pFmtCtx->nb_streams; i++) {
assert(pFmtCtx->streams[i]->index == i);
pContext[i].pStream = pFmtCtx->streams[i];
pContext[i].pDecoder = ffmpeg::avcodec_find_decoder(pFmtCtx->streams[i]->codec->codec_id);
pContext[i].iFramesProcessed= 0;
if (0 == pContext[i].pDecoder)
continue;
if ((iRet = ffmpeg::avcodec_open2(pFmtCtx->streams[i]->codec, pContext[i].pDecoder, NULL)) < 0) {
_ASSERT(FALSE);
hr = E_FAIL;
goto ErrExit;
}
}
while (S_OK == hr) {
ffmpeg::AVFrame* pFrame = 0;
ffmpeg::AVPacket pkt;
ffmpeg::av_init_packet(&pkt);
if (ERROR_SUCCESS != (iRet = ffmpeg::av_read_frame(pFmtCtx, &pkt))) {
hr = E_FAIL;
break;
}
if ((0 == dtsLast) && (0 != pkt.dts))
dtsLast = pkt.dts;
if ((0 == ptsLast) && (0 != pkt.pts))
ptsLast = pkt.pts;
DecodeContext& ctx = pContext[pkt.stream_index];
if (Operation::DECODE_FIRST_FRAME_OF_EACH_STREAM == op) {
if (iStreamsProcessed == pFmtCtx->nb_streams) {
hr = S_FALSE;
goto Next;
}
if (ctx.iFramesProcessed > 0)
goto Next;
iStreamsProcessed++;
}
if (0 == ctx.pDecoder)
goto Next;
if (0 == (pFrame = ffmpeg::av_frame_alloc())) {
hr = E_OUTOFMEMORY;
goto Next;
}
LOGTRACE(TSDecoder, "ProcessTS(%d, 0x%.8x, %d, 0x%.8x, 0x%.8x), this=0x%.8x, decode, S:%d, T:%d\r\n", (int)op, pTS, uiBytes, cb, pCbCtx, this, pkt.stream_index, ctx.pStream->codec->codec_type);
int bGotFrame = false;
int iBytesUsed = 0;
MEDIA_TYPE mt;
memset(&mt, 0, sizeof(mt));
mt.eType = ctx.pStream->codec->codec_type;
switch (mt.eType) {
case ffmpeg::AVMediaType::AVMEDIA_TYPE_AUDIO:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if((iRet = ffmpeg::avcodec_decode_audio4(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
goto Next;
}
_ASSERT(pkt.size == iRet);
// FFMPEG AAC decoder oddity, first call to 'avcodec_decode_audio4' results mute audio where the second result the expected audio
bGotFrame = false;
if ((iRet = ffmpeg::avcodec_decode_audio4(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
goto Next;
}
_ASSERT(pkt.size == iRet);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (false == bGotFrame)
goto Next;
iBytesUsed = ctx.pStream->codec->frame_size;
mt.format.audio.nChannels = ctx.pStream->codec->channels;
mt.format.audio.nSamplesPerSec = ctx.pStream->codec->sample_rate;
mt.format.audio.wBitsPerSample = ffmpeg::av_get_bytes_per_sample(ctx.pStream->codec->sample_fmt) * 8;
mt.format.audio.nBlockAlign = mt.format.audio.nChannels * mt.format.audio.wBitsPerSample / 8;
mt.format.audio.sSampleFormat = (short)pFrame->format;
break;
case ffmpeg::AVMediaType::AVMEDIA_TYPE_VIDEO:
if ((iRet = ffmpeg::avcodec_decode_video2(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
break;
}
if (false == bGotFrame)
goto Next;
assert(ffmpeg::AVPixelFormat::AV_PIX_FMT_YUV420P == ctx.pStream->codec->pix_fmt);// Thats is the only color space currently supported
iBytesUsed = (ctx.pStream->codec->width * ctx.pStream->codec->height * 3) / 2;
mt.format.video.width = ctx.pStream->codec->width;
mt.format.video.height = ctx.pStream->codec->height;
mt.format.video.colorspace = ctx.pStream->codec->pix_fmt;
mt.format.video.fFPS = (float)ctx.pStream->codec->framerate.num / ctx.pStream->codec->framerate.den;
bVideoFound = true;
break;
default:
goto Next;
}
ctx.iFramesProcessed++;
{
FRAME f = { ctx.pStream->index, ((0 == ptsLast) ? dtsLast : ptsLast), (uint8_t**)pFrame->data, (int32_t*)pFrame->linesize };
if ((iRet > 0) && (false == cb(mt, f, pCbCtx)))
hr = S_FALSE;// Breaks the loop
}
Next:
ffmpeg::av_free_packet(&pkt);
if (0 != pFrame) {
//ffmpeg::av_frame_unref(pFrame);
ffmpeg::av_frame_free(&pFrame);
pFrame = 0;
}
}
ErrExit:
for (unsigned int i = 0; i < pFmtCtx->nb_streams; i++)
ffmpeg::avcodec_close(pFmtCtx->streams[i]->codec);
pIoCtx->buffer = 0;// We have allocated the buffer, no need for ffmpeg to free it 4 us
pFmtCtx->pb = 0;
ffmpeg::av_free(pIoCtx);
ffmpeg::avformat_close_input(&pFmtCtx);
ffmpeg::avformat_free_context(pFmtCtx);
return hr;
}
You need to unref the packets before reusing them. And there's no need to allocate and deallocate them all the time.
Here's how I do it which might help you:
// Initialise a packet queue
std::list<AVPacket *> packets;
...
for (int c = 0; c < MAX_PACKETS; c++) {
ff->packets.push_back(av_packet_alloc());
}
while (!quit) {
... get packet from queue
int err = av_read_frame(ff->context, packet);
... process packet (audio, video, etc)
av_packet_unref(packet); // add back to queue for reuse
}
// Release packets
while (ff->packets.size()) { // free packets
AVPacket *packet = ff->packets.front();
av_packet_free(&packet);
ff->packets.pop_front();
}
In your code you've freed a packet which wasn't allocated in the first place.
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.
I am searching how to open archive from memory buffer using minizip.
I found ioapi_mem_c.zip from their page http://www.winimage.com/zLibDll/minizip.html.
I can't understand how to use it. Can some one give me an example?
I solved my problem for unziping:
I added this function to unzip.c
extern unzFile ZEXPORT unzOpenBuffer (const void* buffer, uLong size)
{
char path[16] = {0};
zlib_filefunc64_32_def memory_file;
uLong base = (uLong)buffer;
sprintf(path, "%x+%x", base, size);
fill_memory_filefunc64_32(&memory_file);
return unzOpenInternal(path, &memory_file, 0);
}
And made some changes in ioapi_mem.c:
void fill_memory_filefunc64_32 (pzlib_filefunc_def)
zlib_filefunc64_32_def* pzlib_filefunc_def;
{
pzlib_filefunc_def->zopen32_file = fopen_mem_func;
pzlib_filefunc_def->zfile_func64.zopen64_file = fopen_mem_func;
pzlib_filefunc_def->zfile_func64.zread_file = fread_mem_func;
pzlib_filefunc_def->zfile_func64.zwrite_file = fwrite_mem_func;
pzlib_filefunc_def->ztell32_file = ftell_mem_func;
pzlib_filefunc_def->zseek32_file = fseek_mem_func;
pzlib_filefunc_def->zfile_func64.zseek64_file = NULL;
pzlib_filefunc_def->zfile_func64.zclose_file = fclose_mem_func;
pzlib_filefunc_def->zfile_func64.zerror_file = ferror_mem_func;
pzlib_filefunc_def->zfile_func64.opaque = NULL;
}
I hope this will help someone who will have the same problem.
And Here is simple class implementation how to use it:
void ZipArchiveImpl::OpenArchive()
{
ASSERT(!mInited, "Already opened.");
if ((mFileMode == FM_READ))
{
if (mArchiveName.size() == 0)
{
u32 sz = mFile->GetFileSize();
mUnzBlock.Resize(sz);
mFile->SetPosition(0);
mFile->Read(mUnzBlock.Data(), mUnzBlock.GetSizeInBytes());
mUnzHandle = unzOpenBuffer(mUnzBlock.Data(), mUnzBlock.GetSizeInBytes());
}
else
{
mUnzHandle = unzOpen(mArchiveName.c_str());
}
if (!mUnzHandle) return;
FillMap();
}
else if (mFileMode == FM_WRITE)
{
ASSERT0(mArchiveName.size());
mZipHandle = zipOpen(mArchiveName.c_str(), 0);
if (!mZipHandle) return;
}
mInited = true;
}
IFile* ZipArchiveImpl::OpenRead(const std::string& name)
{
if (IsExist(name))
{
ZipFileInfo info = mFileMap.find(name)->second;
MemoryBlock block(1);
block.Resize(info.uncompressedSize);
int res = unzGoToFilePos(mUnzHandle, &info.filePosInfo);
if (UNZ_OK != res)
{
return false;
}
// open the current file with optional password
if (mArchivePassword != "")
{
res = unzOpenCurrentFilePassword(info.zipFileHandle, mArchivePassword.c_str());
}
else
{
res = unzOpenCurrentFile(info.zipFileHandle);
}
if (UNZ_OK != res)
{
return false;
}
// read uncompressed data
int readResult = unzReadCurrentFile(info.zipFileHandle, block.Data(), info.uncompressedSize);
// close the file
res = unzCloseCurrentFile(info.zipFileHandle);
if (UNZ_OK != res)
{
return false;
}
if (info.uncompressedSize == readResult)
{
return ROBE_NEW MemoryFile(block.Data(), info.uncompressedSize);
}
else
{
return NULL;
}
}
else
{
return NULL;
}
}
IFile* ZipArchiveImpl::OpenRead(u32 id)
{
ASSERT0(mFileNames.size() > id);
if (IsExist(mFileNames[id]))
{
return OpenRead(mFileNames[id]);
}
else
{
return NULL;
}
}
void ZipArchiveImpl::FillMap()
{
s32 walkRes = unzGoToFirstFile(mUnzHandle);
unz_file_info info;
while (UNZ_OK == walkRes)
{
// get info about current file
char currentFileName[512];
s32 fileInfoRes = unzGetCurrentFileInfo(mUnzHandle, &info, currentFileName, sizeof(currentFileName), 0, 0, 0, 0);
std::string name = std::string(currentFileName);
mFileNames.push_back(name);
InitInfo(name, &info);
walkRes = unzGoToNextFile(mUnzHandle);
}
OpenRead(0);
if (UNZ_END_OF_LIST_OF_FILE != walkRes)
{
}
}
void ZipArchiveImpl::InitInfo(const std::string& name, unz_file_info* info)
{
ZipFileInfo zfi;
mFileMap.insert(std::pair<std::string, ZipFileInfo>(name, zfi));
mFileMap[name].zipFileHandle = mUnzHandle;
int res = unzGetFilePos(mFileMap[name].zipFileHandle, &mFileMap[name].filePosInfo);
mFileMap[name].uncompressedSize = info->uncompressed_size;
char lastsymbol = name[name.size() - 1];
if (lastsymbol == '/' || lastsymbol == '\\')
{
mFileMap[name].type = ZFT_DIR;
}
else
{
mFileMap[name].type = ZFT_FILE;
}
}
ZipArchiveImpl::~ZipArchiveImpl()
{
if (mInited)
{
if (mUnzHandle) unzClose(mUnzHandle);
if (mZipHandle) zipClose(mZipHandle, 0);
}
}
bool ZipArchiveImpl::IsExist(const std::string& name)
{
return (mFileMap.find(name) != mFileMap.end());
}
void ZipArchiveImpl::SaveFileToZip(const std::string& path, IFile* file)
{
const u32 DefaultFileAttribute = 32;
MemoryBlock block(1);
block.Resize(file->GetFileSize());
file->Read(block.Data(), block.GetSizeInBytes());
zip_fileinfo zinfo;
memset(&zinfo, 0, sizeof(zinfo));
zinfo.internal_fa = 0;
zinfo.external_fa = DefaultFileAttribute;
::boost::posix_time::ptime pt = ::boost::posix_time::from_time_t(time(0));
std::tm ptm = ::boost::posix_time::to_tm(pt);
zinfo.dosDate = 0;
zinfo.tmz_date.tm_year = ptm.tm_year;
zinfo.tmz_date.tm_mon = ptm.tm_mon;
zinfo.tmz_date.tm_mday = ptm.tm_mday;
zinfo.tmz_date.tm_hour = ptm.tm_hour;
zinfo.tmz_date.tm_min = ptm.tm_min;
zinfo.tmz_date.tm_sec = ptm.tm_sec;
zipOpenNewFileInZip(mZipHandle, path.c_str(), &zinfo, 0, 0, 0, 0, 0, Z_DEFLATED, Z_BEST_SPEED);
zipWriteInFileInZip(mZipHandle, block.Data(), block.GetSizeInBytes());
zipCloseFileInZip(mZipHandle);
}
unsigned long ZipArchiveImpl::GetFileAttributes(const std::string& filePath)
{
unsigned long attrib = 0;
#ifdef WIN32
attrib = ::GetFileAttributes(filePath.c_str());
#else
struct stat path_stat;
if (::stat(filePath.c_str(), &path_stat) == 0)
{
attrib = path_stat.st_mode;
}
#endif
return attrib;
}
added this function to unzip.c
extern unzFile ZEXPORT unzOpenBuffer(const void* buffer, uLong size)
{
zlib_filefunc_def filefunc32 = { 0 };
ourmemory_t *punzmem = (ourmemory_t*)malloc(sizeof(ourmemory_t));
punzmem->size = size;
punzmem->base = (char *)malloc(punzmem->size);
memcpy(punzmem->base, buffer, punzmem->size);
punzmem->grow = 0;
punzmem->cur_offset = 0;
punzmem->limit = 0;
fill_memory_filefunc(&filefunc32, punzmem);
return unzOpen2(NULL, &filefunc32);
}
Looking at the code in the link, there is no obvious way to pass a memory buffer. Save your memory buffer as a file, unzip it.
Or you could implement your own zlib_filefunc_def variant that operates on a lump of memory instead of a file. I don't think that is very hard to do.
Checkout the nmoinvaz fork of minizip: To unzip from a zip file in memory use fill_memory_filefunc and supply a proper ourmemory_t structure
zlib_filefunc_def filefunc32 = {0};
ourmemory_t unzmem = {0};
unzmem.size = bufsize;
unzmem.base = (char *)malloc(unzmem.size);
memcpy(unzmem.base, buffer, unzmem.size);
fill_memory_filefunc(&filefunc32, &unzmem);
unzOpen2("__notused__", &filefunc32);