Milestone reached: Main loop is working, but no UI is in place, that's the next goal

This commit is contained in:
ThatTanishqTak 2025-11-17 23:56:39 +00:00
parent 7f8a1128e3
commit 24d64f196f
2 changed files with 347 additions and 9 deletions

View file

@ -17,7 +17,8 @@
#include <vector> #include <vector>
#define CLAY_IMPLEMENTATION #define CLAY_IMPLEMENTATION
extern "C" { extern "C"
{
#include "../../clay.h" #include "../../clay.h"
#include "../../renderers/vulkan/clay_renderer_vulkan.c" #include "../../renderers/vulkan/clay_renderer_vulkan.c"
} }
@ -87,6 +88,12 @@ private:
VkSemaphore m_ImageAvailableSemaphore = VK_NULL_HANDLE; VkSemaphore m_ImageAvailableSemaphore = VK_NULL_HANDLE;
VkSemaphore m_RenderFinishedSemaphore = VK_NULL_HANDLE; VkSemaphore m_RenderFinishedSemaphore = VK_NULL_HANDLE;
VkFence m_InFlightFence = VK_NULL_HANDLE; VkFence m_InFlightFence = VK_NULL_HANDLE;
VkDescriptorSetLayout m_DescriptorSetLayout = VK_NULL_HANDLE;
VkPipelineLayout m_PipelineLayout = VK_NULL_HANDLE;
VkPipeline m_RectPipeline = VK_NULL_HANDLE;
VkPipeline m_TextPipeline = VK_NULL_HANDLE;
VkPipeline m_ImagePipeline = VK_NULL_HANDLE;
VkDescriptorPool m_DescriptorPool = VK_NULL_HANDLE;
// Clay renderer bindings // Clay renderer bindings
ClayVulkanRenderer m_ClayRenderer{}; ClayVulkanRenderer m_ClayRenderer{};
@ -116,6 +123,9 @@ private:
CreateSwapchain(); CreateSwapchain();
CreateImageViews(); CreateImageViews();
CreateRenderPass(); CreateRenderPass();
CreateDescriptorSetLayout();
CreatePipelineLayout();
CreatePipelines();
CreateFramebuffers(); CreateFramebuffers();
CreateCommandPool(); CreateCommandPool();
AllocateCommandBuffers(); AllocateCommandBuffers();
@ -134,9 +144,9 @@ private:
Clay_Initialize(m_ClayArena, l_LayoutDimensions, Clay_ErrorHandler{ 0 }); Clay_Initialize(m_ClayArena, l_LayoutDimensions, Clay_ErrorHandler{ 0 });
Clay_VulkanRenderer_Init(&m_ClayRenderer, m_Device, m_RenderPass, VK_NULL_HANDLE); Clay_VulkanRenderer_Init(&m_ClayRenderer, m_Device, m_RenderPass, m_PipelineLayout);
Clay_VulkanRenderer_SetPipelines(&m_ClayRenderer, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE); Clay_VulkanRenderer_SetPipelines(&m_ClayRenderer, m_RectPipeline, m_TextPipeline, m_ImagePipeline);
// TODO: Plug descriptor pool + layout management for textures/fonts instead of placeholder pipeline handles. // Descriptor pool and layouts have been created; future improvements can allocate texture/font descriptors per frame.
Clay_VulkanRenderer_RegisterTextMeasure(&m_ClayRenderer); Clay_VulkanRenderer_RegisterTextMeasure(&m_ClayRenderer);
} }
@ -172,6 +182,31 @@ private:
vkDestroySemaphore(m_Device, m_RenderFinishedSemaphore, nullptr); vkDestroySemaphore(m_Device, m_RenderFinishedSemaphore, nullptr);
vkDestroySemaphore(m_Device, m_ImageAvailableSemaphore, nullptr); vkDestroySemaphore(m_Device, m_ImageAvailableSemaphore, nullptr);
if (m_RectPipeline != VK_NULL_HANDLE)
{
vkDestroyPipeline(m_Device, m_RectPipeline, nullptr);
}
if (m_TextPipeline != VK_NULL_HANDLE)
{
vkDestroyPipeline(m_Device, m_TextPipeline, nullptr);
}
if (m_ImagePipeline != VK_NULL_HANDLE)
{
vkDestroyPipeline(m_Device, m_ImagePipeline, nullptr);
}
if (m_PipelineLayout != VK_NULL_HANDLE)
{
vkDestroyPipelineLayout(m_Device, m_PipelineLayout, nullptr);
}
if (m_DescriptorSetLayout != VK_NULL_HANDLE)
{
vkDestroyDescriptorSetLayout(m_Device, m_DescriptorSetLayout, nullptr);
}
if (m_DescriptorPool != VK_NULL_HANDLE)
{
vkDestroyDescriptorPool(m_Device, m_DescriptorPool, nullptr);
}
for (VkFramebuffer l_Framebuffer : m_SwapchainFramebuffers) for (VkFramebuffer l_Framebuffer : m_SwapchainFramebuffers)
{ {
vkDestroyFramebuffer(m_Device, l_Framebuffer, nullptr); vkDestroyFramebuffer(m_Device, l_Framebuffer, nullptr);
@ -220,6 +255,291 @@ private:
} }
} }
VkShaderModule CreateShaderModule(const std::vector<uint32_t>& code)
{
VkShaderModuleCreateInfo l_CreateInfo{};
l_CreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
l_CreateInfo.codeSize = code.size() * sizeof(uint32_t);
l_CreateInfo.pCode = code.data();
VkShaderModule l_ShaderModule = VK_NULL_HANDLE;
if (vkCreateShaderModule(m_Device, &l_CreateInfo, nullptr, &l_ShaderModule) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create shader module; see Vulkan SDK validation output.");
}
return l_ShaderModule;
}
void CreateDescriptorSetLayout()
{
// Texture sampling uses a single combined image sampler bound at set 0, binding 0.
VkDescriptorSetLayoutBinding l_SamplerBinding{};
l_SamplerBinding.binding = 0;
l_SamplerBinding.descriptorCount = 1;
l_SamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
l_SamplerBinding.pImmutableSamplers = nullptr;
l_SamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo l_LayoutInfo{};
l_LayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
l_LayoutInfo.bindingCount = 1;
l_LayoutInfo.pBindings = &l_SamplerBinding;
if (vkCreateDescriptorSetLayout(m_Device, &l_LayoutInfo, nullptr, &m_DescriptorSetLayout) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create descriptor set layout for images");
}
// Keep a small descriptor pool ready for sample textures; real integrations should grow this pool.
VkDescriptorPoolSize l_PoolSize{};
l_PoolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
l_PoolSize.descriptorCount = 8;
VkDescriptorPoolCreateInfo l_PoolInfo{};
l_PoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
l_PoolInfo.poolSizeCount = 1;
l_PoolInfo.pPoolSizes = &l_PoolSize;
l_PoolInfo.maxSets = 8;
if (vkCreateDescriptorPool(m_Device, &l_PoolInfo, nullptr, &m_DescriptorPool) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create descriptor pool for textures");
}
}
void CreatePipelineLayout()
{
VkPipelineLayoutCreateInfo l_PipelineLayoutInfo{};
l_PipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
l_PipelineLayoutInfo.setLayoutCount = 1;
l_PipelineLayoutInfo.pSetLayouts = &m_DescriptorSetLayout;
if (vkCreatePipelineLayout(m_Device, &l_PipelineLayoutInfo, nullptr, &m_PipelineLayout) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create pipeline layout");
}
}
void CreatePipelines()
{
// Embedded SPIR-V shaders keep the demo self contained; see Vulkan SDK docs for shader compilation guidance.
static const std::array<uint32_t, 346> s_RectVertSpv = {
0x7230203,0x10000,0x8000b,0x32,0x0,0x20011,0x1,0x6000b,
0x1,0x4c534c47,0x6474732e,0x3035342e,0x0,0x3000e,0x0,0x1,
0x8000f,0x0,0x4,0x6e69616d,0x0,0xd,0x1b,0x29,
0x30003,0x2,0x1c2,0x40005,0x4,0x6e69616d,0x0,0x60005,
0xb,0x505f6c67,0x65567265,0x78657472,0x0,0x60006,0xb,0x0,
0x505f6c67,0x7469736f,0x6e6f69,0x70006,0xb,0x1,0x505f6c67,0x746e696f,
0x657a6953,0x0,0x70006,0xb,0x2,0x435f6c67,0x4470696c,0x61747369,
0x65636e,0x70006,0xb,0x3,0x435f6c67,0x446c6c75,0x61747369,0x65636e,
0x30005,0xd,0x0,0x60005,0x1b,0x565f6c67,0x65747265,0x646e4978,
0x7865,0x50005,0x1e,0x65646e69,0x6c626178,0x65,0x40005,0x29,
0x5574756f,0x56,0x50005,0x2f,0x65646e69,0x6c626178,0x65,0x30047,
0xb,0x2,0x50048,0xb,0x0,0xb,0x0,0x50048,
0xb,0x1,0xb,0x1,0x50048,0xb,0x2,0xb,
0x3,0x50048,0xb,0x3,0xb,0x4,0x40047,0x1b,
0xb,0x2a,0x40047,0x29,0x1e,0x0,0x20013,0x2,
0x30021,0x3,0x2,0x30016,0x6,0x20,0x40017,0x7,
0x6,0x4,0x40015,0x8,0x20,0x0,0x4002b,0x8,
0x9,0x1,0x4001c,0xa,0x6,0x9,0x6001e,0xb,
0x7,0x6,0xa,0xa,0x40020,0xc,0x3,0xb,
0x4003b,0xc,0xd,0x3,0x40015,0xe,0x20,0x1,
0x4002b,0xe,0xf,0x0,0x40017,0x10,0x6,0x2,
0x4002b,0x8,0x11,0x6,0x4001c,0x12,0x10,0x11,
0x4002b,0x6,0x13,0xbf800000,0x5002c,0x10,0x14,0x13,
0x13,0x4002b,0x6,0x15,0x3f800000,0x5002c,0x10,0x16,
0x15,0x13,0x5002c,0x10,0x17,0x15,0x15,0x5002c,
0x10,0x18,0x13,0x15,0x9002c,0x12,0x19,0x14,
0x16,0x17,0x14,0x17,0x18,0x40020,0x1a,0x1,
0xe,0x4003b,0x1a,0x1b,0x1,0x40020,0x1d,0x7,
0x12,0x40020,0x1f,0x7,0x10,0x4002b,0x6,0x22,
0x0,0x40020,0x26,0x3,0x7,0x40020,0x28,0x3,
0x10,0x4003b,0x28,0x29,0x3,0x5002c,0x10,0x2a,
0x22,0x22,0x5002c,0x10,0x2b,0x15,0x22,0x5002c,
0x10,0x2c,0x22,0x15,0x9002c,0x12,0x2d,0x2a,
0x2b,0x17,0x2a,0x17,0x2c,0x50036,0x2,0x4,
0x0,0x3,0x200f8,0x5,0x4003b,0x1d,0x1e,0x7,
0x4003b,0x1d,0x2f,0x7,0x4003d,0xe,0x1c,0x1b,
0x3003e,0x1e,0x19,0x50041,0x1f,0x20,0x1e,0x1c,
0x4003d,0x10,0x21,0x20,0x50051,0x6,0x23,0x21,
0x0,0x50051,0x6,0x24,0x21,0x1,0x70050,0x7,
0x25,0x23,0x24,0x22,0x15,0x50041,0x26,0x27,
0xd,0xf,0x3003e,0x27,0x25,0x4003d,0xe,0x2e,
0x1b,0x3003e,0x2f,0x2d,0x50041,0x1f,0x30,0x2f,
0x2e,0x4003d,0x10,0x31,0x30,0x3003e,0x29,0x31,
0x100fd,0x10038,
};
static const std::array<uint32_t, 123> s_ColorFragSpv = {
0x7230203,0x10000,0x8000b,0x13,0x0,0x20011,0x1,0x6000b,
0x1,0x4c534c47,0x6474732e,0x3035342e,0x0,0x3000e,0x0,0x1,
0x7000f,0x4,0x4,0x6e69616d,0x0,0x9,0xc,0x30010,
0x4,0x7,0x30003,0x2,0x1c2,0x40005,0x4,0x6e69616d,
0x0,0x50005,0x9,0x4374756f,0x726f6c6f,0x0,0x40005,0xc,
0x56556e69,0x0,0x40047,0x9,0x1e,0x0,0x40047,0xc,
0x1e,0x0,0x20013,0x2,0x30021,0x3,0x2,0x30016,
0x6,0x20,0x40017,0x7,0x6,0x4,0x40020,0x8,
0x3,0x7,0x4003b,0x8,0x9,0x3,0x40017,0xa,
0x6,0x2,0x40020,0xb,0x1,0xa,0x4003b,0xb,
0xc,0x1,0x4002b,0x6,0xe,0x3f000000,0x4002b,0x6,
0xf,0x3f800000,0x50036,0x2,0x4,0x0,0x3,0x200f8,
0x5,0x4003d,0xa,0xd,0xc,0x50051,0x6,0x10,
0xd,0x0,0x50051,0x6,0x11,0xd,0x1,0x70050,
0x7,0x12,0x10,0x11,0xe,0xf,0x3003e,0x9,
0x12,0x100fd,0x10038,
};
static const std::array<uint32_t, 140> s_ImageFragSpv = {
0x7230203,0x10000,0x8000b,0x14,0x0,0x20011,0x1,0x6000b,
0x1,0x4c534c47,0x6474732e,0x3035342e,0x0,0x3000e,0x0,0x1,
0x7000f,0x4,0x4,0x6e69616d,0x0,0x9,0x11,0x30010,
0x4,0x7,0x30003,0x2,0x1c2,0x40005,0x4,0x6e69616d,
0x0,0x50005,0x9,0x4374756f,0x726f6c6f,0x0,0x50005,0xd,
0x78655475,0x65727574,0x0,0x40005,0x11,0x56556e69,0x0,0x40047,
0x9,0x1e,0x0,0x40047,0xd,0x21,0x0,0x40047,
0xd,0x22,0x0,0x40047,0x11,0x1e,0x0,0x20013,
0x2,0x30021,0x3,0x2,0x30016,0x6,0x20,0x40017,
0x7,0x6,0x4,0x40020,0x8,0x3,0x7,0x4003b,
0x8,0x9,0x3,0x90019,0xa,0x6,0x1,0x0,
0x0,0x0,0x1,0x0,0x3001b,0xb,0xa,0x40020,
0xc,0x0,0xb,0x4003b,0xc,0xd,0x0,0x40017,
0xf,0x6,0x2,0x40020,0x10,0x1,0xf,0x4003b,
0x10,0x11,0x1,0x50036,0x2,0x4,0x0,0x3,
0x200f8,0x5,0x4003d,0xb,0xe,0xd,0x4003d,0xf,
0x12,0x11,0x50057,0x7,0x13,0xe,0x12,0x3003e,
0x9,0x13,0x100fd,0x10038,
};
const std::vector<uint32_t> l_VertCode(s_RectVertSpv.begin(), s_RectVertSpv.end());
const std::vector<uint32_t> l_ColorFragCode(s_ColorFragSpv.begin(), s_ColorFragSpv.end());
const std::vector<uint32_t> l_ImageFragCode(s_ImageFragSpv.begin(), s_ImageFragSpv.end());
VkShaderModule l_VertShaderModule = CreateShaderModule(l_VertCode);
VkShaderModule l_ColorFragShaderModule = CreateShaderModule(l_ColorFragCode);
VkShaderModule l_ImageFragShaderModule = CreateShaderModule(l_ImageFragCode);
VkPipelineShaderStageCreateInfo l_VertStageInfo{};
l_VertStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
l_VertStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
l_VertStageInfo.module = l_VertShaderModule;
l_VertStageInfo.pName = "main";
VkPipelineShaderStageCreateInfo l_ColorFragStage{};
l_ColorFragStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
l_ColorFragStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
l_ColorFragStage.module = l_ColorFragShaderModule;
l_ColorFragStage.pName = "main";
VkPipelineShaderStageCreateInfo l_ImageFragStage{};
l_ImageFragStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
l_ImageFragStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
l_ImageFragStage.module = l_ImageFragShaderModule;
l_ImageFragStage.pName = "main";
VkPipelineShaderStageCreateInfo l_ColorStages[] = { l_VertStageInfo, l_ColorFragStage };
VkPipelineShaderStageCreateInfo l_ImageStages[] = { l_VertStageInfo, l_ImageFragStage };
VkPipelineVertexInputStateCreateInfo l_VertexInputInfo{};
l_VertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
VkPipelineInputAssemblyStateCreateInfo l_InputAssembly{};
l_InputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
l_InputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
l_InputAssembly.primitiveRestartEnable = VK_FALSE;
VkViewport l_Viewport{};
l_Viewport.x = 0.0f;
l_Viewport.y = 0.0f;
l_Viewport.width = static_cast<float>(m_SwapchainExtent.width);
l_Viewport.height = static_cast<float>(m_SwapchainExtent.height);
l_Viewport.minDepth = 0.0f;
l_Viewport.maxDepth = 1.0f;
VkRect2D l_Scissor{};
l_Scissor.offset = { 0, 0 };
l_Scissor.extent = m_SwapchainExtent;
VkPipelineViewportStateCreateInfo l_ViewportState{};
l_ViewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
l_ViewportState.viewportCount = 1;
l_ViewportState.pViewports = &l_Viewport;
l_ViewportState.scissorCount = 1;
l_ViewportState.pScissors = &l_Scissor;
VkPipelineRasterizationStateCreateInfo l_Rasterizer{};
l_Rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
l_Rasterizer.depthClampEnable = VK_FALSE;
l_Rasterizer.rasterizerDiscardEnable = VK_FALSE;
l_Rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
l_Rasterizer.lineWidth = 1.0f;
l_Rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
l_Rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
l_Rasterizer.depthBiasEnable = VK_FALSE;
VkPipelineMultisampleStateCreateInfo l_Multisampling{};
l_Multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
l_Multisampling.sampleShadingEnable = VK_FALSE;
l_Multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState l_ColorBlendAttachment{};
l_ColorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
l_ColorBlendAttachment.blendEnable = VK_TRUE;
l_ColorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
l_ColorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
l_ColorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
l_ColorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
l_ColorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
l_ColorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo l_ColorBlending{};
l_ColorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
l_ColorBlending.logicOpEnable = VK_FALSE;
l_ColorBlending.attachmentCount = 1;
l_ColorBlending.pAttachments = &l_ColorBlendAttachment;
std::vector<VkDynamicState> l_DynamicStates = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT };
VkPipelineDynamicStateCreateInfo l_DynamicState{};
l_DynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
l_DynamicState.dynamicStateCount = static_cast<uint32_t>(l_DynamicStates.size());
l_DynamicState.pDynamicStates = l_DynamicStates.data();
VkGraphicsPipelineCreateInfo l_PipelineInfo{};
l_PipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
l_PipelineInfo.pVertexInputState = &l_VertexInputInfo;
l_PipelineInfo.pInputAssemblyState = &l_InputAssembly;
l_PipelineInfo.pViewportState = &l_ViewportState;
l_PipelineInfo.pRasterizationState = &l_Rasterizer;
l_PipelineInfo.pMultisampleState = &l_Multisampling;
l_PipelineInfo.pColorBlendState = &l_ColorBlending;
l_PipelineInfo.pDynamicState = &l_DynamicState;
l_PipelineInfo.layout = m_PipelineLayout;
l_PipelineInfo.renderPass = m_RenderPass;
l_PipelineInfo.subpass = 0;
l_PipelineInfo.stageCount = 2;
l_PipelineInfo.pStages = l_ColorStages;
if (vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, &l_PipelineInfo, nullptr, &m_RectPipeline) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create rectangle pipeline");
}
l_PipelineInfo.pStages = l_ImageStages;
if (vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, &l_PipelineInfo, nullptr, &m_ImagePipeline) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create image pipeline");
}
// Text rendering can reuse the color fragment shader for now; future work can swap in a signed-distance-field shader.
l_PipelineInfo.pStages = l_ColorStages;
if (vkCreateGraphicsPipelines(m_Device, VK_NULL_HANDLE, 1, &l_PipelineInfo, nullptr, &m_TextPipeline) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create text pipeline");
}
vkDestroyShaderModule(m_Device, l_VertShaderModule, nullptr);
vkDestroyShaderModule(m_Device, l_ColorFragShaderModule, nullptr);
vkDestroyShaderModule(m_Device, l_ImageFragShaderModule, nullptr);
}
void CreateSurface() void CreateSurface()
{ {
if (glfwCreateWindowSurface(m_Instance, m_Window, nullptr, &m_Surface) != VK_SUCCESS) if (glfwCreateWindowSurface(m_Instance, m_Window, nullptr, &m_Surface) != VK_SUCCESS)
@ -546,9 +866,25 @@ private:
l_RenderPassInfo.clearValueCount = 1; l_RenderPassInfo.clearValueCount = 1;
l_RenderPassInfo.pClearValues = &l_ClearColor; l_RenderPassInfo.pClearValues = &l_ClearColor;
VkViewport l_Viewport{};
l_Viewport.x = 0.0f;
l_Viewport.y = 0.0f;
l_Viewport.width = static_cast<float>(m_SwapchainExtent.width);
l_Viewport.height = static_cast<float>(m_SwapchainExtent.height);
l_Viewport.minDepth = 0.0f;
l_Viewport.maxDepth = 1.0f;
VkRect2D l_Scissor{};
l_Scissor.offset = { 0, 0 };
l_Scissor.extent = m_SwapchainExtent;
vkCmdBeginRenderPass(commandBuffer, &l_RenderPassInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(commandBuffer, &l_RenderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
// Clay renderer translates render commands into Vulkan draw calls. Pipelines are left as TODOs. // Set dynamic state expected by the pipelines before Clay emits draw calls.
vkCmdSetViewport(commandBuffer, 0, 1, &l_Viewport);
vkCmdSetScissor(commandBuffer, 0, 1, &l_Scissor);
// Clay renderer translates render commands into Vulkan draw calls using the pipelines prepared during initialization.
Clay_Vulkan_Render(&m_ClayRenderer, renderCommands, commandBuffer); Clay_Vulkan_Render(&m_ClayRenderer, renderCommands, commandBuffer);
vkCmdEndRenderPass(commandBuffer); vkCmdEndRenderPass(commandBuffer);

View file

@ -179,8 +179,10 @@ static void ClayVulkan_DrawBorder(ClayVulkanRenderer* renderer, const Clay_Rende
static void ClayVulkan_DrawImage(ClayVulkanRenderer* renderer, const Clay_RenderCommand* command, VkCommandBuffer commandBuffer) static void ClayVulkan_DrawImage(ClayVulkanRenderer* renderer, const Clay_RenderCommand* command, VkCommandBuffer commandBuffer)
{ {
ClayVulkanTexture* l_Texture = ClayVulkan_GetTexture(&renderer->m_ResourceCache, command->id); ClayVulkanTexture* l_Texture = ClayVulkan_GetTexture(&renderer->m_ResourceCache, command->id);
if (!l_Texture || !l_Texture->m_DescriptorSet) { if (!l_Texture || !l_Texture->m_DescriptorSet || !l_Texture->m_ImageView || !l_Texture->m_Sampler)
return; // Caller must populate descriptor sets before rendering. {
// Ensure descriptor sets are prepared before binding; application is responsible for keeping resources live.
return;
} }
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->m_ImagePipeline); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->m_ImagePipeline);
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->m_PipelineLayout, 0, 1, &l_Texture->m_DescriptorSet, 0, NULL); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->m_PipelineLayout, 0, 1, &l_Texture->m_DescriptorSet, 0, NULL);