1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00
OpenDX/src/dxvk/dxvk_device.cpp
Philip Rebohle 656cb2e4aa
[dxvk] Refactor Vulkan extension management
Adding an extension will now require an additional step, but
this evolved version of the extension list code is more sane
and the structures can be more easily copied around.
2018-07-23 20:07:21 +02:00

287 lines
8.8 KiB
C++

#include "dxvk_device.h"
#include "dxvk_instance.h"
namespace dxvk {
DxvkDevice::DxvkDevice(
const Rc<DxvkAdapter>& adapter,
const Rc<vk::DeviceFn>& vkd,
const DxvkDeviceExtensions& extensions,
const VkPhysicalDeviceFeatures& features)
: m_adapter (adapter),
m_vkd (vkd),
m_extensions (extensions),
m_features (features),
m_properties (adapter->deviceProperties()),
m_memory (new DxvkMemoryAllocator (adapter, vkd)),
m_renderPassPool (new DxvkRenderPassPool (vkd)),
m_pipelineManager (new DxvkPipelineManager (this)),
m_metaClearObjects (new DxvkMetaClearObjects (vkd)),
m_metaMipGenObjects (new DxvkMetaMipGenObjects (vkd)),
m_metaResolveObjects(new DxvkMetaResolveObjects (vkd)),
m_unboundResources (this),
m_submissionQueue (this) {
m_graphicsQueue.queueFamily = m_adapter->graphicsQueueFamily();
m_presentQueue.queueFamily = m_adapter->presentQueueFamily();
m_vkd->vkGetDeviceQueue(m_vkd->device(),
m_graphicsQueue.queueFamily, 0,
&m_graphicsQueue.queueHandle);
m_vkd->vkGetDeviceQueue(m_vkd->device(),
m_presentQueue.queueFamily, 0,
&m_presentQueue.queueHandle);
}
DxvkDevice::~DxvkDevice() {
// Wait for all pending Vulkan commands to be
// executed before we destroy any resources.
m_vkd->vkDeviceWaitIdle(m_vkd->device());
}
DxvkDeviceOptions DxvkDevice::options() const {
DxvkDeviceOptions options;
options.maxNumDynamicUniformBuffers = m_properties.limits.maxDescriptorSetUniformBuffersDynamic;
options.maxNumDynamicStorageBuffers = m_properties.limits.maxDescriptorSetStorageBuffersDynamic;
return options;
}
Rc<DxvkPhysicalBuffer> DxvkDevice::allocPhysicalBuffer(
const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) {
return new DxvkPhysicalBuffer(m_vkd,
createInfo, *m_memory, memoryType);
}
Rc<DxvkStagingBuffer> DxvkDevice::allocStagingBuffer(VkDeviceSize size) {
// 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;
}
// Staging buffers only need to be able to handle transfer
// operations, and they need to be in host-visible memory.
DxvkBufferCreateInfo info;
info.size = size;
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;
// 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;
return new DxvkStagingBuffer(this->createBuffer(info, memFlags));
}
void DxvkDevice::recycleStagingBuffer(const Rc<DxvkStagingBuffer>& buffer) {
// Drop staging buffers that are bigger than the
// standard ones to save memory, recycle the rest
if (buffer->size() == DefaultStagingBufferSize) {
m_recycledStagingBuffers.returnObject(buffer);
buffer->reset();
}
}
Rc<DxvkCommandList> DxvkDevice::createCommandList() {
Rc<DxvkCommandList> cmdList = m_recycledCommandLists.retrieveObject();
if (cmdList == nullptr) {
cmdList = new DxvkCommandList(m_vkd,
this, m_adapter->graphicsQueueFamily());
}
return cmdList;
}
Rc<DxvkContext> DxvkDevice::createContext() {
return new DxvkContext(this,
m_pipelineManager,
m_metaClearObjects,
m_metaMipGenObjects,
m_metaResolveObjects);
}
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
const DxvkRenderTargets& renderTargets) {
const DxvkFramebufferSize defaultSize = {
m_properties.limits.maxFramebufferWidth,
m_properties.limits.maxFramebufferHeight,
m_properties.limits.maxFramebufferLayers };
auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets);
auto renderPassObject = m_renderPassPool->getRenderPass(renderPassFormat);
return new DxvkFramebuffer(m_vkd,
renderPassObject, renderTargets, defaultSize);
}
Rc<DxvkBuffer> DxvkDevice::createBuffer(
const DxvkBufferCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) {
return new DxvkBuffer(this, createInfo, memoryType);
}
Rc<DxvkBufferView> DxvkDevice::createBufferView(
const Rc<DxvkBuffer>& buffer,
const DxvkBufferViewCreateInfo& createInfo) {
return new DxvkBufferView(m_vkd, buffer, createInfo);
}
Rc<DxvkImage> DxvkDevice::createImage(
const DxvkImageCreateInfo& createInfo,
VkMemoryPropertyFlags memoryType) {
return new DxvkImage(m_vkd, createInfo, *m_memory, memoryType);
}
Rc<DxvkImageView> DxvkDevice::createImageView(
const Rc<DxvkImage>& image,
const DxvkImageViewCreateInfo& createInfo) {
return new DxvkImageView(m_vkd, image, createInfo);
}
Rc<DxvkQueryPool> DxvkDevice::createQueryPool(
VkQueryType queryType,
uint32_t queryCount) {
return new DxvkQueryPool(m_vkd, queryType, queryCount);
}
Rc<DxvkSampler> DxvkDevice::createSampler(
const DxvkSamplerCreateInfo& createInfo) {
return new DxvkSampler(m_vkd, createInfo);
}
Rc<DxvkSemaphore> DxvkDevice::createSemaphore() {
return new DxvkSemaphore(m_vkd);
}
Rc<DxvkShader> DxvkDevice::createShader(
VkShaderStageFlagBits stage,
uint32_t slotCount,
const DxvkResourceSlot* slotInfos,
const DxvkInterfaceSlots& iface,
const SpirvCodeBuffer& code) {
return new DxvkShader(stage,
slotCount, slotInfos, iface, code);
}
Rc<DxvkSwapchain> DxvkDevice::createSwapchain(
const Rc<DxvkSurface>& surface,
const DxvkSwapchainProperties& properties) {
return new DxvkSwapchain(this, surface, properties);
}
DxvkStatCounters DxvkDevice::getStatCounters() {
DxvkMemoryStats mem = m_memory->getMemoryStats();
DxvkStatCounters result;
result.setCtr(DxvkStatCounter::MemoryAllocated, mem.memoryAllocated);
result.setCtr(DxvkStatCounter::MemoryUsed, mem.memoryUsed);
std::lock_guard<sync::Spinlock> lock(m_statLock);
result.merge(m_statCounters);
return result;
}
void DxvkDevice::initResources() {
m_unboundResources.clearResources(this);
}
VkResult DxvkDevice::presentSwapImage(
const VkPresentInfoKHR& presentInfo) {
{ // 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.queueHandle, &presentInfo);
}
}
void DxvkDevice::submitCommandList(
const Rc<DxvkCommandList>& commandList,
const Rc<DxvkSemaphore>& waitSync,
const Rc<DxvkSemaphore>& wakeSync) {
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
VkSemaphore wakeSemaphore = VK_NULL_HANDLE;
if (waitSync != nullptr) {
waitSemaphore = waitSync->handle();
commandList->trackResource(waitSync);
}
if (wakeSync != nullptr) {
wakeSemaphore = wakeSync->handle();
commandList->trackResource(wakeSync);
}
VkResult status;
{ // Queue submissions are not thread safe
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);
status = commandList->submit(
m_graphicsQueue.queueHandle,
waitSemaphore, wakeSemaphore);
}
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));
}
}
void DxvkDevice::waitForIdle() {
if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS)
Logger::err("DxvkDevice: waitForIdle: Operation failed");
}
void DxvkDevice::recycleCommandList(const Rc<DxvkCommandList>& cmdList) {
m_recycledCommandLists.returnObject(cmdList);
}
}