LCOV - code coverage report
Current view: top level - source/renderer/backend/vulkan - DeviceCommandContext.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 506 0.2 %
Date: 2023-01-19 00:18:29 Functions: 2 48 4.2 %

          Line data    Source code
       1             : /* Copyright (C) 2023 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "DeviceCommandContext.h"
      21             : 
      22             : #include "maths/MathUtil.h"
      23             : #include "ps/CLogger.h"
      24             : #include "ps/containers/Span.h"
      25             : #include "ps/containers/StaticVector.h"
      26             : #include "renderer/backend/vulkan/Buffer.h"
      27             : #include "renderer/backend/vulkan/DescriptorManager.h"
      28             : #include "renderer/backend/vulkan/Device.h"
      29             : #include "renderer/backend/vulkan/Framebuffer.h"
      30             : #include "renderer/backend/vulkan/PipelineState.h"
      31             : #include "renderer/backend/vulkan/RingCommandContext.h"
      32             : #include "renderer/backend/vulkan/ShaderProgram.h"
      33             : #include "renderer/backend/vulkan/Texture.h"
      34             : #include "renderer/backend/vulkan/Utilities.h"
      35             : 
      36             : #include <algorithm>
      37             : 
      38             : namespace Renderer
      39             : {
      40             : 
      41             : namespace Backend
      42             : {
      43             : 
      44             : namespace Vulkan
      45             : {
      46             : 
      47             : namespace
      48             : {
      49             : 
      50             : constexpr uint32_t UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024;
      51             : constexpr uint32_t FRAME_INPLACE_BUFFER_SIZE = 1024 * 1024;
      52             : 
      53             : struct SBaseImageState
      54             : {
      55             :     VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
      56             :     VkAccessFlags accessMask = 0;
      57             :     VkPipelineStageFlags stageMask = 0;
      58             : };
      59             : 
      60           0 : SBaseImageState GetBaseImageState(CTexture* texture)
      61             : {
      62           0 :     if (texture->GetUsage() & ITexture::Usage::SAMPLED)
      63             :     {
      64             :         return {
      65             :             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
      66             :             VK_ACCESS_SHADER_READ_BIT,
      67           0 :             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT};
      68             :     }
      69           0 :     else if (texture->GetUsage() & ITexture::Usage::COLOR_ATTACHMENT)
      70             :     {
      71             :         return {
      72             :             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
      73             :             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
      74           0 :             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
      75             :     }
      76           0 :     else if (texture->GetUsage() & ITexture::Usage::DEPTH_STENCIL_ATTACHMENT)
      77             :     {
      78             :         return {
      79             :             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
      80             :             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
      81           0 :             VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT};
      82             :     }
      83           0 :     return {};
      84             : }
      85             : 
      86             : class ScopedImageLayoutTransition
      87             : {
      88             : public:
      89           0 :     ScopedImageLayoutTransition(
      90             :         CRingCommandContext& commandContext, const PS::span<CTexture* const> textures,
      91             :         const VkImageLayout layout, const VkAccessFlags accessMask, const VkPipelineStageFlags stageMask)
      92           0 :         : m_CommandContext(commandContext), m_Textures(textures), m_Layout(layout),
      93           0 :         m_AccessMask(accessMask), m_StageMask(stageMask)
      94             :     {
      95           0 :         for (CTexture* const texture : m_Textures)
      96             :         {
      97           0 :             const auto state = GetBaseImageState(texture);
      98             : 
      99           0 :             VkImageLayout oldLayout = state.layout;
     100           0 :             if (!texture->IsInitialized())
     101           0 :                 oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     102             : 
     103           0 :             Utilities::SetTextureLayout(
     104           0 :                 m_CommandContext.GetCommandBuffer(), texture,
     105           0 :                 oldLayout, m_Layout,
     106           0 :                 state.accessMask, m_AccessMask, state.stageMask, m_StageMask);
     107             :         }
     108           0 :     }
     109             : 
     110           0 :     ~ScopedImageLayoutTransition()
     111           0 :     {
     112           0 :         for (CTexture* const texture : m_Textures)
     113             :         {
     114           0 :             const auto state = GetBaseImageState(texture);
     115             : 
     116           0 :             Utilities::SetTextureLayout(
     117           0 :                 m_CommandContext.GetCommandBuffer(), texture,
     118           0 :                 m_Layout, state.layout,
     119           0 :                 m_AccessMask, state.accessMask, m_StageMask, state.stageMask);
     120             :         }
     121           0 :     }
     122             : 
     123             : private:
     124             :     CRingCommandContext& m_CommandContext;
     125             :     const PS::span<CTexture* const> m_Textures;
     126             :     const VkImageLayout m_Layout = VK_IMAGE_LAYOUT_UNDEFINED;
     127             :     const VkAccessFlags m_AccessMask = 0;
     128             :     const VkPipelineStageFlags m_StageMask = 0;
     129             : };
     130             : 
     131             : } // anonymous namespace
     132             : 
     133             : // static
     134           0 : std::unique_ptr<IDeviceCommandContext> CDeviceCommandContext::Create(CDevice* device)
     135             : {
     136           0 :     std::unique_ptr<CDeviceCommandContext> deviceCommandContext(new CDeviceCommandContext());
     137           0 :     deviceCommandContext->m_Device = device;
     138           0 :     deviceCommandContext->m_DebugScopedLabels = device->GetCapabilities().debugScopedLabels;
     139           0 :     deviceCommandContext->m_PrependCommandContext =
     140           0 :         device->CreateRingCommandContext(NUMBER_OF_FRAMES_IN_FLIGHT);
     141           0 :     deviceCommandContext->m_CommandContext =
     142           0 :         device->CreateRingCommandContext(NUMBER_OF_FRAMES_IN_FLIGHT);
     143             : 
     144           0 :     deviceCommandContext->m_InPlaceVertexBuffer = device->CreateCBuffer(
     145           0 :         "InPlaceVertexBuffer", IBuffer::Type::VERTEX, FRAME_INPLACE_BUFFER_SIZE, true);
     146           0 :     deviceCommandContext->m_InPlaceIndexBuffer = device->CreateCBuffer(
     147           0 :         "InPlaceIndexBuffer", IBuffer::Type::INDEX, FRAME_INPLACE_BUFFER_SIZE, true);
     148             : 
     149           0 :     deviceCommandContext->m_InPlaceVertexStagingBuffer = device->CreateCBuffer(
     150           0 :         "InPlaceVertexStagingBuffer", IBuffer::Type::UPLOAD, NUMBER_OF_FRAMES_IN_FLIGHT * FRAME_INPLACE_BUFFER_SIZE, true);
     151           0 :     deviceCommandContext->m_InPlaceIndexStagingBuffer = device->CreateCBuffer(
     152           0 :         "InPlaceIndexStagingBuffer", IBuffer::Type::UPLOAD, NUMBER_OF_FRAMES_IN_FLIGHT * FRAME_INPLACE_BUFFER_SIZE, true);
     153             : 
     154           0 :     deviceCommandContext->m_UniformBuffer = device->CreateCBuffer(
     155           0 :         "UniformBuffer", IBuffer::Type::UNIFORM, UNIFORM_BUFFER_SIZE, true);
     156           0 :     deviceCommandContext->m_UniformStagingBuffer = device->CreateCBuffer(
     157           0 :         "UniformStagingBuffer", IBuffer::Type::UPLOAD, NUMBER_OF_FRAMES_IN_FLIGHT * UNIFORM_BUFFER_SIZE, true);
     158             : 
     159           0 :     deviceCommandContext->m_InPlaceVertexStagingBufferMappedData =
     160           0 :         deviceCommandContext->m_InPlaceVertexStagingBuffer->GetMappedData();
     161           0 :     ENSURE(deviceCommandContext->m_InPlaceVertexStagingBufferMappedData);
     162           0 :     deviceCommandContext->m_InPlaceIndexStagingBufferMappedData =
     163           0 :         deviceCommandContext->m_InPlaceIndexStagingBuffer->GetMappedData();
     164           0 :     ENSURE(deviceCommandContext->m_InPlaceIndexStagingBufferMappedData);
     165           0 :     deviceCommandContext->m_UniformStagingBufferMappedData =
     166           0 :         deviceCommandContext->m_UniformStagingBuffer->GetMappedData();
     167           0 :     ENSURE(deviceCommandContext->m_UniformStagingBufferMappedData);
     168             : 
     169             :     // TODO: reduce the code duplication.
     170           0 :     VkDescriptorPoolSize descriptorPoolSize{};
     171           0 :     descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
     172           0 :     descriptorPoolSize.descriptorCount = 1;
     173             : 
     174           0 :     VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{};
     175           0 :     descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
     176           0 :     descriptorPoolCreateInfo.poolSizeCount = 1;
     177           0 :     descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize;
     178           0 :     descriptorPoolCreateInfo.maxSets = 1;
     179           0 :     ENSURE_VK_SUCCESS(vkCreateDescriptorPool(
     180             :         device->GetVkDevice(), &descriptorPoolCreateInfo, nullptr, &deviceCommandContext->m_UniformDescriptorPool));
     181             : 
     182           0 :     VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{};
     183           0 :     descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
     184           0 :     descriptorSetAllocateInfo.descriptorPool = deviceCommandContext->m_UniformDescriptorPool;
     185           0 :     descriptorSetAllocateInfo.descriptorSetCount = 1;
     186           0 :     descriptorSetAllocateInfo.pSetLayouts = &device->GetDescriptorManager().GetUniformDescriptorSetLayout();
     187             : 
     188           0 :     ENSURE_VK_SUCCESS(vkAllocateDescriptorSets(
     189             :         device->GetVkDevice(), &descriptorSetAllocateInfo, &deviceCommandContext->m_UniformDescriptorSet));
     190             : 
     191             :     // TODO: fix the hard-coded size.
     192           0 :     const VkDescriptorBufferInfo descriptorBufferInfos[1] =
     193             :     {
     194           0 :         {deviceCommandContext->m_UniformBuffer->GetVkBuffer(), 0u, 512u}
     195           0 :     };
     196             : 
     197           0 :     VkWriteDescriptorSet writeDescriptorSet{};
     198           0 :     writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
     199           0 :     writeDescriptorSet.dstSet = deviceCommandContext->m_UniformDescriptorSet;
     200           0 :     writeDescriptorSet.dstBinding = 0;
     201           0 :     writeDescriptorSet.dstArrayElement = 0;
     202           0 :     writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
     203           0 :     writeDescriptorSet.descriptorCount = 1;
     204           0 :     writeDescriptorSet.pBufferInfo = descriptorBufferInfos;
     205             : 
     206           0 :     vkUpdateDescriptorSets(
     207             :         device->GetVkDevice(), 1, &writeDescriptorSet, 0, nullptr);
     208             : 
     209           0 :     return deviceCommandContext;
     210             : }
     211             : 
     212             : CDeviceCommandContext::CDeviceCommandContext() = default;
     213             : 
     214           0 : CDeviceCommandContext::~CDeviceCommandContext()
     215             : {
     216           0 :     VkDevice device = m_Device->GetVkDevice();
     217             : 
     218           0 :     vkDeviceWaitIdle(device);
     219             : 
     220           0 :     if (m_UniformDescriptorPool != VK_NULL_HANDLE)
     221           0 :         vkDestroyDescriptorPool(device, m_UniformDescriptorPool, nullptr);
     222           0 : }
     223             : 
     224           0 : IDevice* CDeviceCommandContext::GetDevice()
     225             : {
     226           0 :     return m_Device;
     227             : }
     228             : 
     229           0 : void CDeviceCommandContext::SetGraphicsPipelineState(
     230             :     IGraphicsPipelineState* pipelineState)
     231             : {
     232           0 :     ENSURE(pipelineState);
     233           0 :     m_GraphicsPipelineState = pipelineState->As<CGraphicsPipelineState>();
     234             : 
     235           0 :     CShaderProgram* shaderProgram = m_GraphicsPipelineState->GetShaderProgram()->As<CShaderProgram>();
     236           0 :     if (m_ShaderProgram != shaderProgram)
     237             :     {
     238           0 :         if (m_ShaderProgram)
     239           0 :             m_ShaderProgram->Unbind();
     240           0 :         m_ShaderProgram = shaderProgram;
     241             :     }
     242           0 :     m_IsPipelineStateDirty = true;
     243           0 : }
     244             : 
     245           0 : void CDeviceCommandContext::BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer)
     246             : {
     247           0 :     ENSURE(!m_InsideFramebufferPass);
     248             :     const auto& sourceColorAttachments =
     249           0 :         sourceFramebuffer->As<CFramebuffer>()->GetColorAttachments();
     250             :     const auto& destinationColorAttachments =
     251           0 :         destinationFramebuffer->As<CFramebuffer>()->GetColorAttachments();
     252           0 :     ENSURE(sourceColorAttachments.size() == destinationColorAttachments.size());
     253             :     // TODO: account depth.
     254             :     //ENSURE(
     255             :     //  static_cast<bool>(sourceFramebuffer->As<CFramebuffer>()->GetDepthStencilAttachment()) ==
     256             :     //      static_cast<bool>(destinationFramebuffer->As<CFramebuffer>()->GetDepthStencilAttachment()));
     257             : 
     258           0 :     for (CTexture* sourceColorAttachment : sourceColorAttachments)
     259             :     {
     260           0 :         ENSURE(sourceColorAttachment->GetUsage() & ITexture::Usage::TRANSFER_SRC);
     261             :     }
     262           0 :     for (CTexture* destinationColorAttachment : destinationColorAttachments)
     263             :     {
     264           0 :         ENSURE(destinationColorAttachment->GetUsage() & ITexture::Usage::TRANSFER_DST);
     265             :     }
     266             : 
     267             :     // TODO: combine barriers, reduce duplication, add depth.
     268             :     ScopedImageLayoutTransition scopedColorAttachmentsTransition{
     269           0 :         *m_CommandContext,
     270             :         {sourceColorAttachments.begin(), sourceColorAttachments.end()},
     271             :         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
     272             :         VK_ACCESS_TRANSFER_READ_BIT,
     273           0 :         VK_PIPELINE_STAGE_TRANSFER_BIT};
     274             :     ScopedImageLayoutTransition destinationColorAttachmentsTransition{
     275           0 :         *m_CommandContext,
     276             :         {destinationColorAttachments.begin(), destinationColorAttachments.end()},
     277             :         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
     278             :         VK_ACCESS_TRANSFER_WRITE_BIT,
     279           0 :         VK_PIPELINE_STAGE_TRANSFER_BIT};
     280             : 
     281             :     // TODO: split BlitFramebuffer into ResolveFramebuffer and BlitFramebuffer.
     282           0 :     if (sourceFramebuffer->As<CFramebuffer>()->GetSampleCount() == 1)
     283             :     {
     284             :         // TODO: we need to check for VK_FORMAT_FEATURE_BLIT_*_BIT for used formats.
     285           0 :         for (CFramebuffer::ColorAttachments::size_type index = 0; index < destinationColorAttachments.size(); ++index)
     286             :         {
     287           0 :             CTexture* sourceColorAttachment = sourceColorAttachments[index];
     288           0 :             CTexture* destinationColorAttachment = destinationColorAttachments[index];
     289             : 
     290           0 :             VkImageBlit region{};
     291           0 :             region.srcOffsets[1].x = sourceColorAttachment->GetWidth();
     292           0 :             region.srcOffsets[1].y = sourceColorAttachment->GetHeight();
     293           0 :             region.srcOffsets[1].z = 1;
     294           0 :             region.dstOffsets[1].x = destinationColorAttachment->GetWidth();
     295           0 :             region.dstOffsets[1].y = destinationColorAttachment->GetHeight();
     296           0 :             region.dstOffsets[1].z = 1;
     297           0 :             region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     298           0 :             region.srcSubresource.mipLevel = 0;
     299           0 :             region.srcSubresource.baseArrayLayer = 0;
     300           0 :             region.srcSubresource.layerCount = 1;
     301           0 :             region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     302           0 :             region.dstSubresource.mipLevel = 0;
     303           0 :             region.dstSubresource.baseArrayLayer = 0;
     304           0 :             region.dstSubresource.layerCount = 1;
     305             : 
     306           0 :             ENSURE(sourceColorAttachment->GetImage() != VK_NULL_HANDLE);
     307           0 :             ENSURE(destinationColorAttachment->GetImage() != VK_NULL_HANDLE);
     308           0 :             vkCmdBlitImage(
     309             :                 m_CommandContext->GetCommandBuffer(),
     310             :                 sourceColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
     311             :                 destinationColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
     312             :                 1, &region, VK_FILTER_NEAREST);
     313             :         }
     314             :     }
     315             :     else
     316             :     {
     317           0 :         ENSURE(sourceFramebuffer->As<CFramebuffer>()->GetSampleCount() > 1);
     318           0 :         ENSURE(destinationFramebuffer->As<CFramebuffer>()->GetSampleCount() == 1);
     319           0 :         ENSURE(sourceFramebuffer->As<CFramebuffer>()->GetWidth() == destinationFramebuffer->As<CFramebuffer>()->GetWidth());
     320           0 :         ENSURE(sourceFramebuffer->As<CFramebuffer>()->GetHeight() == destinationFramebuffer->As<CFramebuffer>()->GetHeight());
     321           0 :         for (CFramebuffer::ColorAttachments::size_type index = 0; index < destinationColorAttachments.size(); ++index)
     322             :         {
     323           0 :             CTexture* sourceColorAttachment = sourceColorAttachments[index];
     324           0 :             CTexture* destinationColorAttachment = destinationColorAttachments[index];
     325             : 
     326           0 :             VkImageResolve region{};
     327           0 :             region.extent.width = sourceColorAttachment->GetWidth();
     328           0 :             region.extent.height = sourceColorAttachment->GetHeight();
     329           0 :             region.extent.depth = 1;
     330           0 :             region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     331           0 :             region.srcSubresource.mipLevel = 0;
     332           0 :             region.srcSubresource.baseArrayLayer = 0;
     333           0 :             region.srcSubresource.layerCount = 1;
     334           0 :             region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     335           0 :             region.dstSubresource.mipLevel = 0;
     336           0 :             region.dstSubresource.baseArrayLayer = 0;
     337           0 :             region.dstSubresource.layerCount = 1;
     338             : 
     339           0 :             vkCmdResolveImage(
     340             :                 m_CommandContext->GetCommandBuffer(),
     341             :                 sourceColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
     342             :                 destinationColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
     343             :                 1, &region);
     344             :         }
     345             :     }
     346           0 : }
     347             : 
     348           0 : void CDeviceCommandContext::ClearFramebuffer(const bool color, const bool depth, const bool stencil)
     349             : {
     350           0 :     ENSURE(m_InsideFramebufferPass);
     351           0 :     ENSURE(m_Framebuffer);
     352           0 :     PS::StaticVector<VkClearAttachment, 4> clearAttachments;
     353           0 :     if (color)
     354             :     {
     355           0 :         ENSURE(!m_Framebuffer->GetColorAttachments().empty());
     356           0 :         for (size_t index = 0; index < m_Framebuffer->GetColorAttachments().size(); ++index)
     357             :         {
     358           0 :             VkClearAttachment clearAttachment{};
     359           0 :             clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
     360           0 :             const CColor& clearColor = m_Framebuffer->GetClearColor();
     361           0 :             clearAttachment.clearValue.color.float32[0] = clearColor.r;
     362           0 :             clearAttachment.clearValue.color.float32[1] = clearColor.g;
     363           0 :             clearAttachment.clearValue.color.float32[2] = clearColor.b;
     364           0 :             clearAttachment.clearValue.color.float32[3] = clearColor.a;
     365           0 :             clearAttachment.colorAttachment = index;
     366           0 :             clearAttachments.emplace_back(std::move(clearAttachment));
     367             :         }
     368             :     }
     369           0 :     if (depth || stencil)
     370             :     {
     371           0 :         ENSURE(m_Framebuffer->GetDepthStencilAttachment());
     372           0 :         if (stencil)
     373             :         {
     374             :             const Format depthStencilFormat =
     375           0 :                 m_Framebuffer->GetDepthStencilAttachment()->GetFormat();
     376           0 :             ENSURE(depthStencilFormat == Format::D24_UNORM_S8_UINT ||
     377             :                 depthStencilFormat == Format::D32_SFLOAT_S8_UINT);
     378             :         }
     379           0 :         VkClearAttachment clearAttachment{};
     380           0 :         if (depth)
     381           0 :             clearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
     382           0 :         if (stencil)
     383           0 :             clearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
     384           0 :         clearAttachment.clearValue.depthStencil.depth = 1.0f;
     385           0 :         clearAttachment.clearValue.depthStencil.stencil = 0;
     386           0 :         clearAttachments.emplace_back(std::move(clearAttachment));
     387             :     }
     388           0 :     VkClearRect clearRect{};
     389           0 :     clearRect.layerCount = 1;
     390           0 :     clearRect.rect.offset.x = 0;
     391           0 :     clearRect.rect.offset.y = 0;
     392           0 :     clearRect.rect.extent.width = m_Framebuffer->GetWidth();
     393           0 :     clearRect.rect.extent.height = m_Framebuffer->GetHeight();
     394           0 :     vkCmdClearAttachments(
     395             :         m_CommandContext->GetCommandBuffer(),
     396           0 :         clearAttachments.size(), clearAttachments.data(),
     397             :         1, &clearRect);
     398           0 : }
     399             : 
     400           0 : void CDeviceCommandContext::BeginFramebufferPass(IFramebuffer* framebuffer)
     401             : {
     402           0 :     ENSURE(framebuffer);
     403           0 :     m_IsPipelineStateDirty = true;
     404           0 :     m_Framebuffer = framebuffer->As<CFramebuffer>();
     405           0 :     m_GraphicsPipelineState = nullptr;
     406           0 :     m_VertexInputLayout = nullptr;
     407             : 
     408           0 :     SetScissors(0, nullptr);
     409             : 
     410           0 :     for (CTexture* colorAttachment : m_Framebuffer->GetColorAttachments())
     411             :     {
     412           0 :         if (!(colorAttachment->GetUsage() & ITexture::Usage::SAMPLED) && colorAttachment->IsInitialized())
     413           0 :             continue;
     414           0 :         VkImageLayout oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
     415           0 :         if (!colorAttachment->IsInitialized())
     416           0 :             oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     417           0 :         Utilities::SetTextureLayout(
     418             :             m_CommandContext->GetCommandBuffer(), colorAttachment,
     419             :             oldLayout,
     420             :             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
     421             :             VK_ACCESS_SHADER_READ_BIT,
     422             :             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
     423             :             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
     424             :     }
     425             : 
     426           0 :     CTexture* depthStencilAttachment = m_Framebuffer->GetDepthStencilAttachment();
     427           0 :     if (depthStencilAttachment && ((depthStencilAttachment->GetUsage() & ITexture::Usage::SAMPLED) || !depthStencilAttachment->IsInitialized()))
     428             :     {
     429           0 :         VkImageLayout oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
     430           0 :         if (!depthStencilAttachment->IsInitialized())
     431           0 :             oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
     432           0 :         Utilities::SetTextureLayout(
     433             :             m_CommandContext->GetCommandBuffer(), depthStencilAttachment, oldLayout,
     434             :             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
     435             :             VK_ACCESS_SHADER_READ_BIT,
     436             :             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
     437             :             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
     438             :             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
     439             :     }
     440             : 
     441           0 :     m_InsideFramebufferPass = true;
     442             : 
     443           0 :     VkRenderPassBeginInfo renderPassBeginInfo{};
     444           0 :     renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
     445           0 :     renderPassBeginInfo.renderPass = m_Framebuffer->GetRenderPass();
     446           0 :     renderPassBeginInfo.framebuffer = m_Framebuffer->GetFramebuffer();
     447           0 :     renderPassBeginInfo.renderArea.offset = { 0, 0 };
     448           0 :     renderPassBeginInfo.renderArea.extent = { m_Framebuffer->GetWidth(), m_Framebuffer->GetHeight() };
     449             : 
     450           0 :     PS::StaticVector<VkClearValue, 4> clearValues;
     451             :     const bool needsClearValues =
     452           0 :         m_Framebuffer->GetColorAttachmentLoadOp() == AttachmentLoadOp::CLEAR ||
     453           0 :         (m_Framebuffer->GetDepthStencilAttachment() &&
     454           0 :             m_Framebuffer->GetDepthStencilAttachmentLoadOp() == AttachmentLoadOp::CLEAR);
     455           0 :     if (needsClearValues)
     456             :     {
     457           0 :         for (CTexture* colorAttachment : m_Framebuffer->GetColorAttachments())
     458             :         {
     459             :             UNUSED2(colorAttachment);
     460           0 :             const CColor& clearColor = m_Framebuffer->GetClearColor();
     461             :             // The four array elements of the clear color map to R, G, B, and A
     462             :             // components of image formats, in order.
     463           0 :             clearValues.emplace_back();
     464           0 :             clearValues.back().color.float32[0] = clearColor.r;
     465           0 :             clearValues.back().color.float32[1] = clearColor.g;
     466           0 :             clearValues.back().color.float32[2] = clearColor.b;
     467           0 :             clearValues.back().color.float32[3] = clearColor.a;
     468             :         }
     469           0 :         if (m_Framebuffer->GetDepthStencilAttachment())
     470             :         {
     471           0 :             clearValues.emplace_back();
     472           0 :             clearValues.back().depthStencil.depth = 1.0f;
     473           0 :             clearValues.back().depthStencil.stencil = 0;
     474             :         }
     475           0 :         renderPassBeginInfo.clearValueCount = clearValues.size();
     476           0 :         renderPassBeginInfo.pClearValues = clearValues.data();
     477             :     }
     478             : 
     479           0 :     vkCmdBeginRenderPass(m_CommandContext->GetCommandBuffer(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
     480           0 : }
     481             : 
     482           0 : void CDeviceCommandContext::EndFramebufferPass()
     483             : {
     484           0 :     ENSURE(m_InsideFramebufferPass);
     485           0 :     vkCmdEndRenderPass(m_CommandContext->GetCommandBuffer());
     486             : 
     487           0 :     m_InsideFramebufferPass = false;
     488           0 :     m_BoundIndexBuffer = nullptr;
     489             : 
     490           0 :     ENSURE(m_Framebuffer);
     491           0 :     for (CTexture* colorAttachment : m_Framebuffer->GetColorAttachments())
     492             :     {
     493           0 :         if (!(colorAttachment->GetUsage() & ITexture::Usage::SAMPLED))
     494           0 :             continue;
     495           0 :         Utilities::SetTextureLayout(
     496             :             m_CommandContext->GetCommandBuffer(), colorAttachment,
     497             :             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
     498             :             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
     499             :             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
     500             :             VK_ACCESS_SHADER_READ_BIT,
     501             :             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
     502             :     }
     503             : 
     504           0 :     CTexture* depthStencilAttachment = m_Framebuffer->GetDepthStencilAttachment();
     505           0 :     if (depthStencilAttachment && (depthStencilAttachment->GetUsage() & ITexture::Usage::SAMPLED))
     506             :     {
     507           0 :         Utilities::SetTextureLayout(
     508             :             m_CommandContext->GetCommandBuffer(), depthStencilAttachment,
     509             :             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
     510             :             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
     511             :             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
     512             :             VK_ACCESS_SHADER_READ_BIT,
     513             :             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
     514             :             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
     515             :     }
     516             : 
     517           0 :     m_LastBoundPipeline = VK_NULL_HANDLE;
     518           0 :     if (m_ShaderProgram)
     519           0 :         m_ShaderProgram->Unbind();
     520           0 :     m_ShaderProgram = nullptr;
     521           0 : }
     522             : 
     523           0 : void CDeviceCommandContext::ReadbackFramebufferSync(
     524             :     const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height,
     525             :     void* data)
     526             : {
     527             :     UNUSED2(x);
     528             :     UNUSED2(y);
     529             :     UNUSED2(width);
     530             :     UNUSED2(height);
     531             :     UNUSED2(data);
     532           0 :     LOGERROR("Vulkan: framebuffer readback is not implemented yet.");
     533           0 : }
     534             : 
     535           0 : void CDeviceCommandContext::UploadTexture(ITexture* texture, const Format dataFormat,
     536             :     const void* data, const size_t dataSize,
     537             :     const uint32_t level, const uint32_t layer)
     538             : {
     539           0 :     (m_InsideFramebufferPass ? m_PrependCommandContext : m_CommandContext)->ScheduleUpload(
     540             :         texture->As<CTexture>(), dataFormat, data, dataSize, level, layer);
     541           0 : }
     542             : 
     543           0 : void CDeviceCommandContext::UploadTextureRegion(ITexture* texture, const Format dataFormat,
     544             :     const void* data, const size_t dataSize,
     545             :     const uint32_t xOffset, const uint32_t yOffset,
     546             :     const uint32_t width, const uint32_t height,
     547             :     const uint32_t level, const uint32_t layer)
     548             : {
     549           0 :     (m_InsideFramebufferPass ? m_PrependCommandContext : m_CommandContext)->ScheduleUpload(
     550             :         texture->As<CTexture>(), dataFormat, data, dataSize, xOffset, yOffset, width, height, level, layer);
     551           0 : }
     552             : 
     553           0 : void CDeviceCommandContext::UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize)
     554             : {
     555           0 :     ENSURE(!m_InsideFramebufferPass);
     556           0 :     m_CommandContext->ScheduleUpload(
     557             :         buffer->As<CBuffer>(), data, 0, dataSize);
     558           0 : }
     559             : 
     560           0 : void CDeviceCommandContext::UploadBuffer(IBuffer* buffer, const UploadBufferFunction& uploadFunction)
     561             : {
     562           0 :     ENSURE(!m_InsideFramebufferPass);
     563           0 :     m_CommandContext->ScheduleUpload(
     564             :         buffer->As<CBuffer>(), 0, buffer->As<CBuffer>()->GetSize(), uploadFunction);
     565           0 : }
     566             : 
     567           0 : void CDeviceCommandContext::UploadBufferRegion(
     568             :     IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize)
     569             : {
     570           0 :     ENSURE(!m_InsideFramebufferPass);
     571           0 :     m_CommandContext->ScheduleUpload(
     572             :         buffer->As<CBuffer>(), data, dataOffset, dataSize);
     573           0 : }
     574             : 
     575           0 : void CDeviceCommandContext::UploadBufferRegion(
     576             :     IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize,
     577             :     const UploadBufferFunction& uploadFunction)
     578             : {
     579           0 :     m_CommandContext->ScheduleUpload(
     580             :         buffer->As<CBuffer>(), dataOffset, dataSize, uploadFunction);
     581           0 : }
     582             : 
     583           0 : void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const Rect* scissors)
     584             : {
     585           0 :     ENSURE(m_Framebuffer);
     586           0 :     ENSURE(scissorCount <= 1);
     587           0 :     VkRect2D scissor{};
     588           0 :     if (scissorCount == 1)
     589             :     {
     590             :         // the x and y members of offset member of any element of pScissors must be
     591             :         // greater than or equal to 0.
     592           0 :         int32_t x = scissors[0].x;
     593           0 :         int32_t y = m_Framebuffer->GetHeight() - scissors[0].y - scissors[0].height;
     594           0 :         int32_t width = scissors[0].width;
     595           0 :         int32_t height = scissors[0].height;
     596           0 :         if (x < 0)
     597             :         {
     598           0 :             width = std::max(0, width + x);
     599           0 :             x = 0;
     600             :         }
     601           0 :         if (y < 0)
     602             :         {
     603           0 :             height = std::max(0, height + y);
     604           0 :             y = 0;
     605             :         }
     606           0 :         scissor.offset.x = x;
     607           0 :         scissor.offset.y = y;
     608           0 :         scissor.extent.width = width;
     609           0 :         scissor.extent.height = height;
     610             :     }
     611             :     else
     612             :     {
     613           0 :         scissor.extent.width = m_Framebuffer->GetWidth();
     614           0 :         scissor.extent.height = m_Framebuffer->GetHeight();
     615             :     }
     616           0 :     vkCmdSetScissor(m_CommandContext->GetCommandBuffer(), 0, 1, &scissor);
     617           0 : }
     618             : 
     619           0 : void CDeviceCommandContext::SetViewports(const uint32_t viewportCount, const Rect* viewports)
     620             : {
     621           0 :     ENSURE(m_Framebuffer);
     622           0 :     ENSURE(viewportCount == 1);
     623             : 
     624           0 :     VkViewport viewport{};
     625           0 :     viewport.minDepth = 0.0f;
     626           0 :     viewport.maxDepth = 1.0f;
     627           0 :     viewport.x = static_cast<float>(viewports[0].x);
     628           0 :     viewport.y = static_cast<float>(static_cast<int32_t>(m_Framebuffer->GetHeight()) - viewports[0].y - viewports[0].height);
     629           0 :     viewport.width = static_cast<float>(viewports[0].width);
     630           0 :     viewport.height = static_cast<float>(viewports[0].height);
     631             : 
     632           0 :     vkCmdSetViewport(m_CommandContext->GetCommandBuffer(), 0, 1, &viewport);
     633           0 : }
     634             : 
     635           0 : void CDeviceCommandContext::SetVertexInputLayout(
     636             :     IVertexInputLayout* vertexInputLayout)
     637             : {
     638           0 :     ENSURE(vertexInputLayout);
     639           0 :     m_IsPipelineStateDirty = true;
     640           0 :     m_VertexInputLayout = vertexInputLayout->As<CVertexInputLayout>();
     641           0 : }
     642             : 
     643           0 : void CDeviceCommandContext::SetVertexBuffer(
     644             :     const uint32_t bindingSlot, IBuffer* buffer, const uint32_t offset)
     645             : {
     646           0 :     BindVertexBuffer(bindingSlot, buffer->As<CBuffer>(), offset);
     647           0 : }
     648             : 
     649           0 : void CDeviceCommandContext::SetVertexBufferData(
     650             :     const uint32_t bindingSlot, const void* data, const uint32_t dataSize)
     651             : {
     652             :     // TODO: check vertex buffer alignment.
     653           0 :     const uint32_t ALIGNMENT = 32;
     654             : 
     655           0 :     uint32_t destination = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE + m_InPlaceBlockVertexOffset;
     656           0 :     uint32_t destination2 = m_InPlaceBlockVertexOffset;
     657             :     // TODO: add overflow checks.
     658           0 :     m_InPlaceBlockVertexOffset = (m_InPlaceBlockVertexOffset + dataSize + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
     659           0 :     std::memcpy(static_cast<uint8_t*>(m_InPlaceVertexStagingBufferMappedData) + destination, data, dataSize);
     660             : 
     661           0 :     BindVertexBuffer(bindingSlot, m_InPlaceVertexBuffer.get(), destination2);
     662           0 : }
     663             : 
     664           0 : void CDeviceCommandContext::SetIndexBuffer(IBuffer* buffer)
     665             : {
     666           0 :     BindIndexBuffer(buffer->As<CBuffer>(), 0);
     667           0 : }
     668             : 
     669           0 : void CDeviceCommandContext::SetIndexBufferData(
     670             :     const void* data, const uint32_t dataSize)
     671             : {
     672             :     // TODO: check index buffer alignment.
     673           0 :     const uint32_t ALIGNMENT = 32;
     674             : 
     675           0 :     uint32_t destination = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE + m_InPlaceBlockIndexOffset;
     676           0 :     uint32_t destination2 = m_InPlaceBlockIndexOffset;
     677             :     // TODO: add overflow checks.
     678           0 :     m_InPlaceBlockIndexOffset = (m_InPlaceBlockIndexOffset + dataSize + ALIGNMENT - 1) & (~(ALIGNMENT - 1));
     679           0 :     std::memcpy(static_cast<uint8_t*>(m_InPlaceIndexStagingBufferMappedData) + destination, data, dataSize);
     680             : 
     681           0 :     BindIndexBuffer(m_InPlaceIndexBuffer.get(), destination2);
     682           0 : }
     683             : 
     684           0 : void CDeviceCommandContext::BeginPass()
     685             : {
     686           0 :     ENSURE(m_InsideFramebufferPass);
     687           0 :     m_InsidePass = true;
     688           0 : }
     689             : 
     690           0 : void CDeviceCommandContext::EndPass()
     691             : {
     692           0 :     ENSURE(m_InsidePass);
     693           0 :     m_InsidePass = false;
     694           0 : }
     695             : 
     696           0 : void CDeviceCommandContext::Draw(const uint32_t firstVertex, const uint32_t vertexCount)
     697             : {
     698           0 :     PreDraw();
     699           0 :     vkCmdDraw(m_CommandContext->GetCommandBuffer(), vertexCount, 1, firstVertex, 0);
     700           0 : }
     701             : 
     702           0 : void CDeviceCommandContext::DrawIndexed(
     703             :     const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset)
     704             : {
     705           0 :     ENSURE(vertexOffset == 0);
     706           0 :     PreDraw();
     707           0 :     vkCmdDrawIndexed(m_CommandContext->GetCommandBuffer(), indexCount, 1, firstIndex, 0, 0);
     708           0 : }
     709             : 
     710           0 : void CDeviceCommandContext::DrawInstanced(
     711             :     const uint32_t firstVertex, const uint32_t vertexCount,
     712             :     const uint32_t firstInstance, const uint32_t instanceCount)
     713             : {
     714           0 :     PreDraw();
     715           0 :     vkCmdDraw(
     716             :         m_CommandContext->GetCommandBuffer(), vertexCount, instanceCount, firstVertex, firstInstance);
     717           0 : }
     718             : 
     719           0 : void CDeviceCommandContext::DrawIndexedInstanced(
     720             :     const uint32_t firstIndex, const uint32_t indexCount,
     721             :     const uint32_t firstInstance, const uint32_t instanceCount,
     722             :     const int32_t vertexOffset)
     723             : {
     724           0 :     PreDraw();
     725           0 :     vkCmdDrawIndexed(
     726             :         m_CommandContext->GetCommandBuffer(), indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
     727           0 : }
     728             : 
     729           0 : void CDeviceCommandContext::DrawIndexedInRange(
     730             :     const uint32_t firstIndex, const uint32_t indexCount,
     731             :     const uint32_t UNUSED(start), const uint32_t UNUSED(end))
     732             : {
     733           0 :     DrawIndexed(firstIndex, indexCount, 0);
     734           0 : }
     735             : 
     736           0 : void CDeviceCommandContext::SetTexture(const int32_t bindingSlot, ITexture* texture)
     737             : {
     738           0 :     if (bindingSlot < 0)
     739           0 :         return;
     740             : 
     741           0 :     ENSURE(m_InsidePass);
     742           0 :     ENSURE(texture);
     743           0 :     CTexture* textureToBind = texture->As<CTexture>();
     744           0 :     ENSURE(textureToBind->GetUsage() & ITexture::Usage::SAMPLED);
     745             : 
     746           0 :     if (!m_Device->GetDescriptorManager().UseDescriptorIndexing())
     747             :     {
     748             :         // We can't bind textures which are used as color attachments.
     749           0 :         const auto& colorAttachments = m_Framebuffer->GetColorAttachments();
     750           0 :         ENSURE(std::find(
     751             :             colorAttachments.begin(), colorAttachments.end(), textureToBind) == colorAttachments.end());
     752           0 :         ENSURE(m_Framebuffer->GetDepthStencilAttachment() != textureToBind);
     753             : 
     754           0 :         ENSURE(textureToBind->IsInitialized());
     755             :     }
     756             : 
     757           0 :     m_ShaderProgram->SetTexture(bindingSlot, textureToBind);
     758             : }
     759             : 
     760           0 : void CDeviceCommandContext::SetUniform(
     761             :     const int32_t bindingSlot,
     762             :     const float value)
     763             : {
     764           0 :     ENSURE(m_InsidePass);
     765           0 :     m_ShaderProgram->SetUniform(bindingSlot, value);
     766           0 : }
     767             : 
     768           0 : void CDeviceCommandContext::SetUniform(
     769             :     const int32_t bindingSlot,
     770             :     const float valueX, const float valueY)
     771             : {
     772           0 :     ENSURE(m_InsidePass);
     773           0 :     m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY);
     774           0 : }
     775             : 
     776           0 : void CDeviceCommandContext::SetUniform(
     777             :     const int32_t bindingSlot,
     778             :     const float valueX, const float valueY,
     779             :     const float valueZ)
     780             : {
     781           0 :     ENSURE(m_InsidePass);
     782           0 :     m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ);
     783           0 : }
     784             : 
     785           0 : void CDeviceCommandContext::SetUniform(
     786             :     const int32_t bindingSlot,
     787             :     const float valueX, const float valueY,
     788             :     const float valueZ, const float valueW)
     789             : {
     790           0 :     ENSURE(m_InsidePass);
     791           0 :     m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ, valueW);
     792           0 : }
     793             : 
     794           0 : void CDeviceCommandContext::SetUniform(
     795             :     const int32_t bindingSlot, PS::span<const float> values)
     796             : {
     797           0 :     ENSURE(m_InsidePass);
     798           0 :     m_ShaderProgram->SetUniform(bindingSlot, values);
     799           0 : }
     800             : 
     801           0 : void CDeviceCommandContext::BeginScopedLabel(const char* name)
     802             : {
     803           0 :     if (!m_DebugScopedLabels)
     804           0 :         return;
     805           0 :     VkDebugUtilsLabelEXT label{};
     806           0 :     label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
     807           0 :     label.pLabelName = name;
     808           0 :     vkCmdBeginDebugUtilsLabelEXT(m_CommandContext->GetCommandBuffer(), &label);
     809             : }
     810             : 
     811           0 : void CDeviceCommandContext::EndScopedLabel()
     812             : {
     813           0 :     if (!m_DebugScopedLabels)
     814           0 :         return;
     815           0 :     vkCmdEndDebugUtilsLabelEXT(m_CommandContext->GetCommandBuffer());
     816             : }
     817             : 
     818           0 : void CDeviceCommandContext::Flush()
     819             : {
     820           0 :     ENSURE(!m_InsideFramebufferPass);
     821             :     // TODO: remove hard-coded values and reduce duplication.
     822             :     // TODO: fix unsafe copying when overlaping flushes/frames.
     823             : 
     824           0 :     if (m_InPlaceBlockVertexOffset > 0)
     825             :     {
     826           0 :         VkBufferCopy region{};
     827           0 :         region.srcOffset = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE;
     828           0 :         region.dstOffset = 0;
     829           0 :         region.size = m_InPlaceBlockVertexOffset;
     830             : 
     831           0 :         vkCmdCopyBuffer(
     832             :             m_PrependCommandContext->GetCommandBuffer(),
     833             :             m_InPlaceVertexStagingBuffer->GetVkBuffer(),
     834             :             m_InPlaceVertexBuffer->GetVkBuffer(), 1, &region);
     835             :     }
     836             : 
     837           0 :     if (m_InPlaceBlockIndexOffset > 0)
     838             :     {
     839           0 :         VkBufferCopy region{};
     840           0 :         region.srcOffset = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE;
     841           0 :         region.dstOffset = 0;
     842           0 :         region.size = m_InPlaceBlockIndexOffset;
     843           0 :         vkCmdCopyBuffer(
     844             :             m_PrependCommandContext->GetCommandBuffer(),
     845             :             m_InPlaceIndexStagingBuffer->GetVkBuffer(),
     846             :             m_InPlaceIndexBuffer->GetVkBuffer(), 1, &region);
     847             :     }
     848             : 
     849           0 :     if (m_InPlaceBlockVertexOffset > 0 || m_InPlaceBlockIndexOffset > 0)
     850             :     {
     851           0 :         VkMemoryBarrier memoryBarrier{};
     852           0 :         memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
     853           0 :         memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
     854           0 :         memoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
     855             : 
     856           0 :         vkCmdPipelineBarrier(
     857             :             m_PrependCommandContext->GetCommandBuffer(),
     858             :             VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0,
     859             :             1, &memoryBarrier, 0, nullptr, 0, nullptr);
     860             :     }
     861             : 
     862           0 :     if (m_UniformOffset > 0)
     863             :     {
     864           0 :         VkBufferCopy region{};
     865             :         // TODO: fix values
     866           0 :         region.srcOffset = (m_UniformStagingBuffer->GetSize() / NUMBER_OF_FRAMES_IN_FLIGHT) * m_UniformIndexOffset;
     867           0 :         region.dstOffset = 0;
     868           0 :         region.size = m_UniformOffset;
     869           0 :         vkCmdCopyBuffer(
     870             :             m_PrependCommandContext->GetCommandBuffer(),
     871             :             m_UniformStagingBuffer->GetVkBuffer(),
     872             :             m_UniformBuffer->GetVkBuffer(), 1, &region);
     873           0 :         m_UniformIndexOffset = (m_UniformIndexOffset + 1) % NUMBER_OF_FRAMES_IN_FLIGHT;
     874           0 :         m_UniformOffset = 0;
     875             :     }
     876             : 
     877           0 :     m_IsPipelineStateDirty = true;
     878             :     // TODO: maybe move management to CDevice.
     879           0 :     m_InPlaceBlockIndex = (m_InPlaceBlockIndex + 1) % NUMBER_OF_FRAMES_IN_FLIGHT;
     880           0 :     m_InPlaceBlockVertexOffset = 0;
     881           0 :     m_InPlaceBlockIndexOffset = 0;
     882             : 
     883           0 :     m_PrependCommandContext->Flush();
     884           0 :     m_CommandContext->Flush();
     885           0 : }
     886             : 
     887           0 : void CDeviceCommandContext::PreDraw()
     888             : {
     889           0 :     ENSURE(m_InsidePass);
     890           0 :     ApplyPipelineStateIfDirty();
     891           0 :     m_ShaderProgram->PreDraw(m_CommandContext->GetCommandBuffer());
     892           0 :     if (m_ShaderProgram->IsMaterialConstantsDataOutdated())
     893             :     {
     894             :         const VkDeviceSize alignment =
     895           0 :             std::max(static_cast<VkDeviceSize>(16), m_Device->GetChoosenPhysicalDevice().properties.limits.minUniformBufferOffsetAlignment);
     896           0 :         const uint32_t offset = m_UniformOffset + m_UniformIndexOffset * (m_UniformStagingBuffer->GetSize() / NUMBER_OF_FRAMES_IN_FLIGHT);
     897           0 :         std::memcpy(static_cast<uint8_t*>(m_UniformStagingBufferMappedData) + offset,
     898           0 :             m_ShaderProgram->GetMaterialConstantsData(),
     899           0 :             m_ShaderProgram->GetMaterialConstantsDataSize());
     900           0 :         m_ShaderProgram->UpdateMaterialConstantsData();
     901             : 
     902             :         // TODO: maybe move inside shader program to reduce the # of bind calls.
     903           0 :         vkCmdBindDescriptorSets(
     904           0 :             m_CommandContext->GetCommandBuffer(), m_ShaderProgram->GetPipelineBindPoint(),
     905           0 :             m_ShaderProgram->GetPipelineLayout(), m_Device->GetDescriptorManager().GetUniformSet(),
     906           0 :             1, &m_UniformDescriptorSet, 1, &m_UniformOffset);
     907             : 
     908           0 :         m_UniformOffset += (m_ShaderProgram->GetMaterialConstantsDataSize() + alignment - 1) & ~(alignment - 1);
     909             :     }
     910           0 : }
     911             : 
     912           0 : void CDeviceCommandContext::ApplyPipelineStateIfDirty()
     913             : {
     914           0 :     if (!m_IsPipelineStateDirty)
     915           0 :         return;
     916           0 :     m_IsPipelineStateDirty = false;
     917             : 
     918           0 :     ENSURE(m_GraphicsPipelineState);
     919           0 :     ENSURE(m_VertexInputLayout);
     920           0 :     ENSURE(m_Framebuffer);
     921             : 
     922           0 :     VkPipeline pipeline = m_GraphicsPipelineState->GetOrCreatePipeline(
     923           0 :         m_VertexInputLayout, m_Framebuffer);
     924           0 :     ENSURE(pipeline != VK_NULL_HANDLE);
     925             : 
     926           0 :     if (m_LastBoundPipeline != pipeline)
     927             :     {
     928           0 :         m_LastBoundPipeline = pipeline;
     929           0 :         vkCmdBindPipeline(m_CommandContext->GetCommandBuffer(), m_ShaderProgram->GetPipelineBindPoint(), pipeline);
     930             : 
     931           0 :         m_ShaderProgram->Bind();
     932             : 
     933           0 :         if (m_Device->GetDescriptorManager().UseDescriptorIndexing())
     934             :         {
     935           0 :             vkCmdBindDescriptorSets(
     936           0 :                 m_CommandContext->GetCommandBuffer(), m_ShaderProgram->GetPipelineBindPoint(),
     937           0 :                 m_ShaderProgram->GetPipelineLayout(), 0,
     938           0 :                 1, &m_Device->GetDescriptorManager().GetDescriptorIndexingSet(), 0, nullptr);
     939             :         }
     940             :     }
     941             : }
     942             : 
     943           0 : void CDeviceCommandContext::BindVertexBuffer(
     944             :     const uint32_t bindingSlot, CBuffer* buffer, uint32_t offset)
     945             : {
     946           0 :     VkBuffer vertexBuffers[] = { buffer->GetVkBuffer() };
     947           0 :     VkDeviceSize offsets[] = { offset };
     948           0 :     vkCmdBindVertexBuffers(
     949           0 :         m_CommandContext->GetCommandBuffer(), bindingSlot, std::size(vertexBuffers), vertexBuffers, offsets);
     950           0 : }
     951             : 
     952           0 : void CDeviceCommandContext::BindIndexBuffer(CBuffer* buffer, uint32_t offset)
     953             : {
     954           0 :     if (buffer == m_BoundIndexBuffer && offset == m_BoundIndexBufferOffset)
     955           0 :         return;
     956           0 :     m_BoundIndexBuffer = buffer;
     957           0 :     m_BoundIndexBufferOffset = offset;
     958           0 :     vkCmdBindIndexBuffer(
     959             :         m_CommandContext->GetCommandBuffer(), buffer->GetVkBuffer(), offset, VK_INDEX_TYPE_UINT16);
     960             : }
     961             : 
     962             : } // namespace Vulkan
     963             : 
     964             : } // namespace Backend
     965             : 
     966           3 : } // namespace Renderer

Generated by: LCOV version 1.13