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:
- I am using Vulkan on Qt. So the window was created using the QVulkanWindow class and its helper functions.
- 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!