2017-10-10 23:32:13 +02:00
|
|
|
#pragma once
|
|
|
|
|
2018-03-19 02:18:44 +01:00
|
|
|
#include <mutex>
|
|
|
|
#include <vector>
|
|
|
|
|
2018-01-18 15:52:57 +01:00
|
|
|
#include "dxvk_buffer_res.h"
|
2017-10-10 23:32:13 +02:00
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
2017-12-16 13:21:11 +01:00
|
|
|
/**
|
|
|
|
* \brief Virtual buffer resource
|
|
|
|
*
|
|
|
|
* A simple buffer resource that stores linear,
|
|
|
|
* unformatted data. Can be accessed by the host
|
|
|
|
* if allocated on an appropriate memory type.
|
|
|
|
*/
|
|
|
|
class DxvkBuffer : public RcObject {
|
2018-03-07 13:54:28 +01:00
|
|
|
friend class DxvkBufferView;
|
2017-12-16 13:21:11 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
DxvkBuffer(
|
|
|
|
DxvkDevice* device,
|
|
|
|
const DxvkBufferCreateInfo& createInfo,
|
|
|
|
VkMemoryPropertyFlags memoryType);
|
|
|
|
|
2017-10-15 14:36:41 +02:00
|
|
|
/**
|
|
|
|
* \brief Buffer properties
|
|
|
|
* \returns Buffer properties
|
|
|
|
*/
|
|
|
|
const DxvkBufferCreateInfo& info() const {
|
|
|
|
return m_info;
|
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2018-01-18 11:55:27 +01:00
|
|
|
/**
|
|
|
|
* \brief Memory type flags
|
|
|
|
*
|
|
|
|
* Use this to determine whether a
|
|
|
|
* buffer is mapped to host memory.
|
|
|
|
* \returns Vulkan memory flags
|
|
|
|
*/
|
|
|
|
VkMemoryPropertyFlags memFlags() const {
|
|
|
|
return m_memFlags;
|
|
|
|
}
|
|
|
|
|
2017-10-15 14:36:41 +02:00
|
|
|
/**
|
|
|
|
* \brief Map pointer
|
|
|
|
*
|
|
|
|
* If the buffer has been created on a host-visible
|
|
|
|
* memory type, the buffer memory is mapped and can
|
|
|
|
* be accessed by the host.
|
2017-12-10 15:57:51 +01:00
|
|
|
* \param [in] offset Byte offset into mapped region
|
2017-10-15 14:36:41 +02:00
|
|
|
* \returns Pointer to mapped memory region
|
|
|
|
*/
|
2017-12-10 15:57:51 +01:00
|
|
|
void* mapPtr(VkDeviceSize offset) const {
|
2018-01-19 00:20:05 +01:00
|
|
|
return m_physSlice.mapPtr(offset);
|
2017-10-15 14:36:41 +02:00
|
|
|
}
|
|
|
|
|
2017-12-16 13:21:11 +01:00
|
|
|
/**
|
|
|
|
* \brief Checks whether the buffer is in use
|
|
|
|
*
|
|
|
|
* Returns \c true if the underlying buffer resource
|
|
|
|
* is in use. If it is, it should not be accessed by
|
|
|
|
* the host for reading or writing, but reallocating
|
|
|
|
* the buffer is a valid strategy to overcome this.
|
|
|
|
* \returns \c true if the buffer is in use
|
|
|
|
*/
|
|
|
|
bool isInUse() const {
|
2018-01-19 00:20:05 +01:00
|
|
|
return m_physSlice.resource()->isInUse();
|
2017-12-16 13:21:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Underlying buffer resource
|
|
|
|
*
|
|
|
|
* Use this for lifetime tracking.
|
|
|
|
* \returns The resource object
|
|
|
|
*/
|
|
|
|
Rc<DxvkResource> resource() const {
|
2018-01-19 00:20:05 +01:00
|
|
|
return m_physSlice.resource();
|
2017-12-16 13:21:11 +01:00
|
|
|
}
|
|
|
|
|
2018-01-18 17:32:34 +01:00
|
|
|
/**
|
|
|
|
* \brief Physical buffer slice
|
|
|
|
*
|
|
|
|
* Retrieves a slice into the physical
|
|
|
|
* buffer which backs this buffer.
|
|
|
|
* \returns The backing slice
|
|
|
|
*/
|
|
|
|
DxvkPhysicalBufferSlice slice() const {
|
2018-01-19 00:20:05 +01:00
|
|
|
return m_physSlice;
|
2018-01-18 17:32:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Physical buffer sub slice
|
|
|
|
*
|
|
|
|
* Retrieves a sub slice into the backing buffer.
|
|
|
|
* \param [in] offset Offset into the buffer
|
|
|
|
* \param [in] length Length of the slice
|
|
|
|
* \returns The sub slice
|
|
|
|
*/
|
|
|
|
DxvkPhysicalBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
2018-01-19 00:20:05 +01:00
|
|
|
return m_physSlice.subSlice(offset, length);
|
2018-01-18 17:32:34 +01:00
|
|
|
}
|
2017-12-16 13:21:11 +01:00
|
|
|
|
2018-01-19 00:20:05 +01:00
|
|
|
/**
|
|
|
|
* \brief Replaces backing resource
|
|
|
|
*
|
|
|
|
* Replaces the underlying buffer and implicitly marks
|
|
|
|
* any buffer views using this resource as dirty. Do
|
|
|
|
* not call this directly as this is called implicitly
|
|
|
|
* by the context's \c invalidateBuffer method.
|
|
|
|
* \param [in] slice The new backing resource
|
2018-03-19 02:18:44 +01:00
|
|
|
* \returns Previous buffer slice
|
2018-01-19 00:20:05 +01:00
|
|
|
*/
|
2018-07-19 09:44:58 +02:00
|
|
|
DxvkPhysicalBufferSlice rename(const DxvkPhysicalBufferSlice& slice) {
|
|
|
|
DxvkPhysicalBufferSlice prevSlice = std::move(m_physSlice);
|
|
|
|
m_physSlice = slice;
|
|
|
|
m_revision += 1;
|
|
|
|
return prevSlice;
|
|
|
|
}
|
2018-01-19 00:20:05 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Allocates new physical resource
|
|
|
|
* \returns The new backing buffer slice
|
|
|
|
*/
|
|
|
|
DxvkPhysicalBufferSlice allocPhysicalSlice();
|
|
|
|
|
2018-03-19 02:18:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Frees a physical buffer slice
|
|
|
|
*
|
|
|
|
* Marks the slice as free so that it can be used for
|
|
|
|
* subsequent allocations. Called automatically when
|
|
|
|
* the slice is no longer needed by the GPU.
|
|
|
|
* \param [in] slice The buffer slice to free
|
|
|
|
*/
|
|
|
|
void freePhysicalSlice(
|
|
|
|
const DxvkPhysicalBufferSlice& slice);
|
|
|
|
|
2017-10-15 14:36:41 +02:00
|
|
|
private:
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2017-12-16 13:21:11 +01:00
|
|
|
DxvkDevice* m_device;
|
|
|
|
DxvkBufferCreateInfo m_info;
|
|
|
|
VkMemoryPropertyFlags m_memFlags;
|
2018-03-19 02:18:44 +01:00
|
|
|
|
2018-01-19 00:20:05 +01:00
|
|
|
DxvkPhysicalBufferSlice m_physSlice;
|
2018-03-07 13:54:28 +01:00
|
|
|
uint32_t m_revision = 0;
|
2018-01-19 00:20:05 +01:00
|
|
|
|
2018-07-19 09:44:58 +02:00
|
|
|
sync::Spinlock m_freeMutex;
|
|
|
|
sync::Spinlock m_swapMutex;
|
2018-03-19 14:53:59 +01:00
|
|
|
|
|
|
|
std::vector<DxvkPhysicalBufferSlice> m_freeSlices;
|
|
|
|
std::vector<DxvkPhysicalBufferSlice> m_nextSlices;
|
2018-03-19 02:18:44 +01:00
|
|
|
|
2018-01-29 00:01:00 +01:00
|
|
|
VkDeviceSize m_physSliceLength = 0;
|
|
|
|
VkDeviceSize m_physSliceStride = 0;
|
2018-03-19 02:18:44 +01:00
|
|
|
VkDeviceSize m_physSliceCount = 2;
|
2018-06-22 00:27:52 +02:00
|
|
|
|
|
|
|
Rc<DxvkPhysicalBuffer> m_physBuffer;
|
2017-12-16 13:21:11 +01:00
|
|
|
|
2018-01-19 00:20:05 +01:00
|
|
|
Rc<DxvkPhysicalBuffer> allocPhysicalBuffer(
|
|
|
|
VkDeviceSize sliceCount) const;
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2018-03-19 02:18:44 +01:00
|
|
|
void lock();
|
|
|
|
void unlock();
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
};
|
|
|
|
|
2017-10-15 17:56:06 +02:00
|
|
|
|
|
|
|
/**
|
2017-12-14 15:24:43 +01:00
|
|
|
* \brief Buffer slice
|
2017-10-15 17:56:06 +02:00
|
|
|
*
|
2017-12-14 15:24:43 +01:00
|
|
|
* Stores the buffer and a sub-range of the buffer.
|
|
|
|
* Slices are considered equal if the buffer and
|
|
|
|
* the buffer range are the same.
|
2017-10-15 17:56:06 +02:00
|
|
|
*/
|
2017-12-14 15:24:43 +01:00
|
|
|
class DxvkBufferSlice {
|
2017-10-15 17:56:06 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-12-14 15:24:43 +01:00
|
|
|
DxvkBufferSlice() { }
|
2018-01-07 21:46:26 +01:00
|
|
|
|
2017-12-14 15:24:43 +01:00
|
|
|
DxvkBufferSlice(
|
2017-10-15 17:56:06 +02:00
|
|
|
const Rc<DxvkBuffer>& buffer,
|
|
|
|
VkDeviceSize rangeOffset,
|
|
|
|
VkDeviceSize rangeLength)
|
|
|
|
: m_buffer(buffer),
|
|
|
|
m_offset(rangeOffset),
|
|
|
|
m_length(rangeLength) { }
|
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
explicit DxvkBufferSlice(const Rc<DxvkBuffer>& buffer)
|
|
|
|
: DxvkBufferSlice(buffer, 0, buffer->info().size) { }
|
|
|
|
|
|
|
|
size_t offset() const { return m_offset; }
|
|
|
|
size_t length() const { return m_length; }
|
2018-01-18 18:01:47 +01:00
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Underlying buffer
|
|
|
|
* \returns The virtual buffer
|
|
|
|
*/
|
2017-12-14 19:07:08 +01:00
|
|
|
Rc<DxvkBuffer> buffer() const {
|
2017-10-15 17:56:06 +02:00
|
|
|
return m_buffer;
|
|
|
|
}
|
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Buffer info
|
|
|
|
*
|
|
|
|
* Retrieves the properties of the underlying
|
|
|
|
* virtual buffer. Should not be used directly
|
|
|
|
* by client APIs.
|
|
|
|
* \returns Buffer properties
|
|
|
|
*/
|
|
|
|
const DxvkBufferCreateInfo& bufferInfo() const {
|
|
|
|
return m_buffer->info();
|
2017-11-20 13:21:27 +01:00
|
|
|
}
|
|
|
|
|
2018-01-20 21:42:11 +01:00
|
|
|
/**
|
|
|
|
* \brief Buffer sub slice
|
|
|
|
*
|
|
|
|
* Takes a sub slice from this slice.
|
|
|
|
* \param [in] offset Sub slice offset
|
|
|
|
* \param [in] length Sub slice length
|
|
|
|
* \returns The sub slice object
|
|
|
|
*/
|
|
|
|
DxvkBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
|
|
|
return DxvkBufferSlice(m_buffer, offset, length);
|
|
|
|
}
|
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Checks whether the slice is valid
|
|
|
|
*
|
|
|
|
* A buffer slice that does not point to any virtual
|
|
|
|
* buffer object is considered undefined and cannot
|
|
|
|
* be used for any operations.
|
|
|
|
* \returns \c true if the slice is defined
|
|
|
|
*/
|
|
|
|
bool defined() const {
|
|
|
|
return m_buffer != nullptr;
|
2017-11-20 13:21:27 +01:00
|
|
|
}
|
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Physical slice
|
|
|
|
*
|
|
|
|
* Retrieves the physical slice that currently
|
|
|
|
* backs the virtual slice. This may change
|
|
|
|
* when the virtual buffer gets invalidated.
|
|
|
|
* \returns The physical buffer slice
|
|
|
|
*/
|
2018-01-18 17:32:34 +01:00
|
|
|
DxvkPhysicalBufferSlice physicalSlice() const {
|
|
|
|
return m_buffer->subSlice(m_offset, m_length);
|
|
|
|
}
|
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Pointer to mapped memory region
|
|
|
|
*
|
|
|
|
* \param [in] offset Offset into the slice
|
|
|
|
* \returns Pointer into mapped buffer memory
|
|
|
|
*/
|
2017-12-15 19:11:10 +01:00
|
|
|
void* mapPtr(VkDeviceSize offset) const {
|
|
|
|
return m_buffer->mapPtr(m_offset + offset);
|
|
|
|
}
|
|
|
|
|
2018-01-18 18:50:44 +01:00
|
|
|
/**
|
|
|
|
* \brief Checks whether two slices are equal
|
|
|
|
*
|
|
|
|
* Two slices are considered equal if they point to
|
|
|
|
* the same memory region within the same buffer.
|
|
|
|
* \param [in] other The slice to compare to
|
|
|
|
* \returns \c true if the two slices are the same
|
|
|
|
*/
|
|
|
|
bool matches(const DxvkBufferSlice& other) const {
|
2017-10-15 17:56:06 +02:00
|
|
|
return this->m_buffer == other.m_buffer
|
|
|
|
&& this->m_offset == other.m_offset
|
|
|
|
&& this->m_length == other.m_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
Rc<DxvkBuffer> m_buffer = nullptr;
|
|
|
|
VkDeviceSize m_offset = 0;
|
|
|
|
VkDeviceSize m_length = 0;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-03-07 16:29:13 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Buffer view
|
|
|
|
*
|
|
|
|
* Allows the application to interpret buffer
|
|
|
|
* contents like formatted pixel data. These
|
|
|
|
* buffer views are used as texel buffers.
|
|
|
|
*/
|
|
|
|
class DxvkBufferView : public RcObject {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
DxvkBufferView(
|
|
|
|
const Rc<vk::DeviceFn>& vkd,
|
|
|
|
const Rc<DxvkBuffer>& buffer,
|
|
|
|
const DxvkBufferViewCreateInfo& info);
|
|
|
|
|
|
|
|
~DxvkBufferView();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Buffer view handle
|
|
|
|
* \returns Buffer view handle
|
|
|
|
*/
|
|
|
|
VkBufferView handle() const {
|
|
|
|
return m_physView->handle();
|
|
|
|
}
|
|
|
|
|
2018-04-11 23:13:34 +02:00
|
|
|
/**
|
|
|
|
* \brief Element cound
|
|
|
|
*
|
|
|
|
* Number of typed elements contained
|
|
|
|
* in the buffer view. Depends on the
|
|
|
|
* buffer view format.
|
|
|
|
* \returns Element count
|
|
|
|
*/
|
|
|
|
VkDeviceSize elementCount() const {
|
|
|
|
auto format = imageFormatInfo(m_info.format);
|
|
|
|
return m_info.rangeLength / format->elementSize;
|
|
|
|
}
|
|
|
|
|
2018-03-07 16:29:13 +01:00
|
|
|
/**
|
|
|
|
* \brief Buffer view properties
|
|
|
|
* \returns Buffer view properties
|
|
|
|
*/
|
|
|
|
const DxvkBufferViewCreateInfo& info() const {
|
|
|
|
return m_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Underlying buffer object
|
|
|
|
* \returns Underlying buffer object
|
|
|
|
*/
|
2018-04-12 23:25:40 +02:00
|
|
|
Rc<DxvkBuffer> buffer() const {
|
|
|
|
return m_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Underlying buffer info
|
|
|
|
* \returns Underlying buffer info
|
|
|
|
*/
|
2018-03-07 16:29:13 +01:00
|
|
|
const DxvkBufferCreateInfo& bufferInfo() const {
|
|
|
|
return m_buffer->info();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Backing resource
|
|
|
|
* \returns Backing resource
|
|
|
|
*/
|
|
|
|
Rc<DxvkResource> viewResource() const {
|
|
|
|
return m_physView;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Backing buffer resource
|
|
|
|
* \returns Backing buffer resource
|
|
|
|
*/
|
|
|
|
Rc<DxvkResource> bufferResource() const {
|
2018-09-17 23:30:36 +02:00
|
|
|
return m_physView->bufferResource();
|
2018-03-07 16:29:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Underlying buffer slice
|
|
|
|
* \returns Slice backing the view
|
|
|
|
*/
|
|
|
|
DxvkBufferSlice slice() const {
|
|
|
|
return DxvkBufferSlice(m_buffer,
|
|
|
|
m_info.rangeOffset,
|
|
|
|
m_info.rangeLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Underlying buffer slice
|
|
|
|
* \returns Slice backing the view
|
|
|
|
*/
|
|
|
|
DxvkPhysicalBufferSlice physicalSlice() const {
|
|
|
|
return m_physView->slice();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Updates the buffer view
|
|
|
|
*
|
|
|
|
* If the buffer has been invalidated ever since
|
|
|
|
* the view was created, the view is invalid as
|
|
|
|
* well and needs to be re-created. Call this
|
|
|
|
* prior to using the buffer view handle.
|
|
|
|
*/
|
|
|
|
void updateView();
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
Rc<vk::DeviceFn> m_vkd;
|
|
|
|
DxvkBufferViewCreateInfo m_info;
|
|
|
|
|
|
|
|
Rc<DxvkBuffer> m_buffer;
|
|
|
|
Rc<DxvkPhysicalBufferView> m_physView;
|
|
|
|
|
|
|
|
uint32_t m_revision = 0;
|
|
|
|
|
|
|
|
Rc<DxvkPhysicalBufferView> createView();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2018-03-19 02:18:44 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Buffer slice tracker
|
|
|
|
*
|
|
|
|
* Stores a list of buffer slices that can be
|
|
|
|
* freed. Useful when buffers have been renamed
|
|
|
|
* and the original slice is no longer needed.
|
|
|
|
*/
|
|
|
|
class DxvkBufferTracker {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
DxvkBufferTracker();
|
|
|
|
~DxvkBufferTracker();
|
|
|
|
|
|
|
|
void freeBufferSlice(
|
|
|
|
const Rc<DxvkBuffer>& buffer,
|
|
|
|
const DxvkPhysicalBufferSlice& slice);
|
|
|
|
|
|
|
|
void reset();
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
struct Entry {
|
|
|
|
Rc<DxvkBuffer> buffer;
|
|
|
|
DxvkPhysicalBufferSlice slice;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<Entry> m_entries;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|