<commit_before>/*
 *  Copyright 2019-2021 Diligent Graphics LLC
 *  Copyright 2015-2019 <NAME>
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  In no event and under no legal theory, whether in tort (including negligence), 
 *  contract, or otherwise, unless required by applicable law (such as deliberate 
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental, 
 *  or consequential damages of any character arising as a result of this License or 
 *  out of the use or inability to use the software (including but not limited to damages 
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and 
 *  all other commercial damages or losses), even if such Contributor has been advised 
 *  of the possibility of such damages.
 */

#include "pch.h"
#include "BufferVkImpl.hpp"
#include "RenderDeviceVkImpl.hpp"
#include "DeviceContextVkImpl.hpp"
#include "VulkanTypeConversions.hpp"
#include "BufferViewVkImpl.hpp"
#include "GraphicsAccessories.hpp"
#include "EngineMemory.h"
#include "StringTools.hpp"
#include "VulkanUtilities/VulkanDebug.hpp"
#include "VulkanUtilities/VulkanCommandBuffer.hpp"

namespace Diligent
{

BufferVkImpl::BufferVkImpl(IReferenceCounters*        pRefCounters,
                           FixedBlockMemoryAllocator& BuffViewObjMemAllocator,
                           RenderDeviceVkImpl*        pRenderDeviceVk,
                           const BufferDesc&          BuffDesc,
                           const BufferData*          pBuffData /*= nullptr*/) :
    // clang-format off
    TBufferBase
    {
        pRefCounters,
        BuffViewObjMemAllocator,
        pRenderDeviceVk,
        BuffDesc,
        false
    },
    m_DynamicData(STD_ALLOCATOR_RAW_MEM(CtxDynamicData, GetRawAllocator(), "Allocator for vector<VulkanDynamicAllocation>"))
// clang-format on
{
    ValidateBufferInitData(BuffDesc, pBuffData);

    if (m_Desc.Usage == USAGE_IMMUTABLE)
        VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for immutable buffers");
    if (m_Desc.Usage == USAGE_DYNAMIC)
        VERIFY(pBuffData == nullptr || pBuffData->pData == nullptr, "Initial data must be null for dynamic buffers");

    if (m_Desc.Usage == USAGE_STAGING)
    {
        VERIFY(m_Desc.CPUAccessFlags == CPU_ACCESS_WRITE || m_Desc.CPUAccessFlags == CPU_ACCESS_READ,
               "Exactly one of the CPU_ACCESS_WRITE or CPU_ACCESS_READ flags must be specified for a staging buffer");

        if (m_Desc.CPUAccessFlags == CPU_ACCESS_WRITE)
            VERIFY(pBuffData == nullptr || pBuffData->pData == nullptr, "CPU-writable staging buffers must be updated via map");
    }

    const auto& LogicalDevice  = pRenderDeviceVk->GetLogicalDevice();
    const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
    const auto& DeviceLimits   = PhysicalDevice.GetProperties().limits;
    m_DynamicOffsetAlignment   = std::max(Uint32{4}, static_cast<Uint32>(DeviceLimits.optimalBufferCopyOffsetAlignment));

    VkBufferCreateInfo VkBuffCI = {};
    VkBuffCI.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    VkBuffCI.pNext              = nullptr;
    VkBuffCI.flags              = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
    VkBuffCI.size               = m_Desc.uiSizeInBytes;
    VkBuffCI.usage =
        VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command
        VK_BUFFER_USAGE_TRANSFER_DST_BIT;  // The buffer can be used as the destination of a transfer command

    static_assert(BIND_FLAGS_LAST == 0x400, "Please update this function to handle the new bind flags");

    for (Uint32 BindFlag = 1; BindFlag <= m_Desc.BindFlags; BindFlag <<= 1)
    {
        if ((m_Desc.BindFlags & BindFlag) != BindFlag)
            continue;

        switch (BindFlag)
        {
            case BIND_UNORDERED_ACCESS:
            {
                // RWStructured and RWByteAddress buffers are mapped to storage buffers in Vulkan.
                // RW formatted buffers are mapped to storage texel buffers in Vulkan.
                VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;

                // Each element of pDynamicOffsets of vkCmdBindDescriptorSets function which corresponds to a descriptor
                // binding with type VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC must be a multiple of
                // VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment (13.2.5)
                m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
                m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
                break;
            }
            case BIND_SHADER_RESOURCE:
            {
                // Structured and ByteAddress buffers are mapped to read-only storage buffers in Vulkan.
                // Formatted buffers are mapped to uniform texel buffers in Vulkan.
                VkBuffCI.usage |= m_Desc.Mode == BUFFER_MODE_FORMATTED ? VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;

                m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
                m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
                break;
            }
            case BIND_VERTEX_BUFFER:
            {
                VkBuffCI.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
                break;
            }
            case BIND_INDEX_BUFFER:<commit_msg>BufferVkImpl: fixed buffer offset alignment calculation<commit_after>/*
 *  Copyright 2019-2021 Diligent Graphics LLC
 *  Copyright 2015-2019 <NAME>
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  In no event and under no legal theory, whether in tort (including negligence), 
 *  contract, or otherwise, unless required by applicable law (such as deliberate 
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental, 
 *  or consequential damages of any character arising as a result of this License or 
 *  out of the use or inability to use the software (including but not limited to damages 
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and 
 *  all other commercial damages or losses), even if such Contributor has been advised 
 *  of the possibility of such damages.
 */

#include "pch.h"
#include "BufferVkImpl.hpp"
#include "RenderDeviceVkImpl.hpp"
#include "DeviceContextVkImpl.hpp"
#include "VulkanTypeConversions.hpp"
#include "BufferViewVkImpl.hpp"
#include "GraphicsAccessories.hpp"
#include "EngineMemory.h"
#include "StringTools.hpp"
#include "VulkanUtilities/VulkanDebug.hpp"
#include "VulkanUtilities/VulkanCommandBuffer.hpp"

namespace Diligent
{

BufferVkImpl::BufferVkImpl(IReferenceCounters*        pRefCounters,
                           FixedBlockMemoryAllocator& BuffViewObjMemAllocator,
                           RenderDeviceVkImpl*        pRenderDeviceVk,
                           const BufferDesc&          BuffDesc,
                           const BufferData*          pBuffData /*= nullptr*/) :
    // clang-format off
    TBufferBase
    {
        pRefCounters,
        BuffViewObjMemAllocator,
        pRenderDeviceVk,
        BuffDesc,
        false
    },
    m_DynamicData(STD_ALLOCATOR_RAW_MEM(CtxDynamicData, GetRawAllocator(), "Allocator for vector<VulkanDynamicAllocation>"))
// clang-format on
{
    ValidateBufferInitData(BuffDesc, pBuffData);

    if (m_Desc.Usage == USAGE_IMMUTABLE)
        VERIFY(pBuffData != nullptr && pBuffData->pData != nullptr, "Initial data must not be null for immutable buffers");
    if (m_Desc.Usage == USAGE_DYNAMIC)
        VERIFY(pBuffData == nullptr || pBuffData->pData == nullptr, "Initial data must be null for dynamic buffers");

    if (m_Desc.Usage == USAGE_STAGING)
    {
        VERIFY(m_Desc.CPUAccessFlags == CPU_ACCESS_WRITE || m_Desc.CPUAccessFlags == CPU_ACCESS_READ,
               "Exactly one of the CPU_ACCESS_WRITE or CPU_ACCESS_READ flags must be specified for a staging buffer");

        if (m_Desc.CPUAccessFlags == CPU_ACCESS_WRITE)
            VERIFY(pBuffData == nullptr || pBuffData->pData == nullptr, "CPU-writable staging buffers must be updated via map");
    }

    const auto& LogicalDevice  = pRenderDeviceVk->GetLogicalDevice();
    const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
    const auto& DeviceLimits   = PhysicalDevice.GetProperties().limits;
    m_DynamicOffsetAlignment   = std::max(Uint32{4}, static_cast<Uint32>(DeviceLimits.optimalBufferCopyOffsetAlignment));

    VkBufferCreateInfo VkBuffCI = {};
    VkBuffCI.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    VkBuffCI.pNext              = nullptr;
    VkBuffCI.flags              = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT
    VkBuffCI.size               = m_Desc.uiSizeInBytes;
    VkBuffCI.usage =
        VK_BUFFER_USAGE_TRANSFER_SRC_BIT | // The buffer can be used as the source of a transfer command
        VK_BUFFER_USAGE_TRANSFER_DST_BIT;  // The buffer can be used as the destination of a transfer command

    static_assert(BIND_FLAGS_LAST == 0x400, "Please update this function to handle the new bind flags");

    for (Uint32 BindFlag = 1; BindFlag <= m_Desc.BindFlags; BindFlag <<= 1)
    {
        if ((m_Desc.BindFlags & BindFlag) != BindFlag)
            continue;

        switch (BindFlag)
        {
            case BIND_SHADER_RESOURCE:
            {
                if (m_Desc.Mode == BUFFER_MODE_FORMATTED)
                {
                    // Formatted buffers are mapped to uniform texel buffers in Vulkan.
                    VkBuffCI.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
                    m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
                }
                else
                {
                    // Structured and ByteAddress buffers are mapped to read-only storage buffers in Vulkan.
                    VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
                    m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
                }

                break;
            }
            case BIND_UNORDERED_ACCESS:
            {
                if (m_Desc.Mode == BUFFER_MODE_FORMATTED)
                {
                    // RW formatted buffers are mapped to storage texel buffers in Vulkan.
                    VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
                    m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minTexelBufferOffsetAlignment));
                }
                else
                {
                    // RWStructured and RWByteAddress buffers are mapped to storage buffers in Vulkan.
                    VkBuffCI.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
                    // Each element of pDynamicOffsets of vkCmdBindDescriptorSets function which corresponds to a descriptor
                    // binding with type VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC must be a multiple of
                    // VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment (13.2.5)
                    m_DynamicOffsetAlignment = std::max(m_DynamicOffsetAlignment, static_cast<Uint32>(DeviceLimits.minStorageBufferOffsetAlignment));
                }

                break;
            }
            case BIND_VERTEX_BUFFER:
            {
                VkBuffCI.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
                break;
            }
            case BIND_INDEX_BUFFER:
{'fraction_non_alphanumeric': 0.0700374531835206, 'fraction_numerical': 0.006891385767790262, 'mean_word_length': 2.7864435621100396, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6471', 'n_tokens_mistral': 3878, 'n_tokens_neox': 3711, 'n_words': 1014}