Rendering Engine 0.2.0
Modular Graphics Rendering Engine | v0.2.0
Loading...
Searching...
No Matches
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.
void InitializeRenderer () override
 Initializes all rendering subsystems and GPU resources.
void DrawFrame () override
 Executes a full frame rendering cycle.
bool BeginFrame () override
 Begins frame rendering operations.
void BeginRenderPass () override
 Begins the active render pass for the current frame.
void EndRenderPass () override
 Ends the active render pass.
void EndFrame () override
 Completes the current frame rendering and presents the result.
void WaitIdle () override
 Waits until the GPU has finished all pending rendering operations.
void ShutdownRenderer () override
 Destroys and cleans up all rendering resources.
void RegisterObserver (IRendererObserver *notifier) override
 Registers an observer for rendering events.
void UnregisterObserver (IRendererObserver *notifier) override
 Unregisters a previously registered observer.
IRenderResourcesProvideRenderResources () const override
 Provides access to the general rendering resource manager.
ITextureRenderResourcesProvideTextureRenderResources () const override
 Provides access to texture-related GPU resources.
IMaterialRenderResourcesProvideMaterialRenderResources () const override
 Provides access to material-related GPU resources.
IMeshRenderResourcesProvideMeshRenderResources () const override
 Provides access to mesh-related GPU resources.
void CreateBuffer (VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
 Creates a new Vulkan buffer with the specified usage and memory properties.
void CopyBuffer (VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
 Copies data from one buffer to another using a temporary command buffer.
VkDevice & GetLogicalDevice ()
 Returns reference to the logical Vulkan device.
void TransitionImageLayout (VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, std::uint32_t mipmapLevels)
 Transitions the image layout for a given Vulkan image.
void CopyBufferToImage (VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
 Copies buffer data into an image (used for uploading texture data).
void GenerateMipmaps (VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels)
 Generates mipmaps for a given image resource.
uint32_t FindMemoryType (uint32_t typeFilter, VkMemoryPropertyFlags properties)
 Finds a suitable memory type for a given allocation.
VkPhysicalDevice & GetPhysicalDevice ()
 Returns reference to the physical device.
VkPhysicalDeviceFeatures & GetPhysDevSupportedFeatures ()
 Returns reference to the physical device�s supported features.
VkDescriptorSetLayout CreateDescriptorSetLayout (Material *material)
 Creates a descriptor set layout corresponding to a given material.
size_t GetCurrentFrame () const
 Returns the index of the currently active frame in flight.
std::vector< VkCommandBuffer > GetComandBuffers ()
 Returns the collection of command buffers used for rendering.
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.
Public Member Functions inherited from rendering_engine::IRenderer
virtual ~IRenderer ()=default
 Virtual destructor for safe polymorphic deletion.

Static Public Member Functions

template<typename T>
static VkVertexInputBindingDescription GetBindingDescription ()
 Returns a vertex input binding description for a specific vertex type.
template<typename T>
static std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions ()
 Returns vertex attribute descriptions for a specific vertex type.
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 58 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 38 of file vulkan_renderer.cpp.

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

Member Function Documentation

◆ 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 143 of file vulkan_renderer.cpp.

144{
145 vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame], VK_TRUE, UINT64_MAX);
146
147 VkResult result = vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame], VK_NULL_HANDLE, &mImageIndex);
148
149 if (result == VK_ERROR_OUT_OF_DATE_KHR)
150 {
151 RecreateSwapChain();
152 return false;
153 }
154 else
155 {
156 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
157 {
158 throw std::runtime_error("failed to acquire swap chain image!");
159 }
160 }
161
162 vkResetFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame]);
163
164 vkResetCommandBuffer(mCommandBuffers[mCurrentFrame], /*VkCommandBufferResetFlagBits*/ 0);
165
166 return true;
167}

◆ BeginRenderPass()

void rendering_engine::VulkanRenderer::BeginRenderPass ( )
overridevirtual

Begins the active render pass for the current frame.

Implements rendering_engine::IRenderer.

Definition at line 169 of file vulkan_renderer.cpp.

170{
171 VkCommandBufferBeginInfo beginInfo{};
172 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
173 //beginInfo.flags = 0; // Optional
174 //beginInfo.pInheritanceInfo = nullptr; // Optional
175
176 if (vkBeginCommandBuffer(mCommandBuffers[mCurrentFrame], &beginInfo) != VK_SUCCESS)
177 {
178 throw std::runtime_error("failed to begin recording command buffer!");
179 }
180
181 VkRenderPassBeginInfo renderPassInfo{};
182 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
183 renderPassInfo.renderPass = mRenderPass;
184 renderPassInfo.framebuffer = mSwapChainFramebuffers[mImageIndex];
185
186 renderPassInfo.renderArea.offset = { 0, 0 };
187 renderPassInfo.renderArea.extent = mSwapChainExtent;
188
189 std::array<VkClearValue, 2> clearValues{};
190 clearValues[0].color = { {0.0f, 0.0f, 0.0f, 1.0f} };
191 clearValues[1].depthStencil = { 1.0f, 0 };
192 renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
193 renderPassInfo.pClearValues = clearValues.data();
194
195 vkCmdBeginRenderPass(mCommandBuffers[mCurrentFrame], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
196}

◆ 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 351 of file vulkan_renderer.cpp.

352{
353 auto commandBuffer = BeginSingleTimeCommand();
354
355 VkBufferCopy copyRegion{};
356 copyRegion.srcOffset = 0; // Optional
357 copyRegion.dstOffset = 0; // Optional
358 copyRegion.size = size;
359 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
360
361 EndSingleTimeCommand(commandBuffer);
362}

◆ 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 442 of file vulkan_renderer.cpp.

443{
444 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
445
446 VkBufferImageCopy region{};
447 region.bufferOffset = 0;
448 region.bufferRowLength = 0;
449 region.bufferImageHeight = 0;
450
451 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
452 region.imageSubresource.mipLevel = 0;
453 region.imageSubresource.baseArrayLayer = 0;
454 region.imageSubresource.layerCount = 1;
455
456 region.imageOffset = { 0, 0, 0 };
457 region.imageExtent = {
458 width,
459 height,
460 1
461 };
462
463 vkCmdCopyBufferToImage(
464 commandBuffer,
465 buffer,
466 image,
467 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
468 1,
469 &region
470 );
471
472 EndSingleTimeCommand(commandBuffer);
473}

◆ 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 321 of file vulkan_renderer.cpp.

322{
323 VkBufferCreateInfo bufferInfo{};
324 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
325 bufferInfo.size = size;
326
327 bufferInfo.usage = usage;
328 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
329
330 if (vkCreateBuffer(mLogicalDevice, &bufferInfo, nullptr, &buffer) != VK_SUCCESS)
331 {
332 throw std::runtime_error("failed to create vertex buffer!");
333 }
334
335 VkMemoryRequirements memRequirements;
336 vkGetBufferMemoryRequirements(mLogicalDevice, buffer, &memRequirements);
337
338 VkMemoryAllocateInfo allocInfo{};
339 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
340 allocInfo.allocationSize = memRequirements.size;
341 allocInfo.memoryTypeIndex = FindMemoryType(memRequirements.memoryTypeBits, properties);
342
343 if (vkAllocateMemory(mLogicalDevice, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS)
344 {
345 throw std::runtime_error("failed to allocate vertex buffer memory!");
346 }
347
348 vkBindBufferMemory(mLogicalDevice, buffer, bufferMemory, 0);
349}
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 1323 of file vulkan_renderer.cpp.

1324{
1325 std::uint32_t bindingNumber = 0;
1326 std::vector<VkDescriptorSetLayoutBinding> bindings;
1327
1328 // Uniform buffer to transmit transformation matrix
1329 VkDescriptorSetLayoutBinding uboLayoutBinding{};
1330 uboLayoutBinding.binding = bindingNumber;
1331 uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1332 uboLayoutBinding.descriptorCount = 1;
1333 uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1334 uboLayoutBinding.pImmutableSamplers = nullptr; // Optional
1335
1336 bindings.push_back(uboLayoutBinding);
1337
1338 PackedMaterialData packedMaterialData = material->PackMaterialParameters();
1339 if (!packedMaterialData.buffer.empty())
1340 {
1341 ++bindingNumber;
1342 // Uniform buffer to transmit custom material variables
1343 VkDescriptorSetLayoutBinding customMaterialVariables;
1344 customMaterialVariables.binding = bindingNumber;
1345 customMaterialVariables.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1346 customMaterialVariables.descriptorCount = 1;
1347 customMaterialVariables.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1348 customMaterialVariables.pImmutableSamplers = nullptr; // Optional
1349
1350 bindings.push_back(customMaterialVariables);
1351 }
1352
1353 for (const auto& textureName : material->GetTextures())
1354 {
1355 (void)textureName;
1356 ++bindingNumber;
1357 VkDescriptorSetLayoutBinding samplerLayoutBinding{};
1358 samplerLayoutBinding.binding = bindingNumber;
1359 samplerLayoutBinding.descriptorCount = 1;
1360 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1361 samplerLayoutBinding.pImmutableSamplers = nullptr;
1362 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1363
1364 bindings.push_back(samplerLayoutBinding);
1365 }
1366
1367 VkDescriptorSetLayoutCreateInfo layoutInfo{};
1368 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1369 layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
1370 layoutInfo.pBindings = bindings.data();
1371
1372 VkDescriptorSetLayout result;
1373 if (vkCreateDescriptorSetLayout(mLogicalDevice, &layoutInfo, nullptr, &result) != VK_SUCCESS)
1374 {
1375 throw std::runtime_error("failed to create descriptor set layout!");
1376 }
1377
1378 return result;
1379}

◆ 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 1386 of file vulkan_renderer.cpp.

1387{
1388 VkPipelineLayout pipelineLayout;
1389 VkPipeline pipeline;
1390
1391 VkShaderModule vertShaderModule = CreateShaderModule(spvVertShaderCode);
1392 VkShaderModule fragShaderModule = CreateShaderModule(spvFragShaderCode);
1393
1394 VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
1395 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1396 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
1397
1398 vertShaderStageInfo.module = vertShaderModule;
1399 vertShaderStageInfo.pName = "main";
1400
1401 VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
1402 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1403 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1404 fragShaderStageInfo.module = fragShaderModule;
1405 fragShaderStageInfo.pName = "main";
1406
1407 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
1408
1409 VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
1410 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1411
1412 VkVertexInputBindingDescription bindingDescription;
1413 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1414
1415 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
1416 {
1417 bindingDescription = GetBindingDescription<Vertex2D>();
1418 attributeDescriptions = GetAttributeDescriptions<Vertex2D>();
1419 }
1420 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Surface3D)
1421 {
1424 }
1425
1426 vertexInputInfo.vertexBindingDescriptionCount = 1;
1427 vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
1428
1429 vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
1430 vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
1431
1432 VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
1433 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1434 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1435 inputAssembly.primitiveRestartEnable = VK_FALSE;
1436
1437 VkViewport viewport{};
1438 viewport.x = 0.0f;
1439 viewport.y = 0.0f;
1440 viewport.width = (float)mSwapChainExtent.width;
1441 viewport.height = (float)mSwapChainExtent.height;
1442 viewport.minDepth = 0.0f;
1443 viewport.maxDepth = 1.0f;
1444
1445 VkRect2D scissor{};
1446 scissor.offset = { 0, 0 };
1447 scissor.extent = mSwapChainExtent;
1448
1449 VkPipelineViewportStateCreateInfo viewportState{};
1450 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1451 viewportState.viewportCount = 1;
1452 viewportState.pViewports = &viewport;
1453 viewportState.scissorCount = 1;
1454 viewportState.pScissors = &scissor;
1455
1456 VkPipelineRasterizationStateCreateInfo rasterizer{};
1457 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1458 rasterizer.depthClampEnable = VK_FALSE;
1459 rasterizer.rasterizerDiscardEnable = VK_FALSE;
1460 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
1461 rasterizer.lineWidth = 1.0f;
1462 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
1463 {
1464 rasterizer.cullMode = VK_CULL_MODE_NONE;
1465 }
1466 else
1467 {
1468 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
1469 }
1470 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
1471 rasterizer.depthBiasEnable = VK_FALSE;
1472 rasterizer.depthBiasConstantFactor = 0.0f; // Optional
1473 rasterizer.depthBiasClamp = 0.0f; // Optional
1474 rasterizer.depthBiasSlopeFactor = 0.0f; // Optional
1475
1476 VkPipelineMultisampleStateCreateInfo multisampling{};
1477 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1478 multisampling.sampleShadingEnable = VK_FALSE;
1479 multisampling.rasterizationSamples = mMSAASamples;
1480 multisampling.minSampleShading = 1.0f; // Optional
1481 multisampling.pSampleMask = nullptr; // Optional
1482 multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
1483 multisampling.alphaToOneEnable = VK_FALSE; // Optional
1484
1485 VkPipelineColorBlendAttachmentState colorBlendAttachment{};
1486 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
1487 colorBlendAttachment.blendEnable = (material->GetMaterialSettings().blendMode == BlendMode::Translucent) ? VK_TRUE : VK_FALSE;
1488 colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
1489 colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
1490 colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; // Optional
1491 colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
1492 colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
1493 colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
1494
1495 VkPipelineColorBlendStateCreateInfo colorBlending{};
1496 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1497 colorBlending.logicOpEnable = VK_FALSE;
1498 colorBlending.logicOp = VK_LOGIC_OP_COPY; // Optional
1499 colorBlending.attachmentCount = 1;
1500 colorBlending.pAttachments = &colorBlendAttachment;
1501 colorBlending.blendConstants[0] = 0.0f; // Optional
1502 colorBlending.blendConstants[1] = 0.0f; // Optional
1503 colorBlending.blendConstants[2] = 0.0f; // Optional
1504 colorBlending.blendConstants[3] = 0.0f; // Optional
1505
1506 // To use dynamicState, assign reference to it in pipelineInfo.pDynamicState.
1507 std::vector<VkDynamicState> dynamicStates = {
1508 VK_DYNAMIC_STATE_VIEWPORT,
1509 VK_DYNAMIC_STATE_SCISSOR
1510 };
1511 VkPipelineDynamicStateCreateInfo dynamicState{};
1512 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1513 dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
1514 dynamicState.pDynamicStates = dynamicStates.data();
1515
1516 VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
1517 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
1518 pipelineLayoutInfo.setLayoutCount = 1;
1519 pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
1520
1521 if (vkCreatePipelineLayout(mLogicalDevice, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS)
1522 {
1523 throw std::runtime_error("failed to create pipeline layout!");
1524 }
1525
1526 VkPipelineDepthStencilStateCreateInfo depthStencil{};
1527 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1528 if (material->GetMaterialSettings().materialDomain == MaterialDomain::Sprite2D)
1529 {
1530 depthStencil.depthTestEnable = VK_FALSE;
1531 depthStencil.depthWriteEnable = VK_FALSE;
1532 }
1533 else
1534 {
1535 depthStencil.depthTestEnable = VK_TRUE;
1536 depthStencil.depthWriteEnable = (material->GetMaterialSettings().blendMode == BlendMode::Opaque) ? VK_TRUE : VK_FALSE;
1537 }
1538 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
1539 depthStencil.depthBoundsTestEnable = VK_FALSE;
1540 //depthStencil.minDepthBounds = 0.0f; // Optional
1541 //depthStencil.maxDepthBounds = 1.0f; // Optional
1542 depthStencil.stencilTestEnable = VK_FALSE;
1543 //depthStencil.front = {}; // Optional
1544 depthStencil.back = {}; // Optional
1545
1546 VkGraphicsPipelineCreateInfo pipelineInfo{};
1547 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1548 pipelineInfo.stageCount = 2;
1549 pipelineInfo.pStages = shaderStages;
1550 pipelineInfo.pVertexInputState = &vertexInputInfo;
1551 pipelineInfo.pInputAssemblyState = &inputAssembly;
1552 pipelineInfo.pViewportState = &viewportState;
1553 pipelineInfo.pRasterizationState = &rasterizer;
1554 pipelineInfo.pMultisampleState = &multisampling;
1555 pipelineInfo.pDepthStencilState = &depthStencil;
1556 pipelineInfo.pColorBlendState = &colorBlending;
1557 pipelineInfo.pDynamicState = nullptr;
1558 pipelineInfo.layout = pipelineLayout;
1559 pipelineInfo.renderPass = mRenderPass;
1560 pipelineInfo.subpass = 0;
1561 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
1562 pipelineInfo.basePipelineIndex = -1; // Optional
1563
1564
1565 if (vkCreateGraphicsPipelines(mLogicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeline) != VK_SUCCESS)
1566 {
1567 throw std::runtime_error("failed to create graphics pipeline!");
1568 }
1569 vkDestroyShaderModule(mLogicalDevice, fragShaderModule, nullptr);
1570 vkDestroyShaderModule(mLogicalDevice, vertShaderModule, nullptr);
1571
1572 return std::pair<VkPipelineLayout, VkPipeline>(pipelineLayout, pipeline);
1573}
static std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions()
Returns vertex attribute descriptions for a specific vertex type.
static VkVertexInputBindingDescription GetBindingDescription()
Returns a vertex input binding description for a specific vertex type.

◆ DrawFrame()

void rendering_engine::VulkanRenderer::DrawFrame ( )
overridevirtual

Executes a full frame rendering cycle.

Implements rendering_engine::IRenderer.

Definition at line 67 of file vulkan_renderer.cpp.

68{
69 vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame], VK_TRUE, UINT64_MAX);
70
71 uint32_t imageIndex;
72 VkResult result = vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame], VK_NULL_HANDLE, &imageIndex);
73
74 if (result == VK_ERROR_OUT_OF_DATE_KHR)
75 {
76 RecreateSwapChain();
77 return;
78 }
79 else
80 {
81 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
82 {
83 throw std::runtime_error("failed to acquire swap chain image!");
84 }
85 }
86
87 vkResetFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame]);
88
89 vkResetCommandBuffer(mCommandBuffers[mCurrentFrame], /*VkCommandBufferResetFlagBits*/ 0);
90 RecordCommandBuffer(mCommandBuffers[mCurrentFrame], imageIndex);
91
92 VkSubmitInfo submitInfo{};
93 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
94
95 VkSemaphore waitSemaphores[] = { mImageAvailableSemaphores[mCurrentFrame] };
96 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
97 submitInfo.waitSemaphoreCount = 1;
98 submitInfo.pWaitSemaphores = waitSemaphores;
99 submitInfo.pWaitDstStageMask = waitStages;
100
101 submitInfo.commandBufferCount = 1;
102 submitInfo.pCommandBuffers = &mCommandBuffers[mCurrentFrame];
103
104 VkSemaphore signalSemaphores[] = { mRenderFinishedSemaphores[mCurrentFrame] };
105 submitInfo.signalSemaphoreCount = 1;
106 submitInfo.pSignalSemaphores = signalSemaphores;
107
108 if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[mCurrentFrame]) != VK_SUCCESS)
109 {
110 throw std::runtime_error("failed to submit draw command buffer!");
111 }
112
113 VkPresentInfoKHR presentInfo{};
114 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
115
116 presentInfo.waitSemaphoreCount = 1;
117 presentInfo.pWaitSemaphores = signalSemaphores;
118
119 VkSwapchainKHR swapChains[] = { mSwapChain };
120 presentInfo.swapchainCount = 1;
121 presentInfo.pSwapchains = swapChains;
122
123 presentInfo.pImageIndices = &imageIndex;
124
125 result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
126
127 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mWindowSystem.IsFramebufferResized())
128 {
129 mWindowSystem.ResetFramebufferResizedFlag();
130 RecreateSwapChain();
131 }
132 else
133 {
134 if (result != VK_SUCCESS)
135 {
136 throw std::runtime_error("failed to present swap chain image!");
137 }
138 }
139
140 mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
141}
const int MAX_FRAMES_IN_FLIGHT
Number of frames that can be processed simultaneously (double buffering).

◆ EndFrame()

void rendering_engine::VulkanRenderer::EndFrame ( )
overridevirtual

Completes the current frame rendering and presents the result.

Implements rendering_engine::IRenderer.

Definition at line 203 of file vulkan_renderer.cpp.

204{
205 if (vkEndCommandBuffer(mCommandBuffers[mCurrentFrame]) != VK_SUCCESS)
206 {
207 throw std::runtime_error("failed to record command buffer!");
208 }
209
210 VkSubmitInfo submitInfo{};
211 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
212
213 VkSemaphore waitSemaphores[] = { mImageAvailableSemaphores[mCurrentFrame] };
214 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
215 submitInfo.waitSemaphoreCount = 1;
216 submitInfo.pWaitSemaphores = waitSemaphores;
217 submitInfo.pWaitDstStageMask = waitStages;
218
219 submitInfo.commandBufferCount = 1;
220 submitInfo.pCommandBuffers = &mCommandBuffers[mCurrentFrame];
221
222 VkSemaphore signalSemaphores[] = { mRenderFinishedSemaphores[mCurrentFrame] };
223 submitInfo.signalSemaphoreCount = 1;
224 submitInfo.pSignalSemaphores = signalSemaphores;
225
226 if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[mCurrentFrame]) != VK_SUCCESS)
227 {
228 throw std::runtime_error("failed to submit draw command buffer!");
229 }
230
231 VkPresentInfoKHR presentInfo{};
232 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
233
234 presentInfo.waitSemaphoreCount = 1;
235 presentInfo.pWaitSemaphores = signalSemaphores;
236
237 VkSwapchainKHR swapChains[] = { mSwapChain };
238 presentInfo.swapchainCount = 1;
239 presentInfo.pSwapchains = swapChains;
240
241 presentInfo.pImageIndices = &mImageIndex;
242
243 VkResult result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
244
245 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mWindowSystem.IsFramebufferResized())
246 {
247 mWindowSystem.ResetFramebufferResizedFlag();
248 RecreateSwapChain();
249 }
250 else
251 {
252 if (result != VK_SUCCESS)
253 {
254 throw std::runtime_error("failed to present swap chain image!");
255 }
256 }
257
258 mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
259}

◆ EndRenderPass()

void rendering_engine::VulkanRenderer::EndRenderPass ( )
overridevirtual

Ends the active render pass.

Implements rendering_engine::IRenderer.

Definition at line 198 of file vulkan_renderer.cpp.

199{
200 vkCmdEndRenderPass(mCommandBuffers[mCurrentFrame]);
201}

◆ 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 1297 of file vulkan_renderer.cpp.

1298{
1299 VkPhysicalDeviceMemoryProperties memProperties;
1300 vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memProperties);
1301
1302 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
1303 {
1304 if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
1305 {
1306 return i;
1307 }
1308 }
1309
1310 throw std::runtime_error("failed to find suitable memory type!");
1311}

◆ 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 475 of file vulkan_renderer.cpp.

476{
477 // Check if image format supports linear blitting
478 VkFormatProperties formatProperties;
479 vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, imageFormat, &formatProperties);
480
481 if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
482 {
483 throw std::runtime_error("texture image format does not support linear blitting!");
484 }
485
486 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
487
488 VkImageMemoryBarrier barrier{};
489 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
490 barrier.image = image;
491 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
492 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
493 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
494 barrier.subresourceRange.baseArrayLayer = 0;
495 barrier.subresourceRange.layerCount = 1;
496 barrier.subresourceRange.levelCount = 1;
497
498 int32_t mipWidth = texWidth;
499 int32_t mipHeight = texHeight;
500
501 for (uint32_t i = 1; i < mipLevels; i++)
502 {
503 barrier.subresourceRange.baseMipLevel = i - 1;
504 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
505 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
506 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
507 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
508
509 vkCmdPipelineBarrier(commandBuffer,
510 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
511 0, nullptr,
512 0, nullptr,
513 1, &barrier);
514
515 VkImageBlit blit{};
516 blit.srcOffsets[0] = { 0, 0, 0 };
517 blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
518 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
519 blit.srcSubresource.mipLevel = i - 1;
520 blit.srcSubresource.baseArrayLayer = 0;
521 blit.srcSubresource.layerCount = 1;
522 blit.dstOffsets[0] = { 0, 0, 0 };
523 blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
524 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
525 blit.dstSubresource.mipLevel = i;
526 blit.dstSubresource.baseArrayLayer = 0;
527 blit.dstSubresource.layerCount = 1;
528
529 vkCmdBlitImage(commandBuffer,
530 image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
531 image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
532 1, &blit,
533 VK_FILTER_LINEAR);
534
535 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
536 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
537 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
538 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
539
540 vkCmdPipelineBarrier(commandBuffer,
541 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
542 0, nullptr,
543 0, nullptr,
544 1, &barrier);
545
546 if (mipWidth > 1) mipWidth /= 2;
547 if (mipHeight > 1) mipHeight /= 2;
548 }
549
550 barrier.subresourceRange.baseMipLevel = mipLevels - 1;
551 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
552 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
553 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
554 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
555
556 vkCmdPipelineBarrier(commandBuffer,
557 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
558 0, nullptr,
559 0, nullptr,
560 1, &barrier);
561
562 EndSingleTimeCommand(commandBuffer);
563}

◆ GetAttributeDescriptions() [1/7]

template<typename T>
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 1767 of file vulkan_renderer.cpp.

1778{
1779 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1780 attributeDescriptions.resize(3);
1781
1782 attributeDescriptions[0].binding = 0;
1783 attributeDescriptions[0].location = 0;
1784 attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
1785 attributeDescriptions[0].offset = offsetof(Vertex2D, position);
1786
1787 attributeDescriptions[1].binding = 0;
1788 attributeDescriptions[1].location = 1;
1789 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1790 attributeDescriptions[1].offset = offsetof(Vertex2D, color);
1791
1792 attributeDescriptions[2].binding = 0;
1793 attributeDescriptions[2].location = 2;
1794 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1795 attributeDescriptions[2].offset = offsetof(Vertex2D, textureCoordinates);
1796
1797 return attributeDescriptions;
1798}

◆ GetAttributeDescriptions() [6/7]

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

Definition at line 1767 of file vulkan_renderer.cpp.

1802{
1803 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1804 attributeDescriptions.resize(3);
1805
1806 attributeDescriptions[0].binding = 0;
1807 attributeDescriptions[0].location = 0;
1808 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1809 attributeDescriptions[0].offset = offsetof(VertexPositionColorTexture, position);
1810
1811 attributeDescriptions[1].binding = 0;
1812 attributeDescriptions[1].location = 1;
1813 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1814 attributeDescriptions[1].offset = offsetof(VertexPositionColorTexture, color);
1815
1816 attributeDescriptions[2].binding = 0;
1817 attributeDescriptions[2].location = 2;
1818 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1819 attributeDescriptions[2].offset = offsetof(VertexPositionColorTexture, textureCoordinates);
1820
1821 return attributeDescriptions;
1822}

◆ GetAttributeDescriptions() [7/7]

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

Definition at line 1767 of file vulkan_renderer.cpp.

1826{
1827 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1828 attributeDescriptions.resize(5);
1829
1830 attributeDescriptions[0].binding = 0;
1831 attributeDescriptions[0].location = 0;
1832 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1833 attributeDescriptions[0].offset = offsetof(VertexPositionColorTextureNormalTangent, position);
1834
1835 attributeDescriptions[1].binding = 0;
1836 attributeDescriptions[1].location = 1;
1837 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1838 attributeDescriptions[1].offset = offsetof(VertexPositionColorTextureNormalTangent, color);
1839
1840 attributeDescriptions[2].binding = 0;
1841 attributeDescriptions[2].location = 2;
1842 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1843 attributeDescriptions[2].offset = offsetof(VertexPositionColorTextureNormalTangent, textureCoordinates);
1844
1845 attributeDescriptions[3].binding = 0;
1846 attributeDescriptions[3].location = 3;
1847 attributeDescriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT;
1848 attributeDescriptions[3].offset = offsetof(VertexPositionColorTextureNormalTangent, normal);
1849
1850 attributeDescriptions[4].binding = 0;
1851 attributeDescriptions[4].location = 4;
1852 attributeDescriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT;
1853 attributeDescriptions[4].offset = offsetof(VertexPositionColorTextureNormalTangent, tangent);
1854
1855 return attributeDescriptions;
1856}

◆ 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 1767 of file vulkan_renderer.cpp.

1768{
1769 VkVertexInputBindingDescription binding{};
1770 binding.binding = 0;
1771 binding.stride = sizeof(T);
1772 binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1773 return binding;
1774}

◆ GetComandBuffers()

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

Returns the collection of command buffers used for rendering.

Definition at line 1381 of file vulkan_renderer.cpp.

1382{
1383 return mCommandBuffers;
1384}

◆ GetCurrentFrame()

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

Returns the index of the currently active frame in flight.

Definition at line 180 of file vulkan_renderer.hpp.

181 {
182 return mCurrentFrame;
183 }

◆ GetLogicalDevice()

VkDevice & rendering_engine::VulkanRenderer::GetLogicalDevice ( )

Returns reference to the logical Vulkan device.

Definition at line 364 of file vulkan_renderer.cpp.

365{
366 return mLogicalDevice;
367}

◆ GetPhysDevSupportedFeatures()

VkPhysicalDeviceFeatures & rendering_engine::VulkanRenderer::GetPhysDevSupportedFeatures ( )

Returns reference to the physical device�s supported features.

Definition at line 1318 of file vulkan_renderer.cpp.

1319{
1320 return mPhysDevSupportedFeatures;
1321}

◆ GetPhysicalDevice()

VkPhysicalDevice & rendering_engine::VulkanRenderer::GetPhysicalDevice ( )

Returns reference to the physical device.

Definition at line 1313 of file vulkan_renderer.cpp.

1314{
1315 return mPhysicalDevice;
1316}

◆ InitializeRenderer()

void rendering_engine::VulkanRenderer::InitializeRenderer ( )
overridevirtual

Initializes all rendering subsystems and GPU resources.

Implements rendering_engine::IRenderer.

Definition at line 44 of file vulkan_renderer.cpp.

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

◆ 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 306 of file vulkan_renderer.cpp.

307{
308 return new VulkanMaterialResources(const_cast<VulkanRenderer*>(this));
309}
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 311 of file vulkan_renderer.cpp.

312{
313 return new VulkanMeshResources(const_cast<VulkanRenderer*>(this));
314}

◆ 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 316 of file vulkan_renderer.cpp.

317{
318 return new VulkanRenderResources(const_cast<VulkanRenderer*>(this));
319}

◆ 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 301 of file vulkan_renderer.cpp.

302{
303 return new VulkanTextureResources(const_cast<VulkanRenderer*>(this));
304}

◆ 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 288 of file vulkan_renderer.cpp.

289{
290 if (std::find(mObservers.begin(), mObservers.end(), notifier) == mObservers.end())
291 {
292 mObservers.push_back(notifier);
293 }
294}

◆ ShutdownRenderer()

void rendering_engine::VulkanRenderer::ShutdownRenderer ( )
overridevirtual

Destroys and cleans up all rendering resources.

Implements rendering_engine::IRenderer.

Definition at line 266 of file vulkan_renderer.cpp.

267{
268 CleanupSwapChain();
269
270 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
271 {
272 vkDestroySemaphore(mLogicalDevice, mRenderFinishedSemaphores[i], nullptr);
273 vkDestroySemaphore(mLogicalDevice, mImageAvailableSemaphores[i], nullptr);
274 vkDestroyFence(mLogicalDevice, mInFlightFences[i], nullptr);
275 }
276
277 vkDestroyCommandPool(mLogicalDevice, mCommandPool, nullptr);
278
279 vkDestroyDevice(mLogicalDevice, nullptr);
281 {
282 DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr);
283 }
284 vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
285 vkDestroyInstance(mInstance, nullptr);
286}
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 369 of file vulkan_renderer.cpp.

370{
371 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
372
373 VkImageMemoryBarrier barrier{};
374 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
375 barrier.oldLayout = oldLayout;
376 barrier.newLayout = newLayout;
377
378 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
379 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
380
381 barrier.image = image;
382 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
383 barrier.subresourceRange.baseMipLevel = 0;
384 barrier.subresourceRange.levelCount = mipmapLevels;
385 barrier.subresourceRange.baseArrayLayer = 0;
386 barrier.subresourceRange.layerCount = 1;
387
388 VkPipelineStageFlags sourceStage;
389 VkPipelineStageFlags destinationStage;
390
391 if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
392 {
393 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
394
395 if (HasStencilComponent(format))
396 {
397 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
398 }
399 }
400 else
401 {
402 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
403 }
404
405 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
406 barrier.srcAccessMask = 0;
407 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
408
409 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
410 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
411 }
412 else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
413 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
414 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
415
416 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
417 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
418 }
419 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
420 barrier.srcAccessMask = 0;
421 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
422
423 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
424 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
425 }
426 else {
427 throw std::invalid_argument("unsupported layout transition!");
428 }
429
430 vkCmdPipelineBarrier(
431 commandBuffer,
432 sourceStage, destinationStage,
433 0,
434 0, nullptr,
435 0, nullptr,
436 1, &barrier
437 );
438
439 EndSingleTimeCommand(commandBuffer);
440}

◆ 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 296 of file vulkan_renderer.cpp.

297{
298 mObservers.erase(std::remove(mObservers.begin(), mObservers.end(), notifier), mObservers.end());
299}

◆ WaitIdle()

void rendering_engine::VulkanRenderer::WaitIdle ( )
overridevirtual

Waits until the GPU has finished all pending rendering operations.

Implements rendering_engine::IRenderer.

Definition at line 261 of file vulkan_renderer.cpp.

262{
263 vkDeviceWaitIdle(mLogicalDevice);
264}

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