Rendering Engine 0.2.9
Modular Graphics Rendering Engine | v0.2.9
rendering_engine::VulkanRenderer Class Reference

Vulkan-based implementation of the IRenderer interface. More...

#include <vulkan_renderer.hpp>

Inherits rendering_engine::IRenderer.

Public Member Functions

 VulkanRenderer (IWindowSystem &windowSystem)
 Constructs a VulkanRenderer bound to a specific window system. More...
 
void InitializeRenderer () override
 Initializes all rendering subsystems and GPU resources. More...
 
void DrawFrame () override
 Executes a full frame rendering cycle. More...
 
bool BeginFrame () override
 Begins frame rendering operations. More...
 
void BeginRenderPass () override
 Begins the active render pass for the current frame. More...
 
void EndRenderPass () override
 Ends the active render pass. More...
 
void EndFrame () override
 Completes the current frame rendering and presents the result. More...
 
void WaitIdle () override
 Waits until the GPU has finished all pending rendering operations. More...
 
void ShutdownRenderer () override
 Destroys and cleans up all rendering resources. More...
 
void RegisterObserver (IRendererObserver *notifier) override
 Registers an observer for rendering events. More...
 
void UnregisterObserver (IRendererObserver *notifier) override
 Unregisters a previously registered observer. More...
 
IRenderResourcesProvideRenderResources () const override
 Provides access to the general rendering resource manager. More...
 
ITextureRenderResourcesProvideTextureRenderResources () const override
 Provides access to texture-related GPU resources. More...
 
IMaterialRenderResourcesProvideMaterialRenderResources () const override
 Provides access to material-related GPU resources. More...
 
IMeshRenderResourcesProvideMeshRenderResources () const override
 Provides access to mesh-related GPU resources. More...
 
void SetDefaultColor (float r, float g, float b) override
 Sets the renderer clear color. More...
 
void CreateBuffer (VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
 Creates a new Vulkan buffer with the specified usage and memory properties. More...
 
void CopyBuffer (VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
 Copies data from one buffer to another using a temporary command buffer. More...
 
VkDevice & GetLogicalDevice ()
 Returns reference to the logical Vulkan device. More...
 
void TransitionImageLayout (VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, std::uint32_t mipmapLevels)
 Transitions the image layout for a given Vulkan image. More...
 
void CopyBufferToImage (VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
 Copies buffer data into an image (used for uploading texture data). More...
 
void GenerateMipmaps (VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels)
 Generates mipmaps for a given image resource. More...
 
uint32_t FindMemoryType (uint32_t typeFilter, VkMemoryPropertyFlags properties)
 Finds a suitable memory type for a given allocation. More...
 
VkPhysicalDevice & GetPhysicalDevice ()
 Returns reference to the physical device. More...
 
VkPhysicalDeviceFeatures & GetPhysDevSupportedFeatures ()
 Returns reference to the physical device�s supported features. More...
 
VkDescriptorSetLayout CreateDescriptorSetLayout (Material *material)
 Creates a descriptor set layout corresponding to a given material. More...
 
size_t GetCurrentFrame () const
 Returns the index of the currently active frame in flight. More...
 
std::vector< VkCommandBuffer > GetComandBuffers ()
 Returns the collection of command buffers used for rendering. More...
 
std::pair< VkPipelineLayout, VkPipeline > CreateGraphicsPipeline (Material *material, VkDescriptorSetLayout &descriptorSetLayout, std::vector< char > &spvVertShaderCode, std::vector< char > &spvFragShaderCode)
 Creates a Vulkan graphics pipeline based on material and shader inputs. More...
 
void AddDeferredDestroy (DeferredItem deferredItem)
 
- Public Member Functions inherited from rendering_engine::IRenderer
virtual void InitializeRenderer ()=0
 Initializes all rendering subsystems and GPU resources. More...
 
virtual void DrawFrame ()=0
 Executes a full frame rendering cycle. More...
 
virtual bool BeginFrame ()=0
 Begins frame rendering operations. More...
 
virtual void BeginRenderPass ()=0
 Begins the active render pass for the current frame. More...
 
virtual void EndRenderPass ()=0
 Ends the active render pass. More...
 
virtual void EndFrame ()=0
 Completes the current frame rendering and presents the result. More...
 
virtual void WaitIdle ()=0
 Waits until the GPU has finished all pending rendering operations. More...
 
virtual void ShutdownRenderer ()=0
 Destroys and cleans up all rendering resources. More...
 
virtual void RegisterObserver (IRendererObserver *notifier)=0
 Registers an observer for rendering events. More...
 
virtual void UnregisterObserver (IRendererObserver *notifier)=0
 Unregisters a previously registered observer. More...
 
virtual IRenderResourcesProvideRenderResources () const =0
 Provides access to the general rendering resource manager. More...
 
virtual ITextureRenderResourcesProvideTextureRenderResources () const =0
 Provides access to texture-related GPU resources. More...
 
virtual IMaterialRenderResourcesProvideMaterialRenderResources () const =0
 Provides access to material-related GPU resources. More...
 
virtual IMeshRenderResourcesProvideMeshRenderResources () const =0
 Provides access to mesh-related GPU resources. More...
 
virtual ~IRenderer ()=default
 Virtual destructor for safe polymorphic deletion. More...
 
virtual void SetDefaultColor (float r, float g, float b)=0
 Sets the renderer clear color. More...
 

Static Public Member Functions

template<typename T >
static VkVertexInputBindingDescription GetBindingDescription ()
 Returns a vertex input binding description for a specific vertex type. More...
 
template<typename T >
static std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 Returns vertex attribute descriptions for a specific vertex type. More...
 
template<>
std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 
template<>
std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 
template<>
std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 
template<>
std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 
template<>
std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 
template<>
std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 

Detailed Description

Vulkan-based implementation of the IRenderer interface.

This class encapsulates the initialization and management of Vulkan rendering resources, including device selection, swap chain management, render pass setup, frame synchronization, and command buffer submission. It serves as the core rendering backend for all graphics operations performed by the engine.

Definition at line 89 of file vulkan_renderer.hpp.

Constructor & Destructor Documentation

◆ VulkanRenderer()

rendering_engine::VulkanRenderer::VulkanRenderer ( IWindowSystem windowSystem)

Constructs a VulkanRenderer bound to a specific window system.

Parameters
windowSystemReference to the window system used for surface creation and event handling.

Definition at line 39 of file vulkan_renderer.cpp.

40 :
41 mWindowSystem{windowSystem},
42 mCurrentFrame{0}
43{}

Member Function Documentation

◆ AddDeferredDestroy()

void rendering_engine::VulkanRenderer::AddDeferredDestroy ( DeferredItem  deferredItem)

Definition at line 598 of file vulkan_renderer.cpp.

599{
600 switch (deferredItem.type)
601 {
602 case DeferredType::Buffer: if (deferredItem.buffer == VK_NULL_HANDLE) return; break;
603 case DeferredType::Memory: if (deferredItem.memory == VK_NULL_HANDLE) return; break;
604 case DeferredType::DescriptorPool: if (deferredItem.descriptorPool == VK_NULL_HANDLE) return; break;
605 default: break;
606 }
607 deferredItem.retireFrame = mFrameSerial + MAX_FRAMES_IN_FLIGHT;
608 mDeferredQueue.push_back(deferredItem);
609}
const int MAX_FRAMES_IN_FLIGHT
Number of frames that can be processed simultaneously (double buffering).

◆ BeginFrame()

bool rendering_engine::VulkanRenderer::BeginFrame ( )
overridevirtual

Begins frame rendering operations.

Returns
True if the frame can proceed.

Implements rendering_engine::IRenderer.

Definition at line 149 of file vulkan_renderer.cpp.

150{
151 vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame], VK_TRUE, UINT64_MAX);
152
153 VkResult result = vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame], VK_NULL_HANDLE, &mImageIndex);
154
155 if (result == VK_ERROR_OUT_OF_DATE_KHR)
156 {
157 RecreateSwapChain();
158 return false;
159 }
160 else
161 {
162 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
163 {
164 LOG_ERROR("failed to acquire swap chain image!");
165 throw std::runtime_error("failed to acquire swap chain image!");
166 }
167 }
168
169 if (mImagesInFlight[mImageIndex] != VK_NULL_HANDLE)
170 {
171 vkWaitForFences(mLogicalDevice, 1, &mImagesInFlight[mImageIndex], VK_TRUE, UINT64_MAX);
172 }
173 mImagesInFlight[mImageIndex] = mInFlightFences[mCurrentFrame];
174
175 vkResetFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame]);
176 ++mFrameSerial;
177 ProcessDeferredDestruction();
178
179 vkResetCommandBuffer(mCommandBuffers[mCurrentFrame], /*VkCommandBufferResetFlagBits*/ 0);
180
181 return true;
182}
#define LOG_ERROR(msg)
Definition: logger.hpp:41

◆ BeginRenderPass()

void rendering_engine::VulkanRenderer::BeginRenderPass ( )
overridevirtual

Begins the active render pass for the current frame.

Implements rendering_engine::IRenderer.

Definition at line 184 of file vulkan_renderer.cpp.

185{
186 VkCommandBufferBeginInfo beginInfo{};
187 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
188 //beginInfo.flags = 0; // Optional
189 //beginInfo.pInheritanceInfo = nullptr; // Optional
190
191 if (vkBeginCommandBuffer(mCommandBuffers[mCurrentFrame], &beginInfo) != VK_SUCCESS)
192 {
193 LOG_ERROR("failed to begin recording command buffer!");
194 throw std::runtime_error("failed to begin recording command buffer!");
195 }
196
197 VkRenderPassBeginInfo renderPassInfo{};
198 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
199 renderPassInfo.renderPass = mRenderPass;
200 renderPassInfo.framebuffer = mSwapChainFramebuffers[mImageIndex];
201
202 renderPassInfo.renderArea.offset = { 0, 0 };
203 renderPassInfo.renderArea.extent = mSwapChainExtent;
204
205 std::array<VkClearValue, 2> clearValues{};
206 clearValues[0].color = { {mDefaultColor.r, mDefaultColor.g, mDefaultColor.b, 1.0f} };
207 clearValues[1].depthStencil = { 1.0f, 0 };
208 renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
209 renderPassInfo.pClearValues = clearValues.data();
210
211 vkCmdBeginRenderPass(mCommandBuffers[mCurrentFrame], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
212}

◆ CopyBuffer()

void rendering_engine::VulkanRenderer::CopyBuffer ( VkBuffer  srcBuffer,
VkBuffer  dstBuffer,
VkDeviceSize  size 
)

Copies data from one buffer to another using a temporary command buffer.

Parameters
srcBufferSource buffer.
dstBufferDestination buffer.
sizeSize of data to copy in bytes.

Definition at line 383 of file vulkan_renderer.cpp.

384{
385 auto commandBuffer = BeginSingleTimeCommand();
386
387 VkBufferCopy copyRegion{};
388 copyRegion.srcOffset = 0; // Optional
389 copyRegion.dstOffset = 0; // Optional
390 copyRegion.size = size;
391 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
392
393 EndSingleTimeCommand(commandBuffer);
394}

◆ CopyBufferToImage()

void rendering_engine::VulkanRenderer::CopyBufferToImage ( VkBuffer  buffer,
VkImage  image,
uint32_t  width,
uint32_t  height 
)

Copies buffer data into an image (used for uploading texture data).

Parameters
bufferSource buffer containing pixel data.
imageDestination image.
widthImage width in pixels.
heightImage height in pixels.

Definition at line 474 of file vulkan_renderer.cpp.

475{
476 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
477
478 VkBufferImageCopy region{};
479 region.bufferOffset = 0;
480 region.bufferRowLength = 0;
481 region.bufferImageHeight = 0;
482
483 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
484 region.imageSubresource.mipLevel = 0;
485 region.imageSubresource.baseArrayLayer = 0;
486 region.imageSubresource.layerCount = 1;
487
488 region.imageOffset = { 0, 0, 0 };
489 region.imageExtent = {
490 width,
491 height,
492 1
493 };
494
495 vkCmdCopyBufferToImage(
496 commandBuffer,
497 buffer,
498 image,
499 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
500 1,
501 &region
502 );
503
504 EndSingleTimeCommand(commandBuffer);
505}

◆ CreateBuffer()

void rendering_engine::VulkanRenderer::CreateBuffer ( VkDeviceSize  size,
VkBufferUsageFlags  usage,
VkMemoryPropertyFlags  properties,
VkBuffer &  buffer,
VkDeviceMemory &  bufferMemory 
)

Creates a new Vulkan buffer with the specified usage and memory properties.

Parameters
sizeSize of the buffer in bytes.
usageBitmask specifying intended buffer usage.
propertiesMemory property flags defining allocation type.
bufferOutput handle to the created buffer.
bufferMemoryOutput handle to the allocated buffer memory.

Definition at line 351 of file vulkan_renderer.cpp.

352{
353 VkBufferCreateInfo bufferInfo{};
354 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
355 bufferInfo.size = size;
356
357 bufferInfo.usage = usage;
358 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
359
360 if (vkCreateBuffer(mLogicalDevice, &bufferInfo, nullptr, &buffer) != VK_SUCCESS)
361 {
362 LOG_ERROR("failed to create vertex buffer!");
363 throw std::runtime_error("failed to create vertex buffer!");
364 }
365
366 VkMemoryRequirements memRequirements;
367 vkGetBufferMemoryRequirements(mLogicalDevice, buffer, &memRequirements);
368
369 VkMemoryAllocateInfo allocInfo{};
370 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
371 allocInfo.allocationSize = memRequirements.size;
372 allocInfo.memoryTypeIndex = FindMemoryType(memRequirements.memoryTypeBits, properties);
373
374 if (vkAllocateMemory(mLogicalDevice, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS)
375 {
376 LOG_ERROR("failed to allocate vertex buffer memory!");
377 throw std::runtime_error("failed to allocate vertex buffer memory!");
378 }
379
380 vkBindBufferMemory(mLogicalDevice, buffer, bufferMemory, 0);
381}
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
Finds a suitable memory type for a given allocation.

◆ CreateDescriptorSetLayout()

VkDescriptorSetLayout rendering_engine::VulkanRenderer::CreateDescriptorSetLayout ( Material material)

Creates a descriptor set layout corresponding to a given material.

The layout defines how shader resources (uniform buffers, custom parameters, textures) are bound to the pipeline. By the local convention of this engine:

  • Binding 0 � Transformation matrices (model, view, projection) depending on material domain (2D or 3D).
  • Binding 1 � Custom parameter variable block (if any). All variables are serialized and packed into a single binding.
  • Bindings 2..n � Texture samplers, one texture per binding.

This convention ensures consistent descriptor bindings across all shaders and materials.

Parameters
materialPointer to the material defining binding structure.
Returns
Handle to the created descriptor set layout.

Definition at line 1411 of file vulkan_renderer.cpp.

1412{
1413 std::uint32_t bindingNumber = 0;
1414 std::vector<VkDescriptorSetLayoutBinding> bindings;
1415
1416 // Uniform buffer to transmit transformation matrix
1417 VkDescriptorSetLayoutBinding uboLayoutBinding{};
1418 uboLayoutBinding.binding = bindingNumber;
1419 uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1420 uboLayoutBinding.descriptorCount = 1;
1421 uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1422 uboLayoutBinding.pImmutableSamplers = nullptr; // Optional
1423
1424 bindings.push_back(uboLayoutBinding);
1425
1426 PackedMaterialData packedMaterialData = material->PackMaterialParameters();
1427 if (!packedMaterialData.buffer.empty())
1428 {
1429 ++bindingNumber;
1430 // Uniform buffer to transmit custom material variables
1431 VkDescriptorSetLayoutBinding customMaterialVariables;
1432 customMaterialVariables.binding = bindingNumber;
1433 customMaterialVariables.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1434 customMaterialVariables.descriptorCount = 1;
1435 customMaterialVariables.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
1436 customMaterialVariables.pImmutableSamplers = nullptr; // Optional
1437
1438 bindings.push_back(customMaterialVariables);
1439 }
1440
1441 for (const auto& textureName : material->GetTextures())
1442 {
1443 (void)textureName;
1444 ++bindingNumber;
1445 VkDescriptorSetLayoutBinding samplerLayoutBinding{};
1446 samplerLayoutBinding.binding = bindingNumber;
1447 samplerLayoutBinding.descriptorCount = 1;
1448 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1449 samplerLayoutBinding.pImmutableSamplers = nullptr;
1450 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1451
1452 bindings.push_back(samplerLayoutBinding);
1453 }
1454
1455 VkDescriptorSetLayoutCreateInfo layoutInfo{};
1456 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1457 layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
1458 layoutInfo.pBindings = bindings.data();
1459
1460 VkDescriptorSetLayout result;
1461 if (vkCreateDescriptorSetLayout(mLogicalDevice, &layoutInfo, nullptr, &result) != VK_SUCCESS)
1462 {
1463 LOG_ERROR("failed to create descriptor set layout!");
1464 throw std::runtime_error("failed to create descriptor set layout!");
1465 }
1466
1467 return result;
1468}

◆ CreateGraphicsPipeline()

std::pair< VkPipelineLayout, VkPipeline > rendering_engine::VulkanRenderer::CreateGraphicsPipeline ( Material material,
VkDescriptorSetLayout &  descriptorSetLayout,
std::vector< char > &  spvVertShaderCode,
std::vector< char > &  spvFragShaderCode 
)

Creates a Vulkan graphics pipeline based on material and shader inputs.

Parameters
materialPointer to the material configuration.
descriptorSetLayoutDescriptor set layout used in the pipeline.
spvVertShaderCodeCompiled SPIR-V vertex shader bytecode.
spvFragShaderCodeCompiled SPIR-V fragment shader bytecode.
Returns
A pair containing pipeline layout and pipeline handle.

Definition at line 1475 of file vulkan_renderer.cpp.

1476{
1477 VkPipelineLayout pipelineLayout;
1478 VkPipeline pipeline;
1479
1480 VkShaderModule vertShaderModule = CreateShaderModule(spvVertShaderCode);
1481 VkShaderModule fragShaderModule = CreateShaderModule(spvFragShaderCode);
1482
1483 VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
1484 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1485 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
1486
1487 vertShaderStageInfo.module = vertShaderModule;
1488 vertShaderStageInfo.pName = "main";
1489
1490 VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
1491 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1492 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1493 fragShaderStageInfo.module = fragShaderModule;
1494 fragShaderStageInfo.pName = "main";
1495
1496 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
1497
1498 VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
1499 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1500
1501 VkVertexInputBindingDescription bindingDescription;
1502 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1503
1504 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
1505 {
1506 bindingDescription = GetBindingDescription<Vertex2D>();
1507 attributeDescriptions = GetAttributeDescriptions<Vertex2D>();
1508 }
1509 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Surface3D)
1510 {
1511 bindingDescription = GetBindingDescription<VertexPositionColorTextureNormalTangent>();
1512 attributeDescriptions = GetAttributeDescriptions<VertexPositionColorTextureNormalTangent>();
1513 }
1514
1515 vertexInputInfo.vertexBindingDescriptionCount = 1;
1516 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
1517
1518 vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
1519 vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
1520
1521 VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
1522 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1523 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1524 inputAssembly.primitiveRestartEnable = VK_FALSE;
1525
1526 VkViewport viewport{};
1527 viewport.x = 0.0f;
1528 viewport.y = 0.0f;
1529 viewport.width = (float)mSwapChainExtent.width;
1530 viewport.height = (float)mSwapChainExtent.height;
1531 viewport.minDepth = 0.0f;
1532 viewport.maxDepth = 1.0f;
1533
1534 VkRect2D scissor{};
1535 scissor.offset = { 0, 0 };
1536 scissor.extent = mSwapChainExtent;
1537
1538 VkPipelineViewportStateCreateInfo viewportState{};
1539 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1540 viewportState.viewportCount = 1;
1541 viewportState.pViewports = &viewport;
1542 viewportState.scissorCount = 1;
1543 viewportState.pScissors = &scissor;
1544
1545 VkPipelineRasterizationStateCreateInfo rasterizer{};
1546 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1547 rasterizer.depthClampEnable = VK_FALSE;
1548 rasterizer.rasterizerDiscardEnable = VK_FALSE;
1549 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
1550 rasterizer.lineWidth = 1.0f;
1551 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
1552 {
1553 rasterizer.cullMode = VK_CULL_MODE_NONE;
1554 }
1555 else
1556 {
1557 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
1558 }
1559 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
1560 rasterizer.depthBiasEnable = VK_FALSE;
1561 rasterizer.depthBiasConstantFactor = 0.0f; // Optional
1562 rasterizer.depthBiasClamp = 0.0f; // Optional
1563 rasterizer.depthBiasSlopeFactor = 0.0f; // Optional
1564
1565 VkPipelineMultisampleStateCreateInfo multisampling{};
1566 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1567 multisampling.sampleShadingEnable = VK_FALSE;
1568 multisampling.rasterizationSamples = mMSAASamples;
1569 multisampling.minSampleShading = 1.0f; // Optional
1570 multisampling.pSampleMask = nullptr; // Optional
1571 multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
1572 multisampling.alphaToOneEnable = VK_FALSE; // Optional
1573
1574 VkPipelineColorBlendAttachmentState colorBlendAttachment{};
1575 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
1576 colorBlendAttachment.blendEnable = (material->GetMaterialSettings().blendMode == BlendMode::Translucent) ? VK_TRUE : VK_FALSE;
1577 colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
1578 colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
1579 colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; // Optional
1580 colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
1581 colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
1582 colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
1583
1584 VkPipelineColorBlendStateCreateInfo colorBlending{};
1585 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1586 colorBlending.logicOpEnable = VK_FALSE;
1587 colorBlending.logicOp = VK_LOGIC_OP_COPY; // Optional
1588 colorBlending.attachmentCount = 1;
1589 colorBlending.pAttachments = &colorBlendAttachment;
1590 colorBlending.blendConstants[0] = 0.0f; // Optional
1591 colorBlending.blendConstants[1] = 0.0f; // Optional
1592 colorBlending.blendConstants[2] = 0.0f; // Optional
1593 colorBlending.blendConstants[3] = 0.0f; // Optional
1594
1595 // To use dynamicState, assign reference to it in pipelineInfo.pDynamicState.
1596 std::vector<VkDynamicState> dynamicStates = {
1597 VK_DYNAMIC_STATE_VIEWPORT,
1598 VK_DYNAMIC_STATE_SCISSOR
1599 };
1600 VkPipelineDynamicStateCreateInfo dynamicState{};
1601 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1602 dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
1603 dynamicState.pDynamicStates = dynamicStates.data();
1604
1605 VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
1606 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
1607 pipelineLayoutInfo.setLayoutCount = 1;
1608 pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
1609
1610 if (vkCreatePipelineLayout(mLogicalDevice, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS)
1611 {
1612 LOG_ERROR("failed to create pipeline layout!");
1613 throw std::runtime_error("failed to create pipeline layout!");
1614 }
1615
1616 VkPipelineDepthStencilStateCreateInfo depthStencil{};
1617 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1618 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
1619 {
1620 depthStencil.depthTestEnable = VK_FALSE;
1621 depthStencil.depthWriteEnable = VK_FALSE;
1622 }
1623 else
1624 {
1625 depthStencil.depthTestEnable = VK_TRUE;
1626 depthStencil.depthWriteEnable = (material->GetMaterialSettings().blendMode == BlendMode::Opaque) ? VK_TRUE : VK_FALSE;
1627 }
1628 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
1629 depthStencil.depthBoundsTestEnable = VK_FALSE;
1630 //depthStencil.minDepthBounds = 0.0f; // Optional
1631 //depthStencil.maxDepthBounds = 1.0f; // Optional
1632 depthStencil.stencilTestEnable = VK_FALSE;
1633 //depthStencil.front = {}; // Optional
1634 depthStencil.back = {}; // Optional
1635
1636 VkGraphicsPipelineCreateInfo pipelineInfo{};
1637 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1638 pipelineInfo.stageCount = 2;
1639 pipelineInfo.pStages = shaderStages;
1640 pipelineInfo.pVertexInputState = &vertexInputInfo;
1641 pipelineInfo.pInputAssemblyState = &inputAssembly;
1642 pipelineInfo.pViewportState = &viewportState;
1643 pipelineInfo.pRasterizationState = &rasterizer;
1644 pipelineInfo.pMultisampleState = &multisampling;
1645 pipelineInfo.pDepthStencilState = &depthStencil;
1646 pipelineInfo.pColorBlendState = &colorBlending;
1647 pipelineInfo.pDynamicState = nullptr;
1648 pipelineInfo.layout = pipelineLayout;
1649 pipelineInfo.renderPass = mRenderPass;
1650 pipelineInfo.subpass = 0;
1651 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
1652 pipelineInfo.basePipelineIndex = -1; // Optional
1653
1654
1655 if (vkCreateGraphicsPipelines(mLogicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline) != VK_SUCCESS)
1656 {
1657 LOG_ERROR("failed to create graphics pipeline!");
1658 throw std::runtime_error("failed to create graphics pipeline!");
1659 }
1660 vkDestroyShaderModule(mLogicalDevice, fragShaderModule, nullptr);
1661 vkDestroyShaderModule(mLogicalDevice, vertShaderModule, nullptr);
1662
1663 return std::pair<VkPipelineLayout, VkPipeline>(pipelineLayout, pipeline);
1664}

◆ DrawFrame()

void rendering_engine::VulkanRenderer::DrawFrame ( )
overridevirtual

Executes a full frame rendering cycle.

Implements rendering_engine::IRenderer.

Definition at line 69 of file vulkan_renderer.cpp.

70{
71 vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame], VK_TRUE, UINT64_MAX);
72
73 uint32_t imageIndex;
74 VkResult result = vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame], VK_NULL_HANDLE, &imageIndex);
75
76 if (result == VK_ERROR_OUT_OF_DATE_KHR)
77 {
78 LOG_WARNING("Swapchain out of date. Triggering recreation.");
79 RecreateSwapChain();
80 return;
81 }
82 else
83 {
84 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
85 {
86 LOG_ERROR("failed to acquire swap chain image!");
87 throw std::runtime_error("failed to acquire swap chain image!");
88 }
89 }
90
91 vkResetFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame]);
92
93 vkResetCommandBuffer(mCommandBuffers[mCurrentFrame], /*VkCommandBufferResetFlagBits*/ 0);
94 RecordCommandBuffer(mCommandBuffers[mCurrentFrame], imageIndex);
95
96 VkSubmitInfo submitInfo{};
97 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
98
99 VkSemaphore waitSemaphores[] = { mImageAvailableSemaphores[mCurrentFrame] };
100 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
101 submitInfo.waitSemaphoreCount = 1;
102 submitInfo.pWaitSemaphores = waitSemaphores;
103 submitInfo.pWaitDstStageMask = waitStages;
104
105 submitInfo.commandBufferCount = 1;
106 submitInfo.pCommandBuffers = &mCommandBuffers[mCurrentFrame];
107
108 VkSemaphore signalSemaphores[] = { mRenderFinishedSemaphores[imageIndex] };
109 submitInfo.signalSemaphoreCount = 1;
110 submitInfo.pSignalSemaphores = signalSemaphores;
111
112 if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[mCurrentFrame]) != VK_SUCCESS)
113 {
114 LOG_ERROR("failed to submit draw command buffer!");
115 throw std::runtime_error("failed to submit draw command buffer!");
116 }
117
118 VkPresentInfoKHR presentInfo{};
119 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
120
121 presentInfo.waitSemaphoreCount = 1;
122 presentInfo.pWaitSemaphores = signalSemaphores;
123
124 VkSwapchainKHR swapChains[] = { mSwapChain };
125 presentInfo.swapchainCount = 1;
126 presentInfo.pSwapchains = swapChains;
127
128 presentInfo.pImageIndices = &imageIndex;
129
130 result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
131
132 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mWindowSystem.IsFramebufferResized())
133 {
134 mWindowSystem.ResetFramebufferResizedFlag();
135 RecreateSwapChain();
136 }
137 else
138 {
139 if (result != VK_SUCCESS)
140 {
141 LOG_ERROR("failed to present swap chain image!");
142 throw std::runtime_error("failed to present swap chain image!");
143 }
144 }
145
146 mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
147}
virtual void ResetFramebufferResizedFlag()=0
Resets the framebuffer resized flag after handling a resize event.
virtual bool IsFramebufferResized() const =0
Checks if the framebuffer has been resized since the last frame.
#define LOG_WARNING(msg)
Definition: logger.hpp:40

◆ EndFrame()

void rendering_engine::VulkanRenderer::EndFrame ( )
overridevirtual

Completes the current frame rendering and presents the result.

Implements rendering_engine::IRenderer.

Definition at line 219 of file vulkan_renderer.cpp.

220{
221 if (vkEndCommandBuffer(mCommandBuffers[mCurrentFrame]) != VK_SUCCESS)
222 {
223 LOG_ERROR("failed to record command buffer!");
224 throw std::runtime_error("failed to record command buffer!");
225 }
226
227 VkSubmitInfo submitInfo{};
228 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
229
230 VkSemaphore waitSemaphores[] = { mImageAvailableSemaphores[mCurrentFrame] };
231 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
232 submitInfo.waitSemaphoreCount = 1;
233 submitInfo.pWaitSemaphores = waitSemaphores;
234 submitInfo.pWaitDstStageMask = waitStages;
235
236 submitInfo.commandBufferCount = 1;
237 submitInfo.pCommandBuffers = &mCommandBuffers[mCurrentFrame];
238
239 VkSemaphore signalSemaphores[] = { mRenderFinishedSemaphores[mImageIndex] };
240 submitInfo.signalSemaphoreCount = 1;
241 submitInfo.pSignalSemaphores = signalSemaphores;
242
243 if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[mCurrentFrame]) != VK_SUCCESS)
244 {
245 LOG_ERROR("failed to submit draw command buffer!");
246 throw std::runtime_error("failed to submit draw command buffer!");
247 }
248
249 VkPresentInfoKHR presentInfo{};
250 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
251
252 presentInfo.waitSemaphoreCount = 1;
253 presentInfo.pWaitSemaphores = signalSemaphores;
254
255 VkSwapchainKHR swapChains[] = { mSwapChain };
256 presentInfo.swapchainCount = 1;
257 presentInfo.pSwapchains = swapChains;
258
259 presentInfo.pImageIndices = &mImageIndex;
260
261 VkResult result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
262
263 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mWindowSystem.IsFramebufferResized())
264 {
265 mWindowSystem.ResetFramebufferResizedFlag();
266 RecreateSwapChain();
267 }
268 else
269 {
270 if (result != VK_SUCCESS)
271 {
272 LOG_ERROR("failed to present swap chain image!");
273 throw std::runtime_error("failed to present swap chain image!");
274 }
275 }
276
277 mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
278}

◆ EndRenderPass()

void rendering_engine::VulkanRenderer::EndRenderPass ( )
overridevirtual

Ends the active render pass.

Implements rendering_engine::IRenderer.

Definition at line 214 of file vulkan_renderer.cpp.

215{
216 vkCmdEndRenderPass(mCommandBuffers[mCurrentFrame]);
217}

◆ FindMemoryType()

uint32_t rendering_engine::VulkanRenderer::FindMemoryType ( uint32_t  typeFilter,
VkMemoryPropertyFlags  properties 
)

Finds a suitable memory type for a given allocation.

Parameters
typeFilterBitmask of compatible memory types.
propertiesDesired memory property flags.
Returns
Index of the selected memory type.

Definition at line 1385 of file vulkan_renderer.cpp.

1386{
1387 VkPhysicalDeviceMemoryProperties memProperties;
1388 vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memProperties);
1389
1390 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
1391 {
1392 if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
1393 {
1394 return i;
1395 }
1396 }
1397 LOG_ERROR("failed to find suitable memory type!");
1398 throw std::runtime_error("failed to find suitable memory type!");
1399}

◆ GenerateMipmaps()

void rendering_engine::VulkanRenderer::GenerateMipmaps ( VkImage  image,
VkFormat  imageFormat,
int32_t  texWidth,
int32_t  texHeight,
uint32_t  mipLevels 
)

Generates mipmaps for a given image resource.

Parameters
imageVulkan image handle.
imageFormatImage format (must support linear blitting).
texWidthTexture width in pixels.
texHeightTexture height in pixels.
mipLevelsNumber of mipmap levels to generate.

Definition at line 507 of file vulkan_renderer.cpp.

508{
509 // Check if image format supports linear blitting
510 VkFormatProperties formatProperties;
511 vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, imageFormat, &formatProperties);
512
513 if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
514 {
515 LOG_ERROR("texture image format does not support linear blitting!");
516 throw std::runtime_error("texture image format does not support linear blitting!");
517 }
518
519 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
520
521 VkImageMemoryBarrier barrier{};
522 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
523 barrier.image = image;
524 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
525 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
526 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
527 barrier.subresourceRange.baseArrayLayer = 0;
528 barrier.subresourceRange.layerCount = 1;
529 barrier.subresourceRange.levelCount = 1;
530
531 int32_t mipWidth = texWidth;
532 int32_t mipHeight = texHeight;
533
534 for (uint32_t i = 1; i < mipLevels; i++)
535 {
536 barrier.subresourceRange.baseMipLevel = i - 1;
537 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
538 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
539 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
540 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
541
542 vkCmdPipelineBarrier(commandBuffer,
543 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
544 0, nullptr,
545 0, nullptr,
546 1, &barrier);
547
548 VkImageBlit blit{};
549 blit.srcOffsets[0] = { 0, 0, 0 };
550 blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
551 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
552 blit.srcSubresource.mipLevel = i - 1;
553 blit.srcSubresource.baseArrayLayer = 0;
554 blit.srcSubresource.layerCount = 1;
555 blit.dstOffsets[0] = { 0, 0, 0 };
556 blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
557 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
558 blit.dstSubresource.mipLevel = i;
559 blit.dstSubresource.baseArrayLayer = 0;
560 blit.dstSubresource.layerCount = 1;
561
562 vkCmdBlitImage(commandBuffer,
563 image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
564 image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
565 1, &blit,
566 VK_FILTER_LINEAR);
567
568 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
569 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
570 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
571 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
572
573 vkCmdPipelineBarrier(commandBuffer,
574 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
575 0, nullptr,
576 0, nullptr,
577 1, &barrier);
578
579 if (mipWidth > 1) mipWidth /= 2;
580 if (mipHeight > 1) mipHeight /= 2;
581 }
582
583 barrier.subresourceRange.baseMipLevel = mipLevels - 1;
584 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
585 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
586 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
587 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
588
589 vkCmdPipelineBarrier(commandBuffer,
590 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
591 0, nullptr,
592 0, nullptr,
593 1, &barrier);
594
595 EndSingleTimeCommand(commandBuffer);
596}

◆ GetAttributeDescriptions() [1/7]

template<typename T >
static std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

Returns vertex attribute descriptions for a specific vertex type.

Template Parameters
TVertex type (e.g., Vertex2D, VertexPositionColorTexture, etc.).

◆ GetAttributeDescriptions() [2/7]

template<>
std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

◆ GetAttributeDescriptions() [3/7]

template<>
std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

◆ GetAttributeDescriptions() [4/7]

template<>
std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

◆ GetAttributeDescriptions() [5/7]

template<>
std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

Definition at line 1908 of file vulkan_renderer.cpp.

1919{
1920 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1921 attributeDescriptions.resize(3);
1922
1923 attributeDescriptions[0].binding = 0;
1924 attributeDescriptions[0].location = 0;
1925 attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
1926 attributeDescriptions[0].offset = offsetof(Vertex2D, position);
1927
1928 attributeDescriptions[1].binding = 0;
1929 attributeDescriptions[1].location = 1;
1930 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1931 attributeDescriptions[1].offset = offsetof(Vertex2D, color);
1932
1933 attributeDescriptions[2].binding = 0;
1934 attributeDescriptions[2].location = 2;
1935 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1936 attributeDescriptions[2].offset = offsetof(Vertex2D, textureCoordinates);
1937
1938 return attributeDescriptions;
1939}

◆ GetAttributeDescriptions() [6/7]

template<>
std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

Definition at line 1908 of file vulkan_renderer.cpp.

1943{
1944 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1945 attributeDescriptions.resize(3);
1946
1947 attributeDescriptions[0].binding = 0;
1948 attributeDescriptions[0].location = 0;
1949 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1950 attributeDescriptions[0].offset = offsetof(VertexPositionColorTexture, position);
1951
1952 attributeDescriptions[1].binding = 0;
1953 attributeDescriptions[1].location = 1;
1954 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1955 attributeDescriptions[1].offset = offsetof(VertexPositionColorTexture, color);
1956
1957 attributeDescriptions[2].binding = 0;
1958 attributeDescriptions[2].location = 2;
1959 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1960 attributeDescriptions[2].offset = offsetof(VertexPositionColorTexture, textureCoordinates);
1961
1962 return attributeDescriptions;
1963}

◆ GetAttributeDescriptions() [7/7]

template<>
std::vector< VkVertexInputAttributeDescription > rendering_engine::VulkanRenderer::GetAttributeDescriptions ( )
static

Definition at line 1908 of file vulkan_renderer.cpp.

1967{
1968 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1969 attributeDescriptions.resize(5);
1970
1971 attributeDescriptions[0].binding = 0;
1972 attributeDescriptions[0].location = 0;
1973 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1974 attributeDescriptions[0].offset = offsetof(VertexPositionColorTextureNormalTangent, position);
1975
1976 attributeDescriptions[1].binding = 0;
1977 attributeDescriptions[1].location = 1;
1978 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1979 attributeDescriptions[1].offset = offsetof(VertexPositionColorTextureNormalTangent, color);
1980
1981 attributeDescriptions[2].binding = 0;
1982 attributeDescriptions[2].location = 2;
1983 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1984 attributeDescriptions[2].offset = offsetof(VertexPositionColorTextureNormalTangent, textureCoordinates);
1985
1986 attributeDescriptions[3].binding = 0;
1987 attributeDescriptions[3].location = 3;
1988 attributeDescriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT;
1989 attributeDescriptions[3].offset = offsetof(VertexPositionColorTextureNormalTangent, normal);
1990
1991 attributeDescriptions[4].binding = 0;
1992 attributeDescriptions[4].location = 4;
1993 attributeDescriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT;
1994 attributeDescriptions[4].offset = offsetof(VertexPositionColorTextureNormalTangent, tangent);
1995
1996 return attributeDescriptions;
1997}

◆ GetBindingDescription()

template<typename T >
VkVertexInputBindingDescription rendering_engine::VulkanRenderer::GetBindingDescription
static

Returns a vertex input binding description for a specific vertex type.

Template Parameters
TVertex type (e.g., Vertex2D, VertexPositionColorTexture, etc.).

Definition at line 1908 of file vulkan_renderer.cpp.

1909{
1910 VkVertexInputBindingDescription binding{};
1911 binding.binding = 0;
1912 binding.stride = sizeof(T);
1913 binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1914 return binding;
1915}

◆ GetComandBuffers()

std::vector< VkCommandBuffer > rendering_engine::VulkanRenderer::GetComandBuffers ( )

Returns the collection of command buffers used for rendering.

Definition at line 1470 of file vulkan_renderer.cpp.

1471{
1472 return mCommandBuffers;
1473}

◆ GetCurrentFrame()

size_t rendering_engine::VulkanRenderer::GetCurrentFrame ( ) const
inline

Returns the index of the currently active frame in flight.

Definition at line 213 of file vulkan_renderer.hpp.

214 {
215 return mCurrentFrame;
216 }

◆ GetLogicalDevice()

VkDevice & rendering_engine::VulkanRenderer::GetLogicalDevice ( )

Returns reference to the logical Vulkan device.

Definition at line 396 of file vulkan_renderer.cpp.

397{
398 return mLogicalDevice;
399}

◆ GetPhysDevSupportedFeatures()

VkPhysicalDeviceFeatures & rendering_engine::VulkanRenderer::GetPhysDevSupportedFeatures ( )

Returns reference to the physical device�s supported features.

Definition at line 1406 of file vulkan_renderer.cpp.

1407{
1408 return mPhysDevSupportedFeatures;
1409}

◆ GetPhysicalDevice()

VkPhysicalDevice & rendering_engine::VulkanRenderer::GetPhysicalDevice ( )

Returns reference to the physical device.

Definition at line 1401 of file vulkan_renderer.cpp.

1402{
1403 return mPhysicalDevice;
1404}

◆ InitializeRenderer()

void rendering_engine::VulkanRenderer::InitializeRenderer ( )
overridevirtual

Initializes all rendering subsystems and GPU resources.

Implements rendering_engine::IRenderer.

Definition at line 45 of file vulkan_renderer.cpp.

46{
47 CreateInstance();
48 SetupDebugMessenger();
49 CreateSurface();
50 PickPhysicalDevice();
51 CreateLogicalDevice();
52
53 CreateSwapChain();
54 CreateImageViews();
55 CreateRenderPass();
56
57 CreateCommandPool();
58
59 CreateColorResources();
60 CreateDepthResources();
61
62 CreateFramebuffers();
63
64 CreateCommandBuffers();
65 CreateFrameSyncObjects();
66 CreateSwapchainSyncObjects();
67}

◆ ProvideMaterialRenderResources()

IMaterialRenderResources * rendering_engine::VulkanRenderer::ProvideMaterialRenderResources ( ) const
overridevirtual

Provides access to material-related GPU resources.

Returns
Pointer to the IMaterialRenderResources interface.

Implements rendering_engine::IRenderer.

Definition at line 331 of file vulkan_renderer.cpp.

332{
333 return new VulkanMaterialResources(const_cast<VulkanRenderer*>(this));
334}
VulkanRenderer(IWindowSystem &windowSystem)
Constructs a VulkanRenderer bound to a specific window system.

◆ ProvideMeshRenderResources()

IMeshRenderResources * rendering_engine::VulkanRenderer::ProvideMeshRenderResources ( ) const
overridevirtual

Provides access to mesh-related GPU resources.

Returns
Pointer to the IMeshRenderResources interface.

Implements rendering_engine::IRenderer.

Definition at line 336 of file vulkan_renderer.cpp.

337{
338 return new VulkanMeshResources(const_cast<VulkanRenderer*>(this));
339}

◆ ProvideRenderResources()

IRenderResources * rendering_engine::VulkanRenderer::ProvideRenderResources ( ) const
overridevirtual

Provides access to the general rendering resource manager.

Returns
Pointer to the IRenderResources interface.

Implements rendering_engine::IRenderer.

Definition at line 346 of file vulkan_renderer.cpp.

347{
348 return new VulkanRenderResources(const_cast<VulkanRenderer*>(this));
349}

◆ ProvideTextureRenderResources()

ITextureRenderResources * rendering_engine::VulkanRenderer::ProvideTextureRenderResources ( ) const
overridevirtual

Provides access to texture-related GPU resources.

Returns
Pointer to the ITextureRenderResources interface.

Implements rendering_engine::IRenderer.

Definition at line 326 of file vulkan_renderer.cpp.

327{
328 return new VulkanTextureResources(const_cast<VulkanRenderer*>(this));
329}

◆ RegisterObserver()

void rendering_engine::VulkanRenderer::RegisterObserver ( IRendererObserver notifier)
overridevirtual

Registers an observer for rendering events.

Parameters
notifierPointer to the observer to register.

Implements rendering_engine::IRenderer.

Definition at line 313 of file vulkan_renderer.cpp.

314{
315 if (std::find(mObservers.begin(), mObservers.end(), notifier) == mObservers.end())
316 {
317 mObservers.push_back(notifier);
318 }
319}

◆ SetDefaultColor()

void rendering_engine::VulkanRenderer::SetDefaultColor ( float  r,
float  g,
float  b 
)
overridevirtual

Sets the renderer clear color.

Parameters
rRed channel (linear space, [0.0–1.0])
gGreen channel (linear space, [0.0–1.0])
bBlue channel (linear space, [0.0–1.0])

Implements rendering_engine::IRenderer.

Definition at line 341 of file vulkan_renderer.cpp.

342{
343 mDefaultColor = glm::vec3(r, g, b);
344}

◆ ShutdownRenderer()

void rendering_engine::VulkanRenderer::ShutdownRenderer ( )
overridevirtual

Destroys and cleans up all rendering resources.

Implements rendering_engine::IRenderer.

Definition at line 285 of file vulkan_renderer.cpp.

286{
287 LOG_INFO("Shutting down Vulkan renderer...");
288 vkDeviceWaitIdle(mLogicalDevice);
289
290 mFrameSerial = std::numeric_limits<uint64_t>::max();
291 ProcessDeferredDestruction();
292
293 CleanupSwapChain();
294
295 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
296 {
297 vkDestroySemaphore(mLogicalDevice, mImageAvailableSemaphores[i], nullptr);
298 vkDestroyFence(mLogicalDevice, mInFlightFences[i], nullptr);
299 }
300
301 vkDestroyCommandPool(mLogicalDevice, mCommandPool, nullptr);
302
303 vkDestroyDevice(mLogicalDevice, nullptr);
305 {
306 DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr);
307 }
308 vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
309 vkDestroyInstance(mInstance, nullptr);
310 LOG_INFO("Vulkan renderer shutdown complete.");
311}
#define LOG_INFO(msg)
Definition: logger.hpp:39
const bool enableValidationLayers

◆ TransitionImageLayout()

void rendering_engine::VulkanRenderer::TransitionImageLayout ( VkImage  image,
VkFormat  format,
VkImageLayout  oldLayout,
VkImageLayout  newLayout,
std::uint32_t  mipmapLevels 
)

Transitions the image layout for a given Vulkan image.

Parameters
imageImage handle.
formatImage format.
oldLayoutCurrent image layout.
newLayoutDesired image layout.
mipmapLevelsNumber of mipmap levels to transition.

Definition at line 401 of file vulkan_renderer.cpp.

402{
403 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
404
405 VkImageMemoryBarrier barrier{};
406 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
407 barrier.oldLayout = oldLayout;
408 barrier.newLayout = newLayout;
409
410 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
411 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
412
413 barrier.image = image;
414 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
415 barrier.subresourceRange.baseMipLevel = 0;
416 barrier.subresourceRange.levelCount = mipmapLevels;
417 barrier.subresourceRange.baseArrayLayer = 0;
418 barrier.subresourceRange.layerCount = 1;
419
420 VkPipelineStageFlags sourceStage;
421 VkPipelineStageFlags destinationStage;
422
423 if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
424 {
425 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
426
427 if (HasStencilComponent(format))
428 {
429 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
430 }
431 }
432 else
433 {
434 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
435 }
436
437 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
438 barrier.srcAccessMask = 0;
439 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
440
441 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
442 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
443 }
444 else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
445 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
446 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
447
448 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
449 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
450 }
451 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
452 barrier.srcAccessMask = 0;
453 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
454
455 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
456 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
457 }
458 else {
459 throw std::invalid_argument("unsupported layout transition!");
460 }
461
462 vkCmdPipelineBarrier(
463 commandBuffer,
464 sourceStage, destinationStage,
465 0,
466 0, nullptr,
467 0, nullptr,
468 1, &barrier
469 );
470
471 EndSingleTimeCommand(commandBuffer);
472}

◆ UnregisterObserver()

void rendering_engine::VulkanRenderer::UnregisterObserver ( IRendererObserver notifier)
overridevirtual

Unregisters a previously registered observer.

Parameters
notifierPointer to the observer to remove.

Implements rendering_engine::IRenderer.

Definition at line 321 of file vulkan_renderer.cpp.

322{
323 mObservers.erase(std::remove(mObservers.begin(), mObservers.end(), notifier), mObservers.end());
324}

◆ WaitIdle()

void rendering_engine::VulkanRenderer::WaitIdle ( )
overridevirtual

Waits until the GPU has finished all pending rendering operations.

Implements rendering_engine::IRenderer.

Definition at line 280 of file vulkan_renderer.cpp.

281{
282 vkDeviceWaitIdle(mLogicalDevice);
283}

The documentation for this class was generated from the following files: