Text rendering to a scene using Vulkan

Hi,
I am a newbie to Vulkan here. I am stuck with the text rendering for a couple of days now. Here is what I tried to do:

  1. I am using Vulkan on Qt. So the window was created using the QVulkanWindow class and its helper functions.
  2. I am trying to do it without using the Staging buffer.
// header file
#ifndef VCIRCLEFIT_H
#define VCIRCLEFIT_H
#include "C:/usascii/arial/stb_font_arial_24_usascii.inl"
//defines for STB font used
#define STB_FONT_NAME stb_font_arial_24_usascii
#define STB_FONT_WIDTH STB_FONT_arial_24_usascii_BITMAP_WIDTH
#define STB_FONT_HEIGHT STB_FONT_arial_24_usascii_BITMAP_HEIGHT
#define STB_FIRST_CHAR STB_FONT_arial_24_usascii_FIRST_CHAR
#define STB_NUM_CHARS STB_FONT_arial_24_usascii_NUM_CHARS
#define MAX_CHAR_COUNT 1024
class VCircleFit : public QVulkanWindow
{
public:
    VCircleFit(CircleFit *CF);
    QVulkanWindowRenderer* createRenderer() override;
};
class VulkanRenderer : public QVulkanWindowRenderer
{
public:
    VulkanRenderer(QVulkanWindow *w);

    void initResources() override;
    void startNextFrame() override;
   
    enum TextAlign { alignLeft, alignCenter, alignRight };
private:
 	
    VkShaderModule createShaderModule(const QString &name);
    void createShaders(std::vector<VkPipelineShaderStageCreateInfo> &shaderStages, int);
    void beginTextUpdate();
    void addText(std::string, float, float, TextAlign);
    void endTextUpdate();
    bool createTextureImage(VkImage&, VkDeviceMemory*, uint32_t);
    void createTextDescriptorSet();
    void createTextBuffer(unsigned char (&font6Pixels)[STB_FONT_HEIGHT][STB_FONT_WIDTH],VkDeviceMemory&, VkBuffer&, void* );
    void createTextPipeline(VkPipeline&, VkPipelineLayout&, VkPrimitiveTopology);
    void createTextLayout();
    void writeToImage();
    
	
    QVulkanWindow *m_window;
    QVulkanDeviceFunctions *m_devFuncs;
    QVulkanFunctions *m_Funcs;

    //buffer memory
    VkDeviceMemory m_TextBufMem =  VK_NULL_HANDLE;
    VkDeviceMemory m_TextureMem = VK_NULL_HANDLE;

   //buffers
    VkBuffer m_TextBuf = VK_NULL_HANDLE;

    //graphics pipeline
    VkPipeline m_pipeline10 = VK_NULL_HANDLE;

    //pipeline layout
    VkPipelineLayout m_TexturePipelineLayout=VK_NULL_HANDLE;

    VkPhysicalDeviceFeatures m_physicalDevFeatures = {};

    //void pointer memory
    void *p10;

    glm::vec4 *mappedLocal = nullptr;
    stb_fontchar stbFontData[STB_NUM_CHARS];
    uint32_t numLetters;
    VkImage m_TextureImage = VK_NULL_HANDLE;
    VkImageView m_TextureImgView=VK_NULL_HANDLE;
    VkSampler m_Sampler=VK_NULL_HANDLE;
    VkDescriptorPool m_TextureDescPool=VK_NULL_HANDLE;
    VkDescriptorSetLayout m_TextureDescSetLayout=VK_NULL_HANDLE;
    VkDescriptorSet m_TextureDescSet[QVulkanWindow::MAX_CONCURRENT_FRAME_COUNT];
    VkFormat m_texFormat;

};
#endif // VCIRCLEFIT_H
#include "VCircleFit.h"
#include <QVulkanFunctions>
#include <qvulkanfunctions.h>
static unsigned char font24pixels[STB_FONT_HEIGHT][STB_FONT_WIDTH];
VCircleFit::VCircleFit(CircleFit *CF)
{
    CircFit =CF;
}

QVulkanWindowRenderer* VCircleFit::createRenderer()
{
    return new VulkanRenderer(this);
}

VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
    : m_window(w)
{

}

void VulkanRenderer::initResources()
{
    //initiate device functions and vulkan function wrappers
    m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
    //selecting font

    STB_FONT_NAME(stbFontData, font24pixels, STB_FONT_HEIGHT);

  //  functions for text rendering
   createTextBuffer(font24pixels,m_TextBufMem,m_TextBuf,p10);
   createTextureImage(m_TextureImage,&m_TextureMem,m_window->hostVisibleMemoryIndex());
   createTextDescriptorSet();
   createTextLayout();
   beginTextUpdate();
   addText("mm",375,375,alignRight);
   endTextUpdate();

   createTextPipeline(m_pipeline10,m_TexturePipelineLayout,VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);

}

void VulkanRenderer::startNextFrame()
{
    VkDevice dev = m_window->device();
    VkCommandBuffer cb = m_window->currentCommandBuffer();
    VkClearColorValue clearColor = {{ 1.0f, 1.0, 1.0f, 1.0f }}; //white background
    VkClearDepthStencilValue clearDS = { 1.0f, 0 };
    VkClearValue clearValues[2];
    memset(clearValues, 0, sizeof(clearValues));
    clearValues[0].color = clearColor;
    clearValues[1].depthStencil = clearDS;

    VkRenderPassBeginInfo rpBeginInfo;
    memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
    rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    rpBeginInfo.renderPass = m_window->defaultRenderPass();
    rpBeginInfo.framebuffer = m_window->currentFramebuffer();
    const QSize sz = m_window->swapChainImageSize();
    rpBeginInfo.renderArea.extent.width = sz.width();
    rpBeginInfo.renderArea.extent.height = sz.height();
    rpBeginInfo.clearValueCount = 2;
    rpBeginInfo.pClearValues = clearValues;
    VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();

    //start a render pass
    m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
    //set viewport and scissor
    //viewport
    VkViewport viewport;
    viewport.x = 0; //x start coordinate
    viewport.y= -100; //y start coordinate
    viewport.width = sz.width(); // width of the viewport
    viewport.height = sz.height(); //height of the viewport
    viewport.minDepth = 0; //minimum depth of frame buffer
    viewport.maxDepth = 1; //max depth of frame buffer
    m_devFuncs->vkCmdSetViewport(cb, 0, 1, &viewport);

    //scissor
    VkRect2D scissor;
    scissor.offset.x = 0;
    scissor.offset.y= 0; //offset to use region from
    scissor.extent.width = viewport.width;//extent to use region from start from offset
    scissor.extent.height = viewport.height;
    m_devFuncs->vkCmdSetScissor(cb, 0, 1, &scissor);

    //draw commands
    //note :pipeline binding, vertex buffer binding and draw commands
    //needs to be grouped together

      m_devFuncs->vkCmdBindPipeline(cb,VK_PIPELINE_BIND_POINT_GRAPHICS,m_pipeline10);
      m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_TexturePipelineLayout, 0, 1, &m_TextureDescSet[m_window->currentFrame()], 0, nullptr);
      m_devFuncs->vkCmdBindVertexBuffers(cb,0,1,&m_TextBuf,&vbOffset);
      m_devFuncs->vkCmdBindVertexBuffers(cb,1,1,&m_TextBuf,&vbOffset);
      m_devFuncs->vkCmdDraw(cb,5, 1, 0, 0);

    m_devFuncs->vkCmdEndRenderPass(cmdBuf);

    m_window->frameReady();
    m_window->requestUpdate(); // render continuously, throttled by the presentation rate
}

void VulkanRenderer::createTextBuffer(unsigned char (&font6Pixels)[STB_FONT_HEIGHT][STB_FONT_WIDTH], VkDeviceMemory &m_bufMemory, VkBuffer &m_buffer, void *memory)
{
    VkBufferCreateInfo bufInfo;
    memset(&bufInfo,0,sizeof(bufInfo));
    bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    bufInfo.size = sizeof(glm::vec4)*MAX_CHAR_COUNT; //size of bufffer(size of 1 vertex*number of vertices)
    bufInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
    bufInfo.sharingMode =VK_SHARING_MODE_EXCLUSIVE;

    VkResult err = m_devFuncs->vkCreateBuffer(m_window->device(),&bufInfo,nullptr,&m_buffer);
 
    //memory requirements
    VkMemoryRequirements memReq;
    m_devFuncs->vkGetBufferMemoryRequirements(m_window->device(),m_buffer,&memReq);

    //memory allocation
    VkMemoryAllocateInfo memAllocInfo = {
      VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
        nullptr,
        memReq.size,
        m_window->hostVisibleMemoryIndex() //type of memory, allows host(cpu) to access memory
    };
    //allocating memory on gpu
    err = m_devFuncs->vkAllocateMemory(m_window->device(),&memAllocInfo,nullptr,&m_bufMemory);

    //binding memory with the vertex buffer
    err= m_devFuncs->vkBindBufferMemory(m_window->device(),m_buffer,m_bufMemory,0);
   
    //mapping of gpu memory to chosen point in Host memory
    err=m_devFuncs->vkMapMemory(m_window->device(),m_bufMemory,0,memReq.size,0,&memory);
		
    //copy text data to pointer address
   memcpy(memory,&font6Pixels[0][0],STB_FONT_WIDTH*STB_FONT_HEIGHT);
   m_devFuncs->vkUnmapMemory(m_window->device(),m_bufMemory);
}

void VulkanRenderer::createTextPipeline(VkPipeline &m_pipeline, VkPipelineLayout &m_pipelineLayout, VkPrimitiveTopology tp)
{
    std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
    createShaders(shaderStages,5);

    //how the data for a single vertex (including info such as pos,color,texture etc) is as a whole
    VkVertexInputBindingDescription vertexBindingDesc [] ={
        {
        0, //can bind multiple streams of data, this defines which one
        sizeof(glm::vec4), //size of a single vertex object
        VK_VERTEX_INPUT_RATE_VERTEX //how to move between data after each vertex
        },
        {
        1, //can bind multiple streams of data, this defines which one
        sizeof(glm::vec4), //size of a single vertex object
        VK_VERTEX_INPUT_RATE_VERTEX //how to move between data after each vertex
        }
    };

    VkVertexInputAttributeDescription vertexAttrDesc[] = {
            { // position attribute
                0, // which binding data is at
                0, // location in shader where data will be read from
                VK_FORMAT_R32G32_SFLOAT, //format the data will take
                0
            },
            {
               1,
               1,
               VK_FORMAT_R32G32_SFLOAT,
               sizeof(glm::vec2)
            }
        };
    //creating vertex input info
    VkPipelineVertexInputStateCreateInfo vertexInputInfo;
    vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    vertexInputInfo.pNext =nullptr;
    vertexInputInfo.flags = 0;
    vertexInputInfo.vertexBindingDescriptionCount=2;
    vertexInputInfo.pVertexBindingDescriptions=vertexBindingDesc; //list of vertex binding description(data spacing/stride information)
    vertexInputInfo.vertexAttributeDescriptionCount=2;
    vertexInputInfo.pVertexAttributeDescriptions = vertexAttrDesc; //list of vertex attribute description(data format and where to bind to/from)

    VkGraphicsPipelineCreateInfo pipelineInfo;
    memset(&pipelineInfo,0,sizeof(pipelineInfo));
    pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
    pipelineInfo.stageCount=2;
    pipelineInfo.pStages=shaderStages.data();
    pipelineInfo.pVertexInputState=&vertexInputInfo;

    //2nd step
    //pipeline input assembly
    VkPipelineInputAssemblyStateCreateInfo ia;
    memset(&ia,0,sizeof(ia));
    ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
    ia.topology = tp;
    pipelineInfo.pInputAssemblyState = &ia;

    //3rd step
    //define viewport to output to image
    VkPipelineViewportStateCreateInfo vp;
    memset(&vp,0,sizeof(vp));
    vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
    vp.viewportCount =1;
    vp.scissorCount =1;
    pipelineInfo.pViewportState =&vp;

    //4th step
    VkDynamicState dynEnable[]={VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
    VkPipelineDynamicStateCreateInfo dyn;
    memset(&dyn,0,sizeof(dyn));
    dyn.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
    dyn.dynamicStateCount = sizeof(dynEnable)/sizeof(VkDynamicState);
    dyn.pDynamicStates = dynEnable;
    pipelineInfo.pDynamicState =&dyn;

    //5th step
    VkPipelineRasterizationStateCreateInfo rs;
    memset(&rs, 0, sizeof(rs));
    rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
    rs.polygonMode = VK_POLYGON_MODE_LINE; //handle filling points between vertices
    rs.cullMode = VK_CULL_MODE_BACK_BIT; //which face of a shape to cull
    rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
    rs.lineWidth = 1.0;
    pipelineInfo.pRasterizationState = &rs;

    //enable blending
    VkPipelineColorBlendAttachmentState blendAttachmentState{};
    memset(&blendAttachmentState, 0, sizeof(blendAttachmentState));
    blendAttachmentState.blendEnable = VK_TRUE;
    blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
    blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
    blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
    blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
    blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
    blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
    blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;

    //6th step
    VkPipelineColorBlendStateCreateInfo cb;
    memset(&cb, 0, sizeof(cb));
    cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
    cb.attachmentCount = 1;
    cb.pAttachments = &blendAttachmentState;
    pipelineInfo.pColorBlendState = &cb;

    //7th step
    VkPipelineDepthStencilStateCreateInfo ds;
    memset(&ds, 0, sizeof(ds));
    ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
    ds.depthTestEnable = VK_TRUE;
    ds.depthWriteEnable = VK_TRUE;
    ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
    pipelineInfo.pDepthStencilState = &ds;

    //8th step
    //multi-sampling
    VkPipelineMultisampleStateCreateInfo ms;
    memset(&ms, 0, sizeof(ms));
    ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
    ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
    pipelineInfo.pMultisampleState = &ms;


    //9th step
    pipelineInfo.layout = m_pipelineLayout;

    //9th step
    //define renderpass
    pipelineInfo.renderPass = m_window->defaultRenderPass();

    VkResult err = m_devFuncs->vkCreateGraphicsPipelines(m_window->device(),nullptr,1,&pipelineInfo,nullptr,&m_pipeline);
}

void VulkanRenderer::createTextLayout()
{
    VkPipelineLayoutCreateInfo pipelineLayoutInfo;
    memset(&pipelineLayoutInfo,0,sizeof(pipelineLayoutInfo));
    pipelineLayoutInfo.sType =  VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    pipelineLayoutInfo.setLayoutCount =1;
    pipelineLayoutInfo.pSetLayouts=&m_TextureDescSetLayout;
    pipelineLayoutInfo.pushConstantRangeCount=0;
    pipelineLayoutInfo.pPushConstantRanges=nullptr;
    VkResult err = m_devFuncs->vkCreatePipelineLayout(m_window->device(),&pipelineLayoutInfo,nullptr,&m_TexturePipelineLayout);
}

void VulkanRenderer::writeToImage()
{
    VkImageSubresource subres = {
           VK_IMAGE_ASPECT_COLOR_BIT,
           0, // mip level
           0
       };
    VkSubresourceLayout layout;
    m_devFuncs->vkGetImageSubresourceLayout(m_window->device(), m_TextureImage, &subres, &layout);
    uchar *p;
    VkResult err = m_devFuncs->vkMapMemory(m_window->device(), m_TextureMem, layout.offset, layout.size, 0, reinterpret_cast<void **>(&p));
    for (int y = 0; y < STB_FONT_HEIGHT; ++y) {
            const uchar *line = font24pixels[y];
            memcpy(p, line, STB_FONT_WIDTH * 4);
            p += layout.rowPitch;
        }
    m_devFuncs->vkUnmapMemory(m_window->device(), m_TextureMem);
}

void VulkanRenderer::beginTextUpdate()
{
  m_devFuncs->vkMapMemory(m_window->device(),m_TextBufMem,0,VK_WHOLE_SIZE,0,(void**)&mappedLocal);
  numLetters=0;
}

void VulkanRenderer::addText(std::string text, float x, float y, TextAlign align)
{
    const uint32_t firstChar = STB_FONT_arial_24_usascii_FIRST_CHAR;
    const float charW = 1.5f/750 ;
    const float charH = 1.5f/750.0;

    float fbW = (float)750.0;
    float fbH = (float)750.0;
     x = (x / fbW * 2.0f) - 1.0f;
     y = (y / fbH * 2.0f) - 1.0f;
     // Calculate text width
     float textWidth = 0;
     for (auto letter : text)
      {
                stb_fontchar *charData = &stbFontData[(uint32_t)letter - firstChar];
                textWidth += charData->advance * charW;
     }

    switch (align)
    {
        case alignRight:
            x -= textWidth;
            break;
        case alignCenter:
            x -= textWidth / 2.0f;
            break;
    }
    // Generate a uv mapped quad per char in the new text
    for (auto letter : text)
    {
        stb_fontchar *charData = &stbFontData[(uint32_t)letter - firstChar];

         mappedLocal->x = (x + (float)charData->x0 * charW);
         mappedLocal->y = (y + (float)charData->y0 * charH);
        mappedLocal->z = charData->s0;
        qDebug() << mappedLocal->x;
        mappedLocal->w = charData->t0;
        mappedLocal++;

        mappedLocal->x = (x + (float)charData->x1 * charW);
        mappedLocal->y = (y + (float)charData->y0 * charH);
        mappedLocal->z = charData->s1;
        mappedLocal->w = charData->t0;
        mappedLocal++;


        mappedLocal->x = (x + (float)charData->x0 * charW);
        mappedLocal->y = (y + (float)charData->y1 * charH);
        mappedLocal->z = charData->s0;
        mappedLocal->w = charData->t1;
        mappedLocal++;


        mappedLocal->x = (x + (float)charData->x1 * charW);
        mappedLocal->y = (y + (float)charData->y1 * charH);
        mappedLocal->z = charData->s1;
        mappedLocal->w = charData->t1;
        mappedLocal++;

        mappedLocal->x = (x + (float)charData->x1 * charW);
        mappedLocal->y = (y + (float)charData->y0 * charH);
        mappedLocal->z = charData->s0;
        mappedLocal->w = charData->t0;
        mappedLocal++;

        x += charData->advance * charW;

        numLetters++;
    }
}

bool VulkanRenderer::createTextureImage(VkImage& image, VkDeviceMemory *mem, uint32_t memIndex)
{
    const bool srgb = QCoreApplication::arguments().contains(QStringLiteral("--srgb"));
    m_texFormat = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
    VkImageCreateInfo imageInfo;
    memset(&imageInfo, 0, sizeof(imageInfo));
    imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
    imageInfo.imageType = VK_IMAGE_TYPE_2D;
    imageInfo.format =  m_texFormat;
    imageInfo.extent.width = STB_FONT_WIDTH;
    imageInfo.extent.height=STB_FONT_HEIGHT;
    imageInfo.extent.depth = 1;
    imageInfo.mipLevels = 1;
    imageInfo.arrayLayers = 1;
    imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
    imageInfo.tiling =  VK_IMAGE_TILING_LINEAR;
    imageInfo.usage =  VK_IMAGE_USAGE_SAMPLED_BIT;
    imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;

    VkResult err= m_devFuncs->vkCreateImage(m_window->device(), &imageInfo, nullptr, &image);
    if(err!=VK_SUCCESS)
    {
        qWarning("Failed to create image");
        return false;
    }
    VkMemoryRequirements memReq;
    m_devFuncs->vkGetImageMemoryRequirements(m_window->device(), image, &memReq);

    if (!(memReq.memoryTypeBits & (1 << memIndex))) {
        VkPhysicalDeviceMemoryProperties physDevMemProps;
        m_window->vulkanInstance()->functions()->vkGetPhysicalDeviceMemoryProperties(m_window->physicalDevice(), &physDevMemProps);
        for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
            if (!(memReq.memoryTypeBits & (1 << i)))
                continue;
            memIndex = i;
        }
    }
    VkMemoryAllocateInfo allocInfo;
    allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    allocInfo.pNext =nullptr;
    allocInfo.allocationSize = memReq.size;
    allocInfo.memoryTypeIndex=memIndex;

    err = m_devFuncs->vkAllocateMemory(m_window->device(),&allocInfo, nullptr, mem);
    if (err != VK_SUCCESS) {
        qWarning("Failed to allocate memory for linear image: %d", err);
        return false;
    }
    err = m_devFuncs->vkBindImageMemory(m_window->device(), image, *mem, 0);
    if (err != VK_SUCCESS) {
        qWarning("Failed to bind linear image memory: %d", err);
        return false;
    }
    return true;
}

void VulkanRenderer::createTextDescriptorSet()
{
    writeToImage();
    VkImageViewCreateInfo imageViewInfo;
    memset(&imageViewInfo, 0, sizeof(imageViewInfo));
    imageViewInfo.sType=VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
    imageViewInfo.pNext=nullptr;
    imageViewInfo.viewType= VK_IMAGE_VIEW_TYPE_2D;
    imageViewInfo.image=m_TextureImage;
    imageViewInfo.format=m_texFormat;
    imageViewInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,	VK_COMPONENT_SWIZZLE_A };
    imageViewInfo.subresourceRange={ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };

    VkResult err=m_devFuncs->vkCreateImageView(m_window->device(),&imageViewInfo,nullptr,&m_TextureImgView);

    // Sampler.
   VkSamplerCreateInfo samplerInfo;
   memset(&samplerInfo, 0, sizeof(samplerInfo));
   samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
   samplerInfo.magFilter = VK_FILTER_NEAREST;
   samplerInfo.minFilter = VK_FILTER_NEAREST;
   samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
   samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
   samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
   err = m_devFuncs->vkCreateSampler(m_window->device(), &samplerInfo, nullptr, &m_Sampler);

   // Set up descriptor set and its layout.
   VkDescriptorPoolSize descPoolSizes[1] = {
           { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, uint32_t(m_window->concurrentFrameCount()) }
       };

   VkDescriptorPoolCreateInfo descPoolInfo;
   memset(&descPoolInfo, 0, sizeof(descPoolInfo));
   descPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
   descPoolInfo.maxSets = m_window->concurrentFrameCount();
   descPoolInfo.poolSizeCount = 1;
   descPoolInfo.pPoolSizes = descPoolSizes;
   err = m_devFuncs->vkCreateDescriptorPool(m_window->device(), &descPoolInfo, nullptr, &m_TextureDescPool);
   if (err != VK_SUCCESS)
       qFatal("Failed to create descriptor pool: %d", err);

   VkDescriptorSetLayoutBinding layoutBinding[1] =
      {
          {
              0, // binding
              VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
              1, // descriptorCount
              VK_SHADER_STAGE_FRAGMENT_BIT,
              nullptr
          }
      };
   VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = {
           VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
           nullptr,
           0,
           1, // bindingCount
           layoutBinding
       };
   err=m_devFuncs->vkCreateDescriptorSetLayout(m_window->device(),&descriptorSetLayoutInfo,nullptr,&m_TextureDescSetLayout);

   if(err!=VK_SUCCESS)
       qCritical("Failed to create descriptor set layout: %d", err);

   for (int i = 0; i < m_window->concurrentFrameCount(); ++i) {
           VkDescriptorSetAllocateInfo descSetAllocInfo = {
               VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
               nullptr,
               m_TextureDescPool,
               1,
               &m_TextureDescSetLayout
           };
           err = m_devFuncs->vkAllocateDescriptorSets(m_window->device(), &descSetAllocInfo, &m_TextureDescSet[i]);
           if (err != VK_SUCCESS)
               qFatal("Failed to allocate descriptor set: %d", err);

           VkWriteDescriptorSet descWrite[1];
           memset(descWrite, 0, sizeof(descWrite));
           VkDescriptorImageInfo descImageInfo = {
               m_Sampler,
               m_TextureImgView,
               VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
           };

           descWrite[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
           descWrite[0].dstSet = m_TextureDescSet[i];
           descWrite[0].dstBinding = 0;
           descWrite[0].descriptorCount = 1;
           descWrite[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
           descWrite[0].pImageInfo = &descImageInfo;

           m_devFuncs->vkUpdateDescriptorSets(m_window->device(), 1, descWrite, 0, nullptr);
       }

}

VkShaderModule VulkanRenderer::createShaderModule(const QString &name)
{
    QFile file(name);
    if (!file.open(QIODevice::ReadOnly)) {
         qWarning("Failed to read shader %s", qPrintable(name));
         return VK_NULL_HANDLE;
    }
    QByteArray blob = file.readAll();
    file.close();

    VkShaderModuleCreateInfo shaderInfo;
    memset(&shaderInfo, 0, sizeof(shaderInfo));
    shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
    shaderInfo.codeSize = blob.size();
    shaderInfo.pCode = reinterpret_cast<const uint32_t *>(blob.constData());
    VkShaderModule shaderModule;
    VkResult err = m_devFuncs->vkCreateShaderModule(m_window->device(), &shaderInfo, nullptr, &shaderModule);
    
    return shaderModule;
}

void VulkanRenderer::createShaders(std::vector<VkPipelineShaderStageCreateInfo> &shaderStages, int t)
{
    //get the shader modules
     VkShaderModule vertShaderModule = VK_NULL_HANDLE;
     VkShaderModule fragShaderModule= VK_NULL_HANDLE;

    vertShaderModule = createShaderModule(QStringLiteral(":/Shaders/vert6.spv"));
    fragShaderModule = createShaderModule(QStringLiteral(":/Shaders/frag6.spv"));
    
    //vertex shader create info
    VkPipelineShaderStageCreateInfo vertexShaderCreateInfo= {};
    memset(&vertexShaderCreateInfo,0,sizeof(vertexShaderCreateInfo));
    vertexShaderCreateInfo.sType = 
  VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    vertexShaderCreateInfo.stage= VK_SHADER_STAGE_VERTEX_BIT;
    vertexShaderCreateInfo.module = vertShaderModule;
    vertexShaderCreateInfo.pName ="main";

    //fragment shader create info
    VkPipelineShaderStageCreateInfo fragmentShaderCreateInfo= {};
    memset(&fragmentShaderCreateInfo,0,sizeof(fragmentShaderCreateInfo));
    fragmentShaderCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
    fragmentShaderCreateInfo.stage= VK_SHADER_STAGE_FRAGMENT_BIT;
    fragmentShaderCreateInfo.module = fragShaderModule;
    fragmentShaderCreateInfo.pName ="main";

    shaderStages.push_back(vertexShaderCreateInfo);
    shaderStages.push_back(fragmentShaderCreateInfo);
}

My code is running despite this validation error: command buffer VkCommandBuffer 0x275d8f8eea0[] expects VkImage 0xcb1c7c000000001b[] (subresource: aspectMask 0x1 array layer 0, mip level 0) to be in layout VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL–instead, current layout is VK_IMAGE_LAYOUT_PREINITIALIZED.

here is the output:


You can see the texture rectangle (marked yellow on the image) but I am not seeing any text/char onto the screen. Posting with a really frustrated mind here. Thank you!