Issue with passing data from Vertex Shader to Fragment Shader

I am trying to render a simple triangle on screen. Currently, i am just seeing a blank screen with the color of my ClearValue that I pass into my VkRenderPassBeginInfo object. My triangle vertices are set up on the vertex shader and I am making a draw call with the vertexCount = 3. I have set the right shader stage flags too such as VK_SHADER_STAGE_VERTEX_BIT and VK_SHADER_STAGE_FRAGMENT_BIT.

I have no validation layer messages. After debugging it with RenderDoc I found out that my vertex shader is behaving the way it should. In the “VS Out” tab, I can see the triangle just fine. But when I select the Fragment shader from the “Pipeline State” window, it does not show me anything. This led me to believe that something was wrong with my Frag Shader Module. I have tried a lot of things none of which have seemed to work. I have also checked the Disassembly of the frag shader to confirm that the shader seems to be compiled correctly(I am using shaderc). Any help would be appreciated. I have linked a pastebin with the parts of code that I think are relevant, if I missed something please let me know.

Things that I have tried/other details:

  • I am using VK_CULL_MODE_NONE when creating the pipeline
  • Not using any depth buffering or color blending
  • VkPipelineRasterizationStateCreateInfo::rasterizerDiscardEnable is false

Edit 1:

  • Validation Layers are enabled and no errors appear while running

relevant parts of my code(pastebin): pastebin/rH4MvUGe

Based on the information provided, I don’t think it’s possible to say definitively what the problem might be. But you wrote that RenderDoc shows only the vertex shader stage result. Probably the fragment shader stage either does not participate in the pipeline or is not associated with the Swapchain image. Can you provide pipeline settings, swapchain creaton code and render pass settings?

void createGraphicsPipeline() {

    createShaders();

    createPipelineLayout();

    createRenderPass();

    PipelineConfigInfo pipelineConfigInfo = defaultPipelineConfigInfo();

    pipelineConfigInfo.renderPass = m_renderPass;
    pipelineConfigInfo.pipelineLayout = pipelineLayout;

    VkPipelineShaderStageCreateInfo vkPipelineShaderStageCreateInfo[2];
    vkPipelineShaderStageCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    vkPipelineShaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
    vkPipelineShaderStageCreateInfo[0].module = vertexShader;
    vkPipelineShaderStageCreateInfo[0].pName = "main";
    vkPipelineShaderStageCreateInfo[0].flags = 0;
    vkPipelineShaderStageCreateInfo[0].pNext = nullptr;
    vkPipelineShaderStageCreateInfo[0].pSpecializationInfo = nullptr;

    vkPipelineShaderStageCreateInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    vkPipelineShaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
    vkPipelineShaderStageCreateInfo[1].module = pixelShader;
    vkPipelineShaderStageCreateInfo[1].pName = "main";
    vkPipelineShaderStageCreateInfo[1].flags = 0;
    vkPipelineShaderStageCreateInfo[1].pNext = nullptr;
    vkPipelineShaderStageCreateInfo[1].pSpecializationInfo = nullptr;

    VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
    vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    vertexInputInfo.vertexAttributeDescriptionCount =0 ;
    vertexInputInfo.vertexBindingDescriptionCount = 0;
    vertexInputInfo.pVertexAttributeDescriptions = nullptr;
    vertexInputInfo.pVertexBindingDescriptions = nullptr;

    VkSurfaceCapabilitiesKHR SurfaceCaps;
    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &SurfaceCaps);

    VkViewport viewport{};
    viewport.x = 0.0f;
    viewport.y = 0.0f;
    viewport.width = (float)SurfaceCaps.currentExtent.width;
    viewport.height = (float)SurfaceCaps.currentExtent.height;
    viewport.minDepth = 0.0f;
    viewport.maxDepth = 1.0f;

    VkRect2D scissor{};
    scissor.offset = { 0, 0 };
    scissor.extent = SurfaceCaps.currentExtent;

    VkPipelineViewportStateCreateInfo viewportInfo{};
    viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    viewportInfo.viewportCount = 1;
    viewportInfo.pViewports = &viewport;
    viewportInfo.scissorCount = 1;
    viewportInfo.pScissors = &scissor;

    VkGraphicsPipelineCreateInfo pipelineInfo{};
    pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    pipelineInfo.stageCount = 2;
    pipelineInfo.pStages = vkPipelineShaderStageCreateInfo;
    pipelineInfo.pVertexInputState = &vertexInputInfo;
    pipelineInfo.pInputAssemblyState = &pipelineConfigInfo.vkPipelineInputAssemblyStateCreateInfo;
    pipelineInfo.pViewportState = &viewportInfo;
    pipelineInfo.pRasterizationState = &pipelineConfigInfo.rasterizationInfo;
    pipelineInfo.pMultisampleState = &pipelineConfigInfo.multisampleInfo;
    pipelineInfo.pColorBlendState = &pipelineConfigInfo.colorBlendInfo;
    pipelineInfo.pDepthStencilState = &pipelineConfigInfo.depthStencilInfo;
    pipelineInfo.pDynamicState = nullptr;

    pipelineInfo.layout = pipelineConfigInfo.pipelineLayout;
    pipelineInfo.renderPass = pipelineConfigInfo.renderPass;
    pipelineInfo.subpass = pipelineConfigInfo.subpass;

    pipelineInfo.basePipelineIndex = -1;
    pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;



    CHECK_VK_RESULT(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_pipeline));
    cout << "created graphics pipeline successfully\n";
}`

void createRenderPass() {

   VkAttachmentDescription colorAttachment{};

    colorAttachment.format = getFormat().format;
    colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
    colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
    colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
    colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
    colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
    colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

    VkAttachmentReference colorAttachmentRef{};
    colorAttachmentRef.attachment = 0;
    colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

    VkSubpassDescription subpass{};
    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
    subpass.colorAttachmentCount = 1;
    subpass.pColorAttachments = &colorAttachmentRef;

    VkRenderPassCreateInfo renderPassInfo{};
    renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
    renderPassInfo.attachmentCount = 1;
    renderPassInfo.pAttachments = &colorAttachment;
    renderPassInfo.subpassCount = 1;
    renderPassInfo.pSubpasses = &subpass;

    if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) {
        throw std::runtime_error("Failed to create render pass!");
    }

    cout << "created render pass succesfully\n";
} `

void createSwapChain() {

    VkSurfaceCapabilitiesKHR SurfaceCaps;
    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &SurfaceCaps);
    uint32_t formatCount;

    vector<VkSurfaceFormatKHR> vkSurfaceFormatKHRs;
    vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);

    vkSurfaceFormatKHRs.resize(formatCount);
    vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, vkSurfaceFormatKHRs.data());
    VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(vkSurfaceFormatKHRs);

    assert(SurfaceCaps.currentExtent.width != -1);

    unsigned int NumImages = 2;

    assert(NumImages >= SurfaceCaps.minImageCount);
    assert(NumImages <= SurfaceCaps.maxImageCount);

    VkSwapchainCreateInfoKHR SwapChainCreateInfo = {};
    SwapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    SwapChainCreateInfo.surface = surface;
    SwapChainCreateInfo.minImageCount = NumImages;
    SwapChainCreateInfo.imageFormat = surfaceFormat.format;
    SwapChainCreateInfo.imageColorSpace = surfaceFormat.colorSpace;
    SwapChainCreateInfo.imageExtent = SurfaceCaps.currentExtent;
    SwapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    SwapChainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;// ADNROID ORIENTATION STUFF
    SwapChainCreateInfo.imageArrayLayers = 1;//AR VR STUFF
    SwapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
    SwapChainCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;//v-sync stuff
    SwapChainCreateInfo.clipped = true;
    SwapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;//how the surface interacts with the bg(OS stuff)


    VkResult res = vkCreateSwapchainKHR(device, &SwapChainCreateInfo, NULL, &m_swapChainKHR);

    CHECK_VK_RESULT(res);

    unsigned int NumSwapChainImages = 0;
    res = vkGetSwapchainImagesKHR(device, m_swapChainKHR, &NumSwapChainImages, NULL);

    CHECK_VK_RESULT(res);

    m_images.resize(NumSwapChainImages);
    m_cmdBufs.resize(NumSwapChainImages);

    VkImage s;
    res = vkGetSwapchainImagesKHR(device, m_swapChainKHR, &NumSwapChainImages, &(m_images[0]));
    CHECK_VK_RESULT(res);

    cout << "swapchain created successfully\n";

};`

void createSyncObjects( ) {

    VkSemaphoreCreateInfo semaphoreInfo = {};
    semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

    if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS) {
        throw std::runtime_error("Failed to create semaphore!");
    }

    VkFenceCreateInfo fenceInfo = {};
    fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    fenceInfo.flags = 1; // Ensure the fence starts unsignaled

    if (vkCreateFence(device, &fenceInfo, nullptr, &drawFence) != VK_SUCCESS) {
        throw std::runtime_error("Failed to create fence!");
    }

    cout << "semaphore and fence created successfully\n";

}`

I don’t know if the next part is relevant but here is the order of my functions:

  1. createInstance();
    
  2. createSurface();
    
  3. createPhysicalDevice();
    
  4. createLogicDevice();
    
  5. createSwapChain();
    
  6. createSyncObjects();
    
  7. createGraphicsPipeline();
    
  8. createImageViews();
    
  9. createDepthResources();
    
  10. createFramebuffers();
    
  11. createCommandBuffers();
    

Edit: Added my drawFrame()

void drawFrame() {

//cout << "waiting for fence\n";
vkWaitForFences(device, 1, &drawFence, VK_TRUE, UINT64_MAX);

//cout << "acquiring next image...\n";
uint32_t imageIndex;
CHECK_VK_RESULT(vkAcquireNextImageKHR(device, m_swapChainKHR, UINT64_MAX, imageAvailableSemaphore, nullptr, &imageIndex));

// Reset the fence to unsignaled state before using it
vkResetFences(device, 1, &drawFence);

VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &m_cmdBufs[imageIndex];

CHECK_VK_RESULT(vkQueueSubmit(graphicsQueue,1, &submitInfo, drawFence));
//cout << "submitted next image...\n";

VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;

presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &imageAvailableSemaphore;

VkSwapchainKHR swapChains[] = { m_swapChainKHR };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;

presentInfo.pImageIndices = &imageIndex;

CHECK_VK_RESULT(vkQueuePresentKHR(graphicsQueue, &presentInfo));


}`

here’s the code that you requested: pastebin/EpNTBnX4
since I’m unable to add the full URL

Could be anything\many things. Hard to say without the ability to scan the whole code.

What are your pipeline write masks?

In your code, your present does not wait on the result of the draw\submit. And neither does the draw seem to wait for the image to become available back from the swapchain.

In your validation layers, enable the synchronization validation optional setting.

configInfo.colorBlendAttachment.colorWriteMask =
            VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
            VK_COLOR_COMPONENT_A_BIT;

here is my code

#define GLFW_INCLUDE_VULKAN
#undef _DEBUG
#include <glfw3.h>
#include < stdexcept>
#include < cstdlib>
#include < vector>
#include < cstring>
#include < algorithm>
#include < glm/glm.hpp>
#include < set>
#include < optional>
#include < iostream>
#include < memory>
#include < shaderc/shaderc.hpp>
#include < vulkan/vk_enum_string_helper.h>

const int WIDTH = 800;
const int HEIGHT = 600;

static const char* validationLayer[] = {
    "VK_LAYER_KHRONOS_validation", // standard validation layer
    //"VK_LAYER_LUNARG_standard_validation", // add if not on MacOS
    "VK_LAYER_RENDERDOC_Capture", // add this if you have installed RenderDoc
    "VK_LAYER_KHRONOS_synchronization2"
};
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif

#ifdef _WIN32 // must use MT platform DLL libraries on windows
#pragma comment(lib, "shaderc_combined.lib") 
#endif

#define ARRAY_SIZE_IN_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
#define uint unsigned int
#define CHECK_VK_RESULT(res) \
    {\
        VkResult result = (res); \
        std::string res_s = string_VkResult(result); \
        if (result != VK_SUCCESS) { \
            throw std::runtime_error(res_s); \
        } \
    } 
using namespace std;
class VulkanRenderer {

private:
    struct QueueFamilyIndices {
        uint32_t graphicsFamily;
        uint32_t presentFamily;
        bool graphicsFamilyHasValue = false;
        bool presentFamilyHasValue = false;
        bool isComplete() {
            return graphicsFamilyHasValue && presentFamilyHasValue;
        }
    };

    struct PipelineConfigInfo {
        VkViewport viewport;
        VkRect2D scissor;
        VkPipelineInputAssemblyStateCreateInfo vkPipelineInputAssemblyStateCreateInfo;
        VkPipelineRasterizationStateCreateInfo rasterizationInfo;
        VkPipelineMultisampleStateCreateInfo multisampleInfo;
        VkPipelineColorBlendAttachmentState colorBlendAttachment;
        VkPipelineColorBlendStateCreateInfo colorBlendInfo;
        VkPipelineDepthStencilStateCreateInfo depthStencilInfo;
        VkPipelineLayout pipelineLayout = nullptr;
        VkRenderPass renderPass = nullptr;
        uint32_t subpass = 0;
    };

    //HELPERS
    VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
        for (const auto& availableFormat : availableFormats) {
            if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
                return availableFormat;
            }
        }

        return availableFormats[0];
    }
    QueueFamilyIndices  findQueueFamilies() {
        QueueFamilyIndices indices;

        uint32_t queueFamilyCount = 0;
        vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);

        std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
        vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data());

        int i = 0;
        for (const auto& queueFamily : queueFamilies) {
            if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
                indices.graphicsFamily = i;
                indices.graphicsFamilyHasValue = true;
            }
            VkBool32 presentSupport = false;
            vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &presentSupport);
            if (queueFamily.queueCount > 0 && presentSupport) {
                indices.presentFamily = i;
                indices.presentFamilyHasValue = true;
            }
            if (indices.isComplete()) {
                break;
            }

            i++;
        }

        return indices;
    }
    VkSurfaceFormatKHR getFormat() {
        uint32_t formatCount;
        vector<VkSurfaceFormatKHR> vkSurfaceFormatKHRs;
        vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);
        vkSurfaceFormatKHRs.resize(formatCount);
        vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, vkSurfaceFormatKHRs.data());
        VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(vkSurfaceFormatKHRs);

        return surfaceFormat;
    }
    PipelineConfigInfo defaultPipelineConfigInfo() {
        PipelineConfigInfo configInfo = {};

        configInfo.vkPipelineInputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
        configInfo.vkPipelineInputAssemblyStateCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
        configInfo.vkPipelineInputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE;

        configInfo.viewport.x = 0.0f;
        configInfo.viewport.y = 0.0f;
        configInfo.viewport.width = static_cast<float>(WIDTH);
        configInfo.viewport.height = static_cast<float>(HEIGHT);
        configInfo.viewport.minDepth = 0.0f;
        configInfo.viewport.maxDepth = 1.0f;

        configInfo.scissor.extent = {WIDTH,HEIGHT};
        configInfo.scissor.offset = { 0,0};

        configInfo.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
        configInfo.rasterizationInfo.depthClampEnable = VK_FALSE;
        configInfo.rasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
        configInfo.rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL;
        configInfo.rasterizationInfo.lineWidth = 1.0f;
        configInfo.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
        configInfo.rasterizationInfo.frontFace = VK_FRONT_FACE_CLOCKWISE;
        configInfo.rasterizationInfo.depthBiasEnable = VK_FALSE;
        configInfo.rasterizationInfo.depthBiasConstantFactor = 0.0f;  // Optional
        configInfo.rasterizationInfo.depthBiasClamp = 0.0f;           // Optional
        configInfo.rasterizationInfo.depthBiasSlopeFactor = 0.0f;     // Optional

        configInfo.multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
        configInfo.multisampleInfo.sampleShadingEnable = VK_FALSE;
        configInfo.multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
        configInfo.multisampleInfo.minSampleShading = 1.0f;           // Optional
        configInfo.multisampleInfo.pSampleMask = nullptr;             // Optional
        configInfo.multisampleInfo.alphaToCoverageEnable = VK_FALSE;  // Optional
        configInfo.multisampleInfo.alphaToOneEnable = VK_FALSE;       // Optional

        configInfo.colorBlendAttachment.colorWriteMask =
            VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
            VK_COLOR_COMPONENT_A_BIT;
        configInfo.colorBlendAttachment.blendEnable = VK_FALSE;
        configInfo.colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;   
        configInfo.colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;  
        configInfo.colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;              
        configInfo.colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;   
        configInfo.colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;  
        configInfo.colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;              

        configInfo.colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
        configInfo.colorBlendInfo.logicOpEnable = VK_FALSE;
        configInfo.colorBlendInfo.logicOp = VK_LOGIC_OP_COPY;  
        configInfo.colorBlendInfo.attachmentCount = 1;
        configInfo.colorBlendInfo.pAttachments = &configInfo.colorBlendAttachment;
        configInfo.colorBlendInfo.blendConstants[0] = 0.0f;  
        configInfo.colorBlendInfo.blendConstants[1] = 0.0f;  
        configInfo.colorBlendInfo.blendConstants[2] = 0.0f;  
        configInfo.colorBlendInfo.blendConstants[3] = 0.0f;  

        configInfo.depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
        configInfo.depthStencilInfo.depthTestEnable = VK_TRUE;
        configInfo.depthStencilInfo.depthWriteEnable = VK_TRUE;
        configInfo.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS;
        configInfo.depthStencilInfo.depthBoundsTestEnable = VK_FALSE;
        configInfo.depthStencilInfo.minDepthBounds = 0.0f;  // Optional
        configInfo.depthStencilInfo.maxDepthBounds = 1.0f;  // Optional
        configInfo.depthStencilInfo.stencilTestEnable = VK_FALSE;
        configInfo.depthStencilInfo.front = {};  // Optional
        configInfo.depthStencilInfo.back = {};   // Optional

        return configInfo;

    }
    int findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
        VkPhysicalDeviceMemoryProperties memProperties;
        vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);

        for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
            if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
                return i;
            }
        }

        throw std::runtime_error("Failed to find suitable memory type!");
    }


    void createInstance() {
        VkApplicationInfo appInfo{};
        appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
        appInfo.pApplicationName = "App Name Here";
        appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
        appInfo.pEngineName = "Gear Engine";
        appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
        appInfo.apiVersion = VK_API_VERSION_1_0;

        auto extensions = getRequiredExtensions();
        VkInstanceCreateInfo createInfo = {
            .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
            .pNext = NULL,
            .pApplicationInfo = &appInfo,
            .enabledLayerCount = static_cast<uint32_t>(2),
            .ppEnabledLayerNames = validationLayer,
            .enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
            .ppEnabledExtensionNames = extensions.data()
        };

        //VkAllocationCallbacks* vkAllocationCallbacks = nullptr;
        CHECK_VK_RESULT(vkCreateInstance(&createInfo, nullptr, &instance));
    }
    void createLogicDevice() {

        QueueFamilyIndices indices = findQueueFamilies();

        std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
        std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily, indices.presentFamily };

        float queuePriority = 1.0f;
        for (uint32_t queueFamily : uniqueQueueFamilies) {
            VkDeviceQueueCreateInfo queueCreateInfo = {};
            queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
            queueCreateInfo.queueFamilyIndex = queueFamily;
            queueCreateInfo.queueCount = 1;
            queueCreateInfo.pQueuePriorities = &queuePriority;
            queueCreateInfos.push_back(queueCreateInfo);
        }


        VkPhysicalDeviceFeatures deviceFeatures = {};
        deviceFeatures.samplerAnisotropy = VK_TRUE;

        VkDeviceCreateInfo createInfo = {};
        memset(&createInfo, 0, sizeof(VkDeviceCreateInfo));
        createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
        createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
        createInfo.pQueueCreateInfos = queueCreateInfos.data();
        createInfo.pEnabledFeatures = &deviceFeatures;
        createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensionNames.size());
        createInfo.ppEnabledExtensionNames = deviceExtensionNames.data();
        createInfo.enabledLayerCount = static_cast<uint32_t>(2);
        createInfo.ppEnabledLayerNames = validationLayer;

        CHECK_VK_RESULT(vkCreateDevice(physicalDevice, &createInfo, nullptr, &device)) 

        vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);
        vkGetDeviceQueue(device, indices.presentFamily, 0, &presentQueue);

    }
    void createCommandPool() {

        QueueFamilyIndices queueFamilyIndices = findQueueFamilies();

        VkCommandPoolCreateInfo poolInfo{};
        poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
        poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;
        poolInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; // Optional: Allow resetting command buffers
        CHECK_VK_RESULT(vkCreateCommandPool(device, &poolInfo, nullptr, &m_cmdBufPool));
        cout << "created command pool successfully\n";

    }
    void createPipelineLayout() {
        VkPipelineLayoutCreateInfo vkPipelineLayoutCreateInfo;
        vkPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        vkPipelineLayoutCreateInfo.setLayoutCount = 0;
        vkPipelineLayoutCreateInfo.pSetLayouts = nullptr;
        vkPipelineLayoutCreateInfo.pushConstantRangeCount = 0;
        vkPipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
        vkPipelineLayoutCreateInfo.flags = 0;
        vkPipelineLayoutCreateInfo.pNext = nullptr;
        CHECK_VK_RESULT(vkCreatePipelineLayout(device, &vkPipelineLayoutCreateInfo, nullptr, &pipelineLayout));

        cout << "created graphics pipeline layout successfully\n";

    }
    void createGraphicsPipeline() {
        createShaders();
        createPipelineLayout();
        createRenderPass();


        PipelineConfigInfo pipelineConfigInfo = defaultPipelineConfigInfo();

        pipelineConfigInfo.renderPass = m_renderPass;
        pipelineConfigInfo.pipelineLayout = pipelineLayout;

        VkPipelineShaderStageCreateInfo vkPipelineShaderStageCreateInfo[2];
        vkPipelineShaderStageCreateInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        vkPipelineShaderStageCreateInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
        vkPipelineShaderStageCreateInfo[0].module = vertexShader;
        vkPipelineShaderStageCreateInfo[0].pName = "main";
        vkPipelineShaderStageCreateInfo[0].flags = 0;
        vkPipelineShaderStageCreateInfo[0].pNext = nullptr;
        vkPipelineShaderStageCreateInfo[0].pSpecializationInfo = nullptr;

        vkPipelineShaderStageCreateInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
        vkPipelineShaderStageCreateInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
        vkPipelineShaderStageCreateInfo[1].module = pixelShader;
        vkPipelineShaderStageCreateInfo[1].pName = "main";
        vkPipelineShaderStageCreateInfo[1].flags = 0;
        vkPipelineShaderStageCreateInfo[1].pNext = nullptr;
        vkPipelineShaderStageCreateInfo[1].pSpecializationInfo = nullptr;

        VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
        vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
        vertexInputInfo.vertexAttributeDescriptionCount =0 ;
        vertexInputInfo.vertexBindingDescriptionCount = 0;
        vertexInputInfo.pVertexAttributeDescriptions = nullptr;
        vertexInputInfo.pVertexBindingDescriptions = nullptr;

        VkSurfaceCapabilitiesKHR SurfaceCaps;
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &SurfaceCaps);

        VkViewport viewport{};
        viewport.x = 0.0f;
        viewport.y = 0.0f;
        viewport.width = (float)SurfaceCaps.currentExtent.width;
        viewport.height = (float)SurfaceCaps.currentExtent.height;
        viewport.minDepth = 0.0f;
        viewport.maxDepth = 1.0f;

        VkRect2D scissor{};
        scissor.offset = { 0, 0 };
        scissor.extent = SurfaceCaps.currentExtent;

        VkPipelineViewportStateCreateInfo viewportInfo{};
        viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
        viewportInfo.viewportCount = 1;
        viewportInfo.pViewports = &viewport;
        viewportInfo.scissorCount = 1;
        viewportInfo.pScissors = &scissor;

        VkGraphicsPipelineCreateInfo pipelineInfo{};
        pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
        pipelineInfo.stageCount = 2;
        pipelineInfo.pStages = vkPipelineShaderStageCreateInfo;
        pipelineInfo.pVertexInputState = &vertexInputInfo;
        pipelineInfo.pInputAssemblyState = &pipelineConfigInfo.vkPipelineInputAssemblyStateCreateInfo;
        pipelineInfo.pViewportState = &viewportInfo;
        pipelineInfo.pRasterizationState = &pipelineConfigInfo.rasterizationInfo;
        pipelineInfo.pMultisampleState = &pipelineConfigInfo.multisampleInfo;
        pipelineInfo.pColorBlendState = &pipelineConfigInfo.colorBlendInfo;
        pipelineInfo.pDepthStencilState = &pipelineConfigInfo.depthStencilInfo;
        pipelineInfo.pDynamicState = nullptr;

        pipelineInfo.layout = pipelineConfigInfo.pipelineLayout;
        pipelineInfo.renderPass = pipelineConfigInfo.renderPass;
        pipelineInfo.subpass = pipelineConfigInfo.subpass;

        pipelineInfo.basePipelineIndex = -1;
        pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;



        CHECK_VK_RESULT(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_pipeline));
        cout << "created graphics pipeline successfully\n";
    }
    void createSwapChain() {

        VkSurfaceCapabilitiesKHR SurfaceCaps;
        vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &SurfaceCaps);
        uint32_t formatCount;

        vector<VkSurfaceFormatKHR> vkSurfaceFormatKHRs;
        vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr);

        vkSurfaceFormatKHRs.resize(formatCount);
        vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, vkSurfaceFormatKHRs.data());
        VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(vkSurfaceFormatKHRs);

        assert(SurfaceCaps.currentExtent.width != -1);

        unsigned int NumImages = 2;

        assert(NumImages >= SurfaceCaps.minImageCount);
        assert(NumImages <= SurfaceCaps.maxImageCount);

        VkSwapchainCreateInfoKHR SwapChainCreateInfo = {};
        SwapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
        SwapChainCreateInfo.surface = surface;
        SwapChainCreateInfo.minImageCount = NumImages;
        SwapChainCreateInfo.imageFormat = surfaceFormat.format;
        SwapChainCreateInfo.imageColorSpace = surfaceFormat.colorSpace;
        SwapChainCreateInfo.imageExtent = SurfaceCaps.currentExtent;
        SwapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
        SwapChainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;// ADNROID ORIENTATION STUFF
        SwapChainCreateInfo.imageArrayLayers = 1;//AR VR STUFF
        SwapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
        SwapChainCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;//v-sync stuff
        SwapChainCreateInfo.clipped = true;
        SwapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;//how the surface interacts with the bg(OS stuff)


        VkResult res = vkCreateSwapchainKHR(device, &SwapChainCreateInfo, NULL, &m_swapChainKHR);

        CHECK_VK_RESULT(res);

        unsigned int NumSwapChainImages = 0;
        res = vkGetSwapchainImagesKHR(device, m_swapChainKHR, &NumSwapChainImages, NULL);

        CHECK_VK_RESULT(res);

        m_images.resize(NumSwapChainImages);
        m_cmdBufs.resize(NumSwapChainImages);

        VkImage s;
        res = vkGetSwapchainImagesKHR(device, m_swapChainKHR, &NumSwapChainImages, &(m_images[0]));
        CHECK_VK_RESULT(res);

        cout << "swapchain created successfully\n";

    };
    void createSyncObjects( ) {
        VkSemaphoreCreateInfo semaphoreInfo = {};
        semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;

        if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore) != VK_SUCCESS) {
            throw std::runtime_error("Failed to create semaphore!");
        }

        if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderCompleteSemaphore) != VK_SUCCESS) {
            throw std::runtime_error("Failed to create semaphore!");
        }

        VkFenceCreateInfo fenceInfo = {};
        fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
        fenceInfo.flags = 1; // Ensure the fence starts unsignaled

        if (vkCreateFence(device, &fenceInfo, nullptr, &drawFence) != VK_SUCCESS) {
            throw std::runtime_error("Failed to create fence!");
        }

        cout << "semaphore and fence created successfully\n";

    }
    void createRenderPass() {
        VkAttachmentDescription colorAttachment{};
        colorAttachment.format = getFormat().format;
        colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
        colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
        colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
        colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
        colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
        colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
        colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;

        VkAttachmentReference colorAttachmentRef{};
        colorAttachmentRef.attachment = 0;
        colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

        VkSubpassDescription subpass{};
        subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
        subpass.colorAttachmentCount = 1;
        subpass.pColorAttachments = &colorAttachmentRef;

        VkRenderPassCreateInfo renderPassInfo{};
        renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
        renderPassInfo.attachmentCount = 1;
        renderPassInfo.pAttachments = &colorAttachment;
        renderPassInfo.subpassCount = 1;
        renderPassInfo.pSubpasses = &subpass;

        if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) {
            throw std::runtime_error("Failed to create render pass!");
        }

        cout << "created render pass succesfully\n";
    
    
    } 
    void createCommandBuffers() {
        createCommandPool();

        
        uint32_t swapchainImageCount;
        vkGetSwapchainImagesKHR(device, m_swapChainKHR, &swapchainImageCount, nullptr);
        m_cmdBufs.resize(swapchainImageCount);

        VkCommandBufferAllocateInfo allocInfo{};
        allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
        allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
        allocInfo.commandPool = m_cmdBufPool;
        allocInfo.commandBufferCount = static_cast<uint32_t>(m_cmdBufs.size());

        CHECK_VK_RESULT(vkAllocateCommandBuffers(device, &allocInfo, m_cmdBufs.data()));
        cout << "allocated command buffers succesfully\n";

        for (int i = 0; i < m_cmdBufs.size();i++) {
            VkCommandBufferBeginInfo vkCommandBufferBeginInfo{};
            vkCommandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;

            CHECK_VK_RESULT(vkBeginCommandBuffer(m_cmdBufs[i], &vkCommandBufferBeginInfo));
            
            VkRenderPassBeginInfo vkRenderPassBeginInfo{};
            vkRenderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
            vkRenderPassBeginInfo.renderPass = m_renderPass;
            vkRenderPassBeginInfo.framebuffer = m_fbs[i];

            VkSurfaceCapabilitiesKHR SurfaceCaps;
            vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &SurfaceCaps);

            vkRenderPassBeginInfo.renderArea.offset = { 0,0 };
            vkRenderPassBeginInfo.renderArea.extent = SurfaceCaps.currentExtent;

            VkClearValue clearValues[2];
            clearValues[0].color = { 0.001f,0.101f,0.001f,1.0f };//background color
            clearValues[1].depthStencil = { 1.0f,0 };

            vkRenderPassBeginInfo.clearValueCount = static_cast<uint32_t>(sizeof(clearValues) / sizeof(VkClearValue));
            vkRenderPassBeginInfo.pClearValues = clearValues;

            vkCmdBeginRenderPass(m_cmdBufs[i], &vkRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);

            vkCmdBindPipeline(m_cmdBufs[i], VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);

            vkCmdDraw(m_cmdBufs[i], 3, 1, 0, 0);

            vkCmdEndRenderPass(m_cmdBufs[i]);

            CHECK_VK_RESULT(vkEndCommandBuffer(m_cmdBufs[i]));

        }
        cout << "created command buffers succesfully\n";

    }
    void createImageViews() {
        uint32_t swapchainImageCount;
        vkGetSwapchainImagesKHR(device, m_swapChainKHR, &swapchainImageCount, nullptr);
        std::vector<VkImage> swapchainImages(swapchainImageCount);
        vkGetSwapchainImagesKHR(device, m_swapChainKHR, &swapchainImageCount, swapchainImages.data());

        m_views.resize(swapchainImageCount);

        for (size_t i = 0; i < swapchainImageCount; i++) {
            VkImageViewCreateInfo createInfo{};
            createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
            createInfo.image = swapchainImages[i];
            createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
            createInfo.format = getFormat().format;
            createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            createInfo.subresourceRange.baseMipLevel = 0;
            createInfo.subresourceRange.levelCount = 1;
            createInfo.subresourceRange.baseArrayLayer = 0;
            createInfo.subresourceRange.layerCount = 1;

            if (vkCreateImageView(device, &createInfo, nullptr, &m_views[i]) != VK_SUCCESS) {
                throw std::runtime_error("Failed to create image views!");
            }
        }

        cout << "created Image views succesfully\n";
    };
    void createFramebuffers() {

        uint32_t swapchainImageCount;
        vkGetSwapchainImagesKHR(device, m_swapChainKHR, &swapchainImageCount, nullptr);

        m_fbs.resize(swapchainImageCount);

        for (size_t i = 0; i < swapchainImageCount; i++) {
            VkImageView attachments[] = {
                m_views[i]
                //,depthView
            };
            VkFramebufferCreateInfo framebufferInfo{};
            framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
            framebufferInfo.renderPass = m_renderPass;
            framebufferInfo.attachmentCount = 1;
            framebufferInfo.pAttachments = attachments;
            framebufferInfo.width = WIDTH;
            framebufferInfo.height = HEIGHT;
            framebufferInfo.layers = 1;

            if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &m_fbs[i]) != VK_SUCCESS) {
                throw std::runtime_error("Failed to create framebuffer!");
            }
        }

        cout << "frame buffer create successfully\n";
    }

    void cleanupSwapChain() {
        for (size_t i = 0; i < m_fbs.size(); i++) {
            vkDestroyFramebuffer(device, m_fbs[i], nullptr);
        }

        for (size_t i = 0; i < m_views.size(); i++) {
            vkDestroyImageView(device, m_views[i], nullptr);
        }

        vkDestroySwapchainKHR(device, m_swapChainKHR, nullptr);
    }

    void recreateSwapChain() {
        auto extent = getExtent();
        while (extent.width == 0 || extent.height == 0) {
            extent = getExtent();
            glfwWaitEvents();
        }
        vkDeviceWaitIdle(device);

        createSwapChain();
    }

    void drawFrame() {
        // Wait for the fence with a timeout
        constexpr uint64_t timeout = 100000000; // 100 ms
        const VkResult fenceResult = vkWaitForFences(device, 1, &drawFence, VK_TRUE, timeout);
        if (fenceResult == VK_TIMEOUT) {
            // Handle timeout situation
            throw std::runtime_error("Fence wait timed out!");
        }
        else if (fenceResult != VK_SUCCESS) {
            throw std::runtime_error("Failed to wait for fence!");
        }

        vkResetFences(device, 1, &drawFence);

        uint32_t imageIndex;
        VkResult acquireResult = vkAcquireNextImageKHR(device, m_swapChainKHR, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);

        if (acquireResult == VK_ERROR_OUT_OF_DATE_KHR) {
            // Handle swapchain out of date
            recreateSwapChain();
            return;
        }
        else if (acquireResult != VK_SUCCESS) {
            throw std::runtime_error("Failed to acquire next image!");
        }

        VkSubmitInfo submitInfo = {};
        submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
        submitInfo.commandBufferCount = 1;
        submitInfo.pCommandBuffers = &m_cmdBufs[imageIndex];

        VkSemaphore waitSemaphores[] = { imageAvailableSemaphore };
        VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
        submitInfo.waitSemaphoreCount = 1;
        submitInfo.pWaitSemaphores = waitSemaphores;
        submitInfo.pWaitDstStageMask = waitStages;

        VkSemaphore signalSemaphores[] = { renderCompleteSemaphore };
        submitInfo.signalSemaphoreCount = 1;
        submitInfo.pSignalSemaphores = signalSemaphores;

        CHECK_VK_RESULT(vkQueueSubmit(graphicsQueue, 1, &submitInfo, drawFence));

        VkPresentInfoKHR presentInfo = {};
        presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
        presentInfo.waitSemaphoreCount = 1;
        presentInfo.pWaitSemaphores = signalSemaphores;

        VkSwapchainKHR swapChains[] = { m_swapChainKHR };
        presentInfo.swapchainCount = 1;
        presentInfo.pSwapchains = swapChains;
        presentInfo.pImageIndices = &imageIndex;

        VkResult queuePresentResult = vkQueuePresentKHR(presentQueue, &presentInfo);

        if (queuePresentResult == VK_ERROR_OUT_OF_DATE_KHR || queuePresentResult == VK_SUBOPTIMAL_KHR) {
            // Handle swapchain out of date or suboptimal
            //recreateSwapChain();
        }
        else if (queuePresentResult != VK_SUCCESS) {
            throw std::runtime_error("Failed to present image!");
        }
    }

public:
  
    GLFWwindow* window;
    VkInstance instance; 
    VkSurfaceKHR surface;     
    VkQueue graphicsQueue;    
    VkDevice device;
    
    VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
    std::vector<VkImageView> m_views;
    VkRenderPass m_renderPass;
    std::vector<VkFramebuffer> m_fbs;
    VkPipeline m_pipeline;
    VkPipelineLayout pipelineLayout;
    VkSwapchainKHR m_swapChainKHR;

    VkQueue presentQueue;
    VkCommandPool m_cmdBufPool;
    VkSemaphore imageAvailableSemaphore;
    VkSemaphore renderCompleteSemaphore;

    VkFence drawFence;
     std::vector<VkImage> m_images;
    VkShaderModule vertexShader = nullptr;
    VkShaderModule pixelShader = nullptr;
    std::vector<VkCommandBuffer> m_cmdBufs;
    VkImage depthImage;
    VkDeviceMemory depthMemory;
    VkImageView depthView;
    vector<const char*> deviceExtensionNames = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };

    std::vector<const char*> getRequiredExtensions() {
        uint32_t glfwExtensionCount = 0;
        const char** glfwExtensions;
        glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
        std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);

        if (enableValidationLayers) {
            extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
        }
        return extensions;
    }
    void init() {
        createInstance();
        createSurface();
        createPhysicalDevice();
        createLogicDevice();
        createSwapChain();
        createSyncObjects();
        createGraphicsPipeline();
        createImageViews();
        createFramebuffers();
        createCommandBuffers();
    }
    };

In defaultPipelineConfigInfo() you assign reference to local object at

configInfo.colorBlendInfo.pAttachments = &configInfo.colorBlendAttachment;

This does not survive the function call, so your pointer points to destroyed object, and so either the dereference would crash, or yield undefined value for the write masks.