2017-10-10 23:32:13 +02:00
|
|
|
#include "dxvk_device.h"
|
|
|
|
#include "dxvk_instance.h"
|
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
|
|
|
DxvkDevice::DxvkDevice(
|
2017-12-02 16:47:06 +01:00
|
|
|
const Rc<DxvkAdapter>& adapter,
|
|
|
|
const Rc<vk::DeviceFn>& vkd,
|
2018-01-16 13:24:36 +01:00
|
|
|
const Rc<DxvkDeviceExtensions>& extensions,
|
2017-12-02 16:47:06 +01:00
|
|
|
const VkPhysicalDeviceFeatures& features)
|
2017-10-15 17:56:06 +02:00
|
|
|
: m_adapter (adapter),
|
|
|
|
m_vkd (vkd),
|
2018-01-16 13:24:36 +01:00
|
|
|
m_extensions (extensions),
|
2017-12-02 16:47:06 +01:00
|
|
|
m_features (features),
|
2018-04-11 17:05:12 +02:00
|
|
|
m_memory (new DxvkMemoryAllocator (adapter, vkd)),
|
|
|
|
m_renderPassPool (new DxvkRenderPassPool (vkd)),
|
|
|
|
m_pipelineCache (new DxvkPipelineCache (vkd)),
|
|
|
|
m_metaClearObjects(new DxvkMetaClearObjects (vkd)),
|
2018-01-27 19:25:41 +01:00
|
|
|
m_unboundResources(this),
|
2017-12-16 18:10:55 +01:00
|
|
|
m_submissionQueue (this) {
|
2017-10-10 23:32:13 +02:00
|
|
|
m_vkd->vkGetDeviceQueue(m_vkd->device(),
|
|
|
|
m_adapter->graphicsQueueFamily(), 0,
|
|
|
|
&m_graphicsQueue);
|
|
|
|
m_vkd->vkGetDeviceQueue(m_vkd->device(),
|
|
|
|
m_adapter->presentQueueFamily(), 0,
|
|
|
|
&m_presentQueue);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkDevice::~DxvkDevice() {
|
2017-12-11 19:48:00 +01:00
|
|
|
// Wait for all pending Vulkan commands to be
|
|
|
|
// executed before we destroy any resources.
|
2017-10-10 23:32:13 +02:00
|
|
|
m_vkd->vkDeviceWaitIdle(m_vkd->device());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-19 00:20:05 +01:00
|
|
|
Rc<DxvkPhysicalBuffer> DxvkDevice::allocPhysicalBuffer(
|
2017-12-16 13:21:11 +01:00
|
|
|
const DxvkBufferCreateInfo& createInfo,
|
|
|
|
VkMemoryPropertyFlags memoryType) {
|
2018-01-18 15:52:57 +01:00
|
|
|
return new DxvkPhysicalBuffer(m_vkd,
|
2018-01-29 00:01:00 +01:00
|
|
|
createInfo, *m_memory, memoryType);
|
2017-12-16 13:21:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-10 15:57:51 +01:00
|
|
|
Rc<DxvkStagingBuffer> DxvkDevice::allocStagingBuffer(VkDeviceSize size) {
|
2017-12-11 19:17:08 +01:00
|
|
|
// In case we need a standard-size staging buffer, try
|
|
|
|
// to recycle an old one that has been returned earlier
|
|
|
|
if (size <= DefaultStagingBufferSize) {
|
|
|
|
const Rc<DxvkStagingBuffer> buffer
|
|
|
|
= m_recycledStagingBuffers.retrieveObject();
|
|
|
|
|
|
|
|
if (buffer != nullptr)
|
|
|
|
return buffer;
|
|
|
|
}
|
2017-12-10 15:57:51 +01:00
|
|
|
|
2017-12-11 19:17:08 +01:00
|
|
|
// Staging buffers only need to be able to handle transfer
|
|
|
|
// operations, and they need to be in host-visible memory.
|
2017-12-10 15:57:51 +01:00
|
|
|
DxvkBufferCreateInfo info;
|
2017-12-11 19:17:08 +01:00
|
|
|
info.size = size;
|
2017-12-10 15:57:51 +01:00
|
|
|
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
|
|
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
|
|
|
| VK_PIPELINE_STAGE_HOST_BIT;
|
|
|
|
info.access = VK_ACCESS_TRANSFER_READ_BIT
|
|
|
|
| VK_ACCESS_HOST_WRITE_BIT;
|
|
|
|
|
|
|
|
VkMemoryPropertyFlags memFlags
|
|
|
|
= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
|
|
|
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
|
|
|
2017-12-11 19:17:08 +01:00
|
|
|
// Don't create buffers that are too small. A staging
|
|
|
|
// buffer should be able to serve multiple uploads.
|
|
|
|
if (info.size < DefaultStagingBufferSize)
|
|
|
|
info.size = DefaultStagingBufferSize;
|
|
|
|
|
2017-12-10 15:57:51 +01:00
|
|
|
return new DxvkStagingBuffer(this->createBuffer(info, memFlags));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DxvkDevice::recycleStagingBuffer(const Rc<DxvkStagingBuffer>& buffer) {
|
2017-12-11 19:17:08 +01:00
|
|
|
// Drop staging buffers that are bigger than the
|
|
|
|
// standard ones to save memory, recycle the rest
|
2017-12-12 00:41:56 +01:00
|
|
|
if (buffer->size() == DefaultStagingBufferSize) {
|
2017-12-11 19:17:08 +01:00
|
|
|
m_recycledStagingBuffers.returnObject(buffer);
|
2017-12-12 00:41:56 +01:00
|
|
|
buffer->reset();
|
|
|
|
}
|
2017-12-10 15:57:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
Rc<DxvkCommandList> DxvkDevice::createCommandList() {
|
2017-12-11 19:17:08 +01:00
|
|
|
Rc<DxvkCommandList> cmdList = m_recycledCommandLists.retrieveObject();
|
|
|
|
|
|
|
|
if (cmdList == nullptr) {
|
|
|
|
cmdList = new DxvkCommandList(m_vkd,
|
|
|
|
this, m_adapter->graphicsQueueFamily());
|
|
|
|
}
|
|
|
|
|
|
|
|
return cmdList;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rc<DxvkContext> DxvkDevice::createContext() {
|
2018-04-11 17:05:12 +02:00
|
|
|
return new DxvkContext(this,
|
|
|
|
m_pipelineCache,
|
|
|
|
m_metaClearObjects);
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
|
|
|
|
const DxvkRenderTargets& renderTargets) {
|
|
|
|
auto format = renderTargets.renderPassFormat();
|
2017-10-15 17:56:06 +02:00
|
|
|
auto renderPass = m_renderPassPool->getRenderPass(format);
|
2017-10-10 23:32:13 +02:00
|
|
|
return new DxvkFramebuffer(m_vkd, renderPass, renderTargets);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-15 14:36:41 +02:00
|
|
|
Rc<DxvkBuffer> DxvkDevice::createBuffer(
|
|
|
|
const DxvkBufferCreateInfo& createInfo,
|
|
|
|
VkMemoryPropertyFlags memoryType) {
|
2017-12-16 13:21:11 +01:00
|
|
|
return new DxvkBuffer(this, createInfo, memoryType);
|
2017-10-15 14:36:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-21 19:50:57 +01:00
|
|
|
Rc<DxvkBufferView> DxvkDevice::createBufferView(
|
|
|
|
const Rc<DxvkBuffer>& buffer,
|
|
|
|
const DxvkBufferViewCreateInfo& createInfo) {
|
|
|
|
return new DxvkBufferView(m_vkd, buffer, createInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
Rc<DxvkImage> DxvkDevice::createImage(
|
|
|
|
const DxvkImageCreateInfo& createInfo,
|
|
|
|
VkMemoryPropertyFlags memoryType) {
|
2017-12-16 13:21:11 +01:00
|
|
|
return new DxvkImage(m_vkd, createInfo, *m_memory, memoryType);
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rc<DxvkImageView> DxvkDevice::createImageView(
|
|
|
|
const Rc<DxvkImage>& image,
|
|
|
|
const DxvkImageViewCreateInfo& createInfo) {
|
|
|
|
return new DxvkImageView(m_vkd, image, createInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-13 13:43:27 +01:00
|
|
|
Rc<DxvkQueryPool> DxvkDevice::createQueryPool(
|
2018-02-15 13:25:18 +01:00
|
|
|
VkQueryType queryType,
|
|
|
|
uint32_t queryCount) {
|
|
|
|
return new DxvkQueryPool(m_vkd, queryType, queryCount);
|
2018-02-13 13:43:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-03 20:23:26 +01:00
|
|
|
Rc<DxvkSampler> DxvkDevice::createSampler(
|
|
|
|
const DxvkSamplerCreateInfo& createInfo) {
|
|
|
|
return new DxvkSampler(m_vkd, createInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
Rc<DxvkSemaphore> DxvkDevice::createSemaphore() {
|
|
|
|
return new DxvkSemaphore(m_vkd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 15:35:29 +01:00
|
|
|
Rc<DxvkShader> DxvkDevice::createShader(
|
|
|
|
VkShaderStageFlagBits stage,
|
2017-12-07 09:38:31 +01:00
|
|
|
uint32_t slotCount,
|
|
|
|
const DxvkResourceSlot* slotInfos,
|
2018-01-12 14:25:26 +01:00
|
|
|
const DxvkInterfaceSlots& iface,
|
2017-11-20 15:35:29 +01:00
|
|
|
const SpirvCodeBuffer& code) {
|
2017-12-08 18:14:05 +01:00
|
|
|
return new DxvkShader(stage,
|
2018-01-12 14:25:26 +01:00
|
|
|
slotCount, slotInfos, iface, code);
|
2017-12-03 00:40:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
Rc<DxvkSwapchain> DxvkDevice::createSwapchain(
|
|
|
|
const Rc<DxvkSurface>& surface,
|
|
|
|
const DxvkSwapchainProperties& properties) {
|
2017-12-12 12:50:52 +01:00
|
|
|
return new DxvkSwapchain(this, surface, properties);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-03 11:56:12 +02:00
|
|
|
DxvkStatCounters DxvkDevice::getStatCounters() {
|
2018-04-03 15:32:00 +02:00
|
|
|
DxvkMemoryStats mem = m_memory->getMemoryStats();
|
|
|
|
|
2018-04-03 11:56:12 +02:00
|
|
|
DxvkStatCounters result;
|
2018-04-03 15:32:00 +02:00
|
|
|
result.setCtr(DxvkStatCounter::MemoryAllocated, mem.memoryAllocated);
|
|
|
|
result.setCtr(DxvkStatCounter::MemoryUsed, mem.memoryUsed);
|
2018-04-03 11:56:12 +02:00
|
|
|
|
2018-04-03 15:52:39 +02:00
|
|
|
std::lock_guard<sync::Spinlock> lock(m_statLock);
|
|
|
|
result.merge(m_statCounters);
|
2018-04-03 11:56:12 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-01 14:26:38 +01:00
|
|
|
void DxvkDevice::initResources() {
|
|
|
|
m_unboundResources.clearResources(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-12 12:50:52 +01:00
|
|
|
VkResult DxvkDevice::presentSwapImage(
|
|
|
|
const VkPresentInfoKHR& presentInfo) {
|
2018-04-03 11:56:12 +02:00
|
|
|
{ // Queue submissions are not thread safe
|
|
|
|
std::lock_guard<std::mutex> queueLock(m_submissionLock);
|
|
|
|
std::lock_guard<sync::Spinlock> statLock(m_statLock);
|
|
|
|
|
|
|
|
m_statCounters.addCtr(DxvkStatCounter::QueuePresentCount, 1);
|
|
|
|
return m_vkd->vkQueuePresentKHR(m_presentQueue, &presentInfo);
|
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-22 18:57:33 +01:00
|
|
|
void DxvkDevice::submitCommandList(
|
2017-10-10 23:32:13 +02:00
|
|
|
const Rc<DxvkCommandList>& commandList,
|
|
|
|
const Rc<DxvkSemaphore>& waitSync,
|
|
|
|
const Rc<DxvkSemaphore>& wakeSync) {
|
2017-12-01 14:27:53 +01:00
|
|
|
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
|
|
|
VkSemaphore wakeSemaphore = VK_NULL_HANDLE;
|
2017-10-10 23:32:13 +02:00
|
|
|
|
|
|
|
if (waitSync != nullptr) {
|
|
|
|
waitSemaphore = waitSync->handle();
|
|
|
|
commandList->trackResource(waitSync);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wakeSync != nullptr) {
|
|
|
|
wakeSemaphore = wakeSync->handle();
|
|
|
|
commandList->trackResource(wakeSync);
|
|
|
|
}
|
|
|
|
|
2018-03-22 20:15:46 +01:00
|
|
|
VkResult status;
|
|
|
|
|
2017-12-12 12:50:52 +01:00
|
|
|
{ // Queue submissions are not thread safe
|
2018-04-03 11:56:12 +02:00
|
|
|
std::lock_guard<std::mutex> queueLock(m_submissionLock);
|
|
|
|
std::lock_guard<sync::Spinlock> statLock(m_statLock);
|
|
|
|
|
|
|
|
m_statCounters.merge(commandList->statCounters());
|
|
|
|
m_statCounters.addCtr(DxvkStatCounter::QueueSubmitCount, 1);
|
2018-03-22 18:57:33 +01:00
|
|
|
|
2018-03-22 20:15:46 +01:00
|
|
|
status = commandList->submit(
|
2018-03-22 18:57:33 +01:00
|
|
|
m_graphicsQueue, waitSemaphore, wakeSemaphore);
|
2017-12-12 12:50:52 +01:00
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2018-03-22 20:15:46 +01:00
|
|
|
if (status == VK_SUCCESS) {
|
|
|
|
// Add this to the set of running submissions
|
|
|
|
m_submissionQueue.submit(commandList);
|
|
|
|
} else {
|
|
|
|
Logger::err(str::format(
|
|
|
|
"DxvkDevice: Command buffer submission failed: ",
|
|
|
|
status));
|
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-12 10:29:17 +01:00
|
|
|
void DxvkDevice::waitForIdle() {
|
2017-10-10 23:32:13 +02:00
|
|
|
if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS)
|
2018-03-01 08:23:55 +01:00
|
|
|
Logger::err("DxvkDevice: waitForIdle: Operation failed");
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
2017-12-16 18:10:55 +01:00
|
|
|
|
|
|
|
void DxvkDevice::recycleCommandList(const Rc<DxvkCommandList>& cmdList) {
|
|
|
|
m_recycledCommandLists.returnObject(cmdList);
|
|
|
|
}
|
|
|
|
|
2018-03-21 02:45:11 +01:00
|
|
|
}
|