text: #include "dxvk_device.h"
  #include "dxvk_staging.h"
  
  namespace dxvk {
    
    DxvkStagingBuffer::DxvkStagingBuffer(
      const Rc<DxvkBuffer>& buffer)
    : m_buffer(buffer), m_bufferSize(buffer->info().size){
      
    }
    
    
    DxvkStagingBuffer::~DxvkStagingBuffer() {
      
    }
    
    
    VkDeviceSize DxvkStagingBuffer::size() const {
      return m_bufferSize;
    }
    
    
    VkDeviceSize DxvkStagingBuffer::freeBytes() const {
      return m_bufferSize - m_bufferOffset;
    }
    
    
    bool DxvkStagingBuffer::alloc(
            VkDeviceSize            size,
            DxvkStagingBufferSlice& slice) {
      if (m_bufferOffset + size > m_bufferSize)
        return false;
      
      auto physicalSlice = m_buffer->subSlice(m_bufferOffset, size);
      slice.buffer = physicalSlice.handle();
      slice.offset = physicalSlice.offset();
      slice.mapPtr = physicalSlice.mapPtr(0);
      
      m_bufferOffset = align(m_bufferOffset + size, 64);
      return true;
    }
    
    
    void DxvkStagingBuffer::reset() {
      m_bufferOffset = 0;
    }
    
    
    DxvkStagingAlloc::DxvkStagingAlloc(DxvkDevice* device)
    : m_device(device) { }
    
    
    DxvkStagingAlloc::~DxvkStagingAlloc() {
      this->reset();
    }
    
    
    DxvkStagingBufferSlice DxvkStagingAlloc::alloc(VkDeviceSize size) {
      Rc<DxvkStagingBuffer> selectedBuffer;
      
      // Try a worst-fit allocation strategy on the existing staging
      // buffers first. This should keep the amount of wasted space
      // small, especially if there are large allocations.
      for (const auto& buf : m_stagingBuffers) {
        if (selectedBuffer == nullptr || (buf->freeBytes() > selectedBuffer->freeBytes()))
          selectedBuffer = buf;
      }
      
      // If we have no suitable buffer, allocate one from the device
      // that is *at least* as large as the amount of data we need
      // to upload. Usually it will be bigger.
      DxvkStagingBufferSlice slice;
      
      if ((selectedBuffer == nullptr) || (!selectedBuffer->alloc(size, slice))) {
        selectedBuffer = m_device->allocStagingBuffer(size);
        selectedBuffer->alloc(size, slice);
        m_stagingBuffers.push_back(selectedBuffer);
      }
      
      return slice;
    }
    
    
    void DxvkStagingAlloc::reset() {
      for (const auto& buf : m_stagingBuffers)
        m_device->recycleStagingBuffer(buf);
      
      m_stagingBuffers.resize(0);
    }
    
  }
  