From ff7f3e86eeb6d337ea0685a733661074fd14df1b Mon Sep 17 00:00:00 2001
From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com>
Date: Wed, 19 Nov 2025 22:58:48 +0000
Subject: [PATCH] Added multi triangle support
---
.gitignore | 2 +
.idea/dictionaries/project.xml | 7 +
.idea/editor.xml | 18 ++
main.cpp | 23 +-
shaders/vert.vert | 9 +-
src/VulkanRenderer.h | 5 +-
src/managers/vulkan/VulkanManager.h | 35 +++
src/managers/vulkan/VulkanManagerInit.cpp | 276 ++++++++++----------
src/managers/vulkan/VulkanManagerRender.cpp | 117 +++++++++
9 files changed, 341 insertions(+), 151 deletions(-)
create mode 100644 .gitignore
create mode 100644 .idea/dictionaries/project.xml
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..80d20dd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+# Compiled shader output #
+*.spv
diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..8f83205
--- /dev/null
+++ b/.idea/dictionaries/project.xml
@@ -0,0 +1,7 @@
+
+
+
+ spirv
+
+
+
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
index 008a960..14b5dc8 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -253,5 +253,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main.cpp b/main.cpp
index d0d4bbc..a1fa97b 100644
--- a/main.cpp
+++ b/main.cpp
@@ -23,20 +23,39 @@ int main()
/* Initializes GLFW and creates a window */
GLFWwindow* window = GLFWManager::Init(800, 600, "Vulkan window");
- if (!window)
+ if (window == nullptr)
return -1;
/* Runs Vulkan initialisation functions */
if (!VulkanManager::Init(window))
CleanupAllAndExit(EXIT_FAILURE);
+ /* Adds runtime objects */
+ const std::vector vertices = {
+ 0.0f, -0.5f,
+ 0.5f, 0.9f,
+ -0.5f, 0.5f
+ };
+
+ const std::vector indices = {0, 1, 2};
+
+ VulkanManager::CreateNewRenderObject(vertices, indices);
+
+ const std::vector otherVertices = {
+ -0.9f, 0.0f,
+ -0.9f, -0.9f,
+ 0.0f, -0.9f
+ };
+
+ VulkanManager::CreateNewRenderObject(otherVertices, indices);
+
/* Polls window events whilst it is still open */
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
GLFWManager::UpdateWindowTitleFPSInfo();
- if (!VulkanManager::RenderPass(window))
+ if (VulkanManager::RenderPass(window) == false)
CleanupAllAndExit(EXIT_FAILURE);
}
diff --git a/shaders/vert.vert b/shaders/vert.vert
index 0c10bde..beac4de 100644
--- a/shaders/vert.vert
+++ b/shaders/vert.vert
@@ -1,13 +1,8 @@
#version 450
-vec2 positions[3] = vec2[]
-(
- vec2(0.0, -0.5),
- vec2(0.5, 0.5),
- vec2(-0.5, 0.5)
-);
+layout(location = 0) in vec2 inPosition;
void main()
{
- gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
+ gl_Position = vec4(inPosition, 0.0, 1.0);
}
diff --git a/src/VulkanRenderer.h b/src/VulkanRenderer.h
index 330dcb0..8d9aaca 100644
--- a/src/VulkanRenderer.h
+++ b/src/VulkanRenderer.h
@@ -9,9 +9,10 @@
/* Commonly used C++ STD files */
+#include
#include
+#include
#include
#include
-#include
-#include
#include
+#include
diff --git a/src/managers/vulkan/VulkanManager.h b/src/managers/vulkan/VulkanManager.h
index 9e7bd33..f4056d6 100644
--- a/src/managers/vulkan/VulkanManager.h
+++ b/src/managers/vulkan/VulkanManager.h
@@ -4,9 +4,16 @@
namespace PB::Renderer
{
+ struct Vertex2D
+ {
+ float x, y;
+ };
+
class VulkanManager
{
public:
+ // === Public functions === //
+
/* Static class so (de)constructors have been deleted to stop accidental creation */
VulkanManager() = delete;
~VulkanManager() = delete;
@@ -88,9 +95,22 @@ namespace PB::Renderer
*/
static bool RenderPass(GLFWwindow* window);
+ static void CreateNewRenderObject(const std::vector& vertices, const std::vector& indices);
+
private:
// === Internal helper structs === //
+ struct RenderObject
+ {
+ VkBuffer VertexBuffer;
+ VkDeviceMemory VertexBufferMemory;
+
+ VkBuffer IndexBuffer;
+ VkDeviceMemory IndexBufferMemory;
+
+ uint32_t IndexCount;
+ };
+
struct QueueFamilyIndices
{
static constexpr uint32_t UNDEFINED_UINT32_VALUE = 0xFFFFFFFF;
@@ -113,6 +133,13 @@ namespace PB::Renderer
std::vector presentModes;
};
+ struct BufferCreationInfo
+ {
+ VkDeviceSize size;
+ VkBufferUsageFlags usage;
+ VkMemoryPropertyFlags properties;
+ };
+
// === Vulkan init helpers === //
static bool IsDeviceSuitable(const VkPhysicalDevice& device);
@@ -132,6 +159,14 @@ namespace PB::Renderer
static void RecreateSwapChain(GLFWwindow* window);
static void CleanupSwapChain();
+ static VkResult RecordCommandBuffer(uint32_t imageIndex);
+
+ static uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
+ static void CreateBuffer(VkBuffer& buffer, VkDeviceMemory& memory, const BufferCreationInfo& info);
+
+ // === Custom resources === //
+
+ static std::vector s_RenderObjects;
// === Vulkan resources === //
diff --git a/src/managers/vulkan/VulkanManagerInit.cpp b/src/managers/vulkan/VulkanManagerInit.cpp
index ab196f8..a01ce9c 100644
--- a/src/managers/vulkan/VulkanManagerInit.cpp
+++ b/src/managers/vulkan/VulkanManagerInit.cpp
@@ -2,6 +2,12 @@
namespace PB::Renderer
{
+ // === Custom resources === //
+
+ std::vector VulkanManager::s_RenderObjects = {};
+
+ // === Vulkan Resources === //
+
VkInstance VulkanManager::s_Instance = VK_NULL_HANDLE;
VkSurfaceKHR VulkanManager::s_Surface = VK_NULL_HANDLE;
@@ -537,116 +543,139 @@ namespace PB::Renderer
}
bool VulkanManager::CreateGraphicsPipeline()
+{
+ VkShaderModule vertShaderModule = CreateShaderModule("../shaders/vert.spv");
+ VkShaderModule fragShaderModule = CreateShaderModule("../shaders/frag.spv");
+
+ VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
+ vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
+ vertShaderStageInfo.module = vertShaderModule;
+ vertShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
+ fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+ fragShaderStageInfo.module = fragShaderModule;
+ fragShaderStageInfo.pName = "main";
+
+ VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
+
+ struct Vertex { float pos[2]; };
+
+ // Binding description
+ VkVertexInputBindingDescription binding{};
+ binding.binding = 0;
+ binding.stride = sizeof(Vertex);
+ binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+
+ // Attribute description
+ VkVertexInputAttributeDescription attribute{};
+ attribute.location = 0; // matches layout(location = 0)
+ attribute.binding = 0;
+ attribute.format = VK_FORMAT_R32G32_SFLOAT; // vec2
+ attribute.offset = offsetof(Vertex, pos);
+
+ VkVertexInputBindingDescription bindingDescriptions[] = { binding };
+ VkVertexInputAttributeDescription attributeDescriptions[] = { attribute };
+
+ VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
+ vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+ vertexInputInfo.vertexBindingDescriptionCount = 1;
+ vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions;
+ vertexInputInfo.vertexAttributeDescriptionCount = 1;
+ vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions;
+
+ VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
+ inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+ inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+ inputAssembly.primitiveRestartEnable = VK_FALSE;
+
+ VkViewport viewport{};
+ viewport.x = 0.0f;
+ viewport.y = 0.0f;
+ viewport.width = static_cast(s_SwapChainExtent.width);
+ viewport.height = static_cast(s_SwapChainExtent.height);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor{};
+ scissor.offset = { 0, 0 };
+ scissor.extent = s_SwapChainExtent;
+
+ VkPipelineViewportStateCreateInfo viewportState{};
+ viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+ viewportState.viewportCount = 1;
+ viewportState.pViewports = &viewport;
+ viewportState.scissorCount = 1;
+ viewportState.pScissors = &scissor;
+
+ VkPipelineRasterizationStateCreateInfo rasterizer{};
+ rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+ rasterizer.depthClampEnable = VK_FALSE;
+ rasterizer.rasterizerDiscardEnable = VK_FALSE;
+ rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
+ rasterizer.lineWidth = 1.0f;
+ rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
+ rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
+ rasterizer.depthBiasEnable = VK_FALSE;
+
+ VkPipelineMultisampleStateCreateInfo multisampling{};
+ multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+ multisampling.sampleShadingEnable = VK_FALSE;
+ multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
+
+ VkPipelineColorBlendAttachmentState colorBlendAttachment{};
+ colorBlendAttachment.colorWriteMask =
+ VK_COLOR_COMPONENT_R_BIT
+ | VK_COLOR_COMPONENT_G_BIT
+ | VK_COLOR_COMPONENT_B_BIT
+ | VK_COLOR_COMPONENT_A_BIT;
+ colorBlendAttachment.blendEnable = VK_FALSE;
+
+ VkPipelineColorBlendStateCreateInfo colorBlending{};
+ colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+ colorBlending.logicOpEnable = VK_FALSE;
+ colorBlending.attachmentCount = 1;
+ colorBlending.pAttachments = &colorBlendAttachment;
+
+ VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+
+ if (vkCreatePipelineLayout(s_Device, &pipelineLayoutInfo, nullptr, &s_PipelineLayout) != VK_SUCCESS)
{
- VkShaderModule vertShaderModule = CreateShaderModule("../shaders/vert.spv");
- VkShaderModule fragShaderModule = CreateShaderModule("../shaders/frag.spv");
-
- VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
- vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
- vertShaderStageInfo.module = vertShaderModule;
- vertShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
- fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- fragShaderStageInfo.module = fragShaderModule;
- fragShaderStageInfo.pName = "main";
-
- VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
-
- VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
- vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- vertexInputInfo.vertexBindingDescriptionCount = 0;
- vertexInputInfo.vertexAttributeDescriptionCount = 0;
-
- VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
- inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- inputAssembly.primitiveRestartEnable = VK_FALSE;
-
- VkViewport viewport{};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = static_cast(s_SwapChainExtent.width);
- viewport.height = static_cast(s_SwapChainExtent.height);
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
-
- VkRect2D scissor{};
- scissor.offset = {0,0};
- scissor.extent = s_SwapChainExtent;
-
- VkPipelineViewportStateCreateInfo viewportState{};
- viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewportState.viewportCount = 1;
- viewportState.pViewports = &viewport;
- viewportState.scissorCount = 1;
- viewportState.pScissors = &scissor;
-
- VkPipelineRasterizationStateCreateInfo rasterizer{};
- rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterizer.depthClampEnable = VK_FALSE;
- rasterizer.rasterizerDiscardEnable = VK_FALSE;
- rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
- rasterizer.lineWidth = 1.0f;
- rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
- rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
- rasterizer.depthBiasEnable = VK_FALSE;
-
- VkPipelineMultisampleStateCreateInfo multisampling{};
- multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampling.sampleShadingEnable = VK_FALSE;
- multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
-
- VkPipelineColorBlendAttachmentState colorBlendAttachment{};
- colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT
- | VK_COLOR_COMPONENT_G_BIT
- | VK_COLOR_COMPONENT_B_BIT
- | VK_COLOR_COMPONENT_A_BIT;
- colorBlendAttachment.blendEnable = VK_FALSE;
-
- VkPipelineColorBlendStateCreateInfo colorBlending{};
- colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colorBlending.logicOpEnable = VK_FALSE;
- colorBlending.attachmentCount = 1;
- colorBlending.pAttachments = &colorBlendAttachment;
-
- VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
- pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
-
- if (vkCreatePipelineLayout(s_Device, &pipelineLayoutInfo, nullptr, &s_PipelineLayout) != VK_SUCCESS)
- {
- std::cout << "PB::Renderer::VulkanManager::CreateGraphicsPipeline(): Could not make pipeline layout" << std::endl;
- return false;
- }
-
- VkGraphicsPipelineCreateInfo pipelineInfo{};
- pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipelineInfo.stageCount = 2;
- pipelineInfo.pStages = shaderStages;
- pipelineInfo.pVertexInputState = &vertexInputInfo;
- pipelineInfo.pInputAssemblyState = &inputAssembly;
- pipelineInfo.pViewportState = &viewportState;
- pipelineInfo.pRasterizationState = &rasterizer;
- pipelineInfo.pMultisampleState = &multisampling;
- pipelineInfo.pColorBlendState = &colorBlending;
- pipelineInfo.layout = s_PipelineLayout;
- pipelineInfo.renderPass = s_RenderPass;
- pipelineInfo.subpass = 0;
-
- if (vkCreateGraphicsPipelines(s_Device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &s_RenderPipeline) != VK_SUCCESS)
- {
- std::cout << "PB::Renderer::VulkanManager::CreateGraphicsPipeline(): Could not make graphics pipeline" << std::endl;
- return false;
- }
-
- vkDestroyShaderModule(s_Device, vertShaderModule, nullptr);
- vkDestroyShaderModule(s_Device, fragShaderModule, nullptr);
-
- return true;
+ std::cout << "PB::VulkanManager::CreateGraphicsPipeline(): Failed to create pipeline layout\n";
+ return false;
}
+ VkGraphicsPipelineCreateInfo pipelineInfo{};
+ pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+ pipelineInfo.stageCount = 2;
+ pipelineInfo.pStages = shaderStages;
+
+ pipelineInfo.pVertexInputState = &vertexInputInfo;
+ pipelineInfo.pInputAssemblyState = &inputAssembly;
+ pipelineInfo.pViewportState = &viewportState;
+ pipelineInfo.pRasterizationState = &rasterizer;
+ pipelineInfo.pMultisampleState = &multisampling;
+ pipelineInfo.pColorBlendState = &colorBlending;
+
+ pipelineInfo.layout = s_PipelineLayout;
+ pipelineInfo.renderPass = s_RenderPass;
+ pipelineInfo.subpass = 0;
+
+ if (vkCreateGraphicsPipelines(s_Device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &s_RenderPipeline) != VK_SUCCESS)
+ {
+ std::cout << "PB::VulkanManager::CreateGraphicsPipeline(): Failed to create graphics pipeline\n";
+ return false;
+ }
+
+ vkDestroyShaderModule(s_Device, vertShaderModule, nullptr);
+ vkDestroyShaderModule(s_Device, fragShaderModule, nullptr);
+
+ return true;
+}
+
VkShaderModule VulkanManager::CreateShaderModule(const std::string& filename)
{
std::ifstream file(filename, std::ios::ate | std::ios::binary);
@@ -703,39 +732,6 @@ namespace PB::Renderer
return false;
}
- for (size_t i = 0; i < s_CommandBuffers.size(); i++)
- {
- VkCommandBufferBeginInfo beginInfo{};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-
- vkBeginCommandBuffer(s_CommandBuffers[i], &beginInfo);
-
- VkRenderPassBeginInfo renderPassInfo{};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- renderPassInfo.renderPass = s_RenderPass;
- renderPassInfo.framebuffer = s_Framebuffers[i];
- renderPassInfo.renderArea.offset = {0, 0};
- renderPassInfo.renderArea.extent = s_SwapChainExtent;
-
- VkClearValue clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
- renderPassInfo.clearValueCount = 1;
- renderPassInfo.pClearValues = &clearColor;
-
- vkCmdBeginRenderPass(s_CommandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
-
- vkCmdBindPipeline(s_CommandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, s_RenderPipeline);
-
- vkCmdDraw(s_CommandBuffers[i], 3, 1, 0, 0);
-
- vkCmdEndRenderPass(s_CommandBuffers[i]);
-
- if (vkEndCommandBuffer(s_CommandBuffers[i]) != VK_SUCCESS)
- {
- std::cout << "PB::Renderer::VulkanManager::CreateCommandBuffers(): Could not end command buffer" << std::endl;
- return false;
- }
- }
-
return true;
}
diff --git a/src/managers/vulkan/VulkanManagerRender.cpp b/src/managers/vulkan/VulkanManagerRender.cpp
index c63dae9..4cb01ac 100644
--- a/src/managers/vulkan/VulkanManagerRender.cpp
+++ b/src/managers/vulkan/VulkanManagerRender.cpp
@@ -18,6 +18,35 @@ namespace PB::Renderer
}
}
+ void VulkanManager::CreateNewRenderObject(const std::vector& vertices, const std::vector& indices)
+ {
+ RenderObject obj{};
+ obj.IndexCount = indices.size();
+
+ BufferCreationInfo vertexCreationInfo;
+ vertexCreationInfo.size = vertices.size() * sizeof(float);;
+ vertexCreationInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
+ vertexCreationInfo.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+ CreateBuffer(obj.VertexBuffer, obj.VertexBufferMemory, vertexCreationInfo);
+
+ void* data;
+ vkMapMemory(s_Device, obj.VertexBufferMemory, 0, vertices.size() * sizeof(float), 0, &data);
+ std::memcpy(data, vertices.data(), vertices.size() * sizeof(float));
+ vkUnmapMemory(s_Device, obj.VertexBufferMemory);
+
+ BufferCreationInfo indexCreationInfo;
+ indexCreationInfo.size = indices.size() * sizeof(uint32_t);
+ indexCreationInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
+ indexCreationInfo.properties = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+ CreateBuffer(obj.IndexBuffer, obj.IndexBufferMemory, indexCreationInfo);
+
+ vkMapMemory(s_Device, obj.IndexBufferMemory, 0, indices.size() * sizeof(uint32_t), 0, &data);
+ std::memcpy(data, indices.data(), indices.size() * sizeof(uint32_t));
+ vkUnmapMemory(s_Device, obj.IndexBufferMemory);
+
+ s_RenderObjects.push_back(obj);
+ }
+
void VulkanManager::RecreateSwapChain(GLFWwindow* window)
{
int width, height;
@@ -64,6 +93,52 @@ namespace PB::Renderer
vkDestroySwapchainKHR(s_Device, s_SwapChain, nullptr);
}
+ VkResult VulkanManager::RecordCommandBuffer(const uint32_t imageIndex)
+ {
+ VkResult result = VK_SUCCESS;
+
+ const VkCommandBuffer& cmd = s_CommandBuffers[imageIndex];
+ VkCommandBufferBeginInfo beginInfo{};
+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ beginInfo.flags = 0;
+ beginInfo.pInheritanceInfo = nullptr;
+
+ result = vkBeginCommandBuffer(cmd, &beginInfo);
+ CHECK_RESULT(result);
+
+ VkRenderPassBeginInfo renderPassInfo{};
+ renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ renderPassInfo.renderPass = s_RenderPass;
+ renderPassInfo.framebuffer = s_Framebuffers[imageIndex];
+ renderPassInfo.renderArea.offset = { 0, 0 };
+ renderPassInfo.renderArea.extent = s_SwapChainExtent;
+
+ VkClearValue clearValue[2];
+ clearValue[0].color = { 0.0f, 0.0f, 0.0f, 1.0f };
+ clearValue[1].depthStencil = { 1.0f, 0 };
+
+ renderPassInfo.clearValueCount = 2;
+ renderPassInfo.pClearValues = clearValue;
+
+ vkCmdBeginRenderPass(cmd, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
+ vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, s_RenderPipeline);
+
+ for (const auto& renderObject : s_RenderObjects)
+ {
+ VkBuffer vertexBuffer = { renderObject.VertexBuffer };
+ constexpr VkDeviceSize offsets[] = { 0 };
+
+ vkCmdBindVertexBuffers(cmd, 0, 1, &vertexBuffer, offsets);
+ vkCmdBindIndexBuffer(cmd, renderObject.IndexBuffer, 0, VK_INDEX_TYPE_UINT32);
+ vkCmdDrawIndexed(cmd, renderObject.IndexCount, 1, 0, 0, 0);
+ }
+
+ vkCmdEndRenderPass(cmd);
+ result = vkEndCommandBuffer(cmd);
+
+ return result;
+ }
+
VkResult VulkanManager::RenderPassInternal()
{
uint32_t imageIndex;
@@ -77,6 +152,9 @@ namespace PB::Renderer
);
CHECK_RESULT(result);
+ result = RecordCommandBuffer(imageIndex);
+ CHECK_RESULT(result);
+
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
@@ -112,4 +190,43 @@ namespace PB::Renderer
vkQueueWaitIdle(s_PresentQueue);
return VK_SUCCESS;
}
+
+ uint32_t VulkanManager::FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
+ {
+ VkPhysicalDeviceMemoryProperties memProperties;
+ vkGetPhysicalDeviceMemoryProperties(s_PhysicalDevice, &memProperties);
+
+ for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
+ {
+ bool typeSupported = (typeFilter & (1 << i)) != 0;
+ bool hasProperties = (memProperties.memoryTypes[i].propertyFlags & properties) == properties;
+
+ if (typeSupported && hasProperties)
+ return i;
+ }
+
+ return -1;
+ }
+
+ void VulkanManager::CreateBuffer(VkBuffer& buffer, VkDeviceMemory& memory, const BufferCreationInfo& info)
+ {
+ VkBufferCreateInfo bufferInfo{};
+ bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+ bufferInfo.size = info.size;
+ bufferInfo.usage = info.usage;
+ bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+ vkCreateBuffer(s_Device, &bufferInfo, nullptr, &buffer);
+
+ VkMemoryRequirements memRequirements;
+ vkGetBufferMemoryRequirements(s_Device, buffer, &memRequirements);
+
+ VkMemoryAllocateInfo allocInfo{};
+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+ allocInfo.allocationSize = memRequirements.size;
+ allocInfo.memoryTypeIndex = FindMemoryType(memRequirements.memoryTypeBits, info.properties);
+
+ vkAllocateMemory(s_Device, &allocInfo, nullptr, &memory);
+ vkBindBufferMemory(s_Device, buffer, memory, 0);
+ }
}