#include "dxvk_device.h" #include "dxvk_instance.h" namespace dxvk { DxvkDevice::DxvkDevice( const Rc& instance, const Rc& adapter, const Rc& vkd, const DxvkDeviceExtensions& extensions, const DxvkDeviceFeatures& features) : m_options (instance->options()), m_instance (instance), m_adapter (adapter), m_vkd (vkd), m_extensions (extensions), m_features (features), m_properties (adapter->devicePropertiesExt()), m_perfHints (getPerfHints()), m_objects (this), m_submissionQueue (this) { auto queueFamilies = m_adapter->findQueueFamilies(); m_queues.graphics = getQueue(queueFamilies.graphics, 0); m_queues.transfer = getQueue(queueFamilies.transfer, 0); } DxvkDevice::~DxvkDevice() { // Wait for all pending Vulkan commands to be // executed before we destroy any resources. this->waitForIdle(); } bool DxvkDevice::isUnifiedMemoryArchitecture() const { auto memory = m_adapter->memoryProperties(); bool result = true; for (uint32_t i = 0; i < memory.memoryHeapCount; i++) result &= memory.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; return result; } VkPipelineStageFlags DxvkDevice::getShaderPipelineStages() const { VkPipelineStageFlags result = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; if (m_features.core.features.geometryShader) result |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; if (m_features.core.features.tessellationShader) { result |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; } return result; } DxvkDeviceOptions DxvkDevice::options() const { DxvkDeviceOptions options; options.maxNumDynamicUniformBuffers = m_properties.core.properties.limits.maxDescriptorSetUniformBuffersDynamic; options.maxNumDynamicStorageBuffers = m_properties.core.properties.limits.maxDescriptorSetStorageBuffersDynamic; return options; } Rc DxvkDevice::createCommandList() { Rc cmdList = m_recycledCommandLists.retrieveObject(); if (cmdList == nullptr) cmdList = new DxvkCommandList(this); return cmdList; } Rc DxvkDevice::createDescriptorPool() { Rc pool = m_recycledDescriptorPools.retrieveObject(); if (pool == nullptr) pool = new DxvkDescriptorPool(m_vkd); return pool; } Rc DxvkDevice::createContext() { return new DxvkContext(this); } Rc DxvkDevice::createGpuEvent() { return new DxvkGpuEvent(m_vkd); } Rc DxvkDevice::createGpuQuery( VkQueryType type, VkQueryControlFlags flags, uint32_t index) { return new DxvkGpuQuery(m_vkd, type, flags, index); } Rc DxvkDevice::createFramebuffer( const DxvkRenderTargets& renderTargets) { const DxvkFramebufferSize defaultSize = { m_properties.core.properties.limits.maxFramebufferWidth, m_properties.core.properties.limits.maxFramebufferHeight, m_properties.core.properties.limits.maxFramebufferLayers }; auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets); auto renderPassObject = m_objects.renderPassPool().getRenderPass(renderPassFormat); return new DxvkFramebuffer(m_vkd, renderPassObject, renderTargets, defaultSize); } Rc DxvkDevice::createBuffer( const DxvkBufferCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { return new DxvkBuffer(this, createInfo, m_objects.memoryManager(), memoryType); } Rc DxvkDevice::createBufferView( const Rc& buffer, const DxvkBufferViewCreateInfo& createInfo) { return new DxvkBufferView(m_vkd, buffer, createInfo); } Rc DxvkDevice::createImage( const DxvkImageCreateInfo& createInfo, VkMemoryPropertyFlags memoryType) { return new DxvkImage(m_vkd, createInfo, m_objects.memoryManager(), memoryType); } Rc DxvkDevice::createImageFromVkImage( const DxvkImageCreateInfo& createInfo, VkImage image) { return new DxvkImage(m_vkd, createInfo, image); } Rc DxvkDevice::createImageView( const Rc& image, const DxvkImageViewCreateInfo& createInfo) { return new DxvkImageView(m_vkd, image, createInfo); } Rc DxvkDevice::createSampler( const DxvkSamplerCreateInfo& createInfo) { return new DxvkSampler(this, createInfo); } Rc DxvkDevice::createShader( VkShaderStageFlagBits stage, uint32_t slotCount, const DxvkResourceSlot* slotInfos, const DxvkInterfaceSlots& iface, const SpirvCodeBuffer& code) { return new DxvkShader(stage, slotCount, slotInfos, iface, code, DxvkShaderOptions(), DxvkShaderConstData()); } DxvkStatCounters DxvkDevice::getStatCounters() { DxvkPipelineCount pipe = m_objects.pipelineManager().getPipelineCount(); DxvkStatCounters result; result.setCtr(DxvkStatCounter::PipeCountGraphics, pipe.numGraphicsPipelines); result.setCtr(DxvkStatCounter::PipeCountCompute, pipe.numComputePipelines); result.setCtr(DxvkStatCounter::PipeCompilerBusy, m_objects.pipelineManager().isCompilingShaders()); result.setCtr(DxvkStatCounter::GpuIdleTicks, m_submissionQueue.gpuIdleTicks()); std::lock_guard lock(m_statLock); result.merge(m_statCounters); return result; } DxvkMemoryStats DxvkDevice::getMemoryStats(uint32_t heap) { return m_objects.memoryManager().getMemoryStats(heap); } uint32_t DxvkDevice::getCurrentFrameId() const { return m_statCounters.getCtr(DxvkStatCounter::QueuePresentCount); } void DxvkDevice::initResources() { m_objects.dummyResources().clearResources(this); } void DxvkDevice::registerShader(const Rc& shader) { m_objects.pipelineManager().registerShader(shader); } void DxvkDevice::presentImage( const Rc& presenter, VkSemaphore semaphore, DxvkSubmitStatus* status) { status->result = VK_NOT_READY; DxvkPresentInfo presentInfo; presentInfo.presenter = presenter; presentInfo.waitSync = semaphore; m_submissionQueue.present(presentInfo, status); std::lock_guard statLock(m_statLock); m_statCounters.addCtr(DxvkStatCounter::QueuePresentCount, 1); } void DxvkDevice::submitCommandList( const Rc& commandList, VkSemaphore waitSync, VkSemaphore wakeSync) { DxvkSubmitInfo submitInfo; submitInfo.cmdList = commandList; submitInfo.waitSync = waitSync; submitInfo.wakeSync = wakeSync; m_submissionQueue.submit(submitInfo); std::lock_guard statLock(m_statLock); m_statCounters.merge(commandList->statCounters()); m_statCounters.addCtr(DxvkStatCounter::QueueSubmitCount, 1); } VkResult DxvkDevice::waitForSubmission(DxvkSubmitStatus* status) { VkResult result = status->result.load(); if (result == VK_NOT_READY) { m_submissionQueue.synchronizeSubmission(status); result = status->result.load(); } return result; } void DxvkDevice::waitForIdle() { this->lockSubmission(); if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS) Logger::err("DxvkDevice: waitForIdle: Operation failed"); this->unlockSubmission(); } DxvkDevicePerfHints DxvkDevice::getPerfHints() { DxvkDevicePerfHints hints; hints.preferFbDepthStencilCopy = m_extensions.extShaderStencilExport && (m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_MESA_RADV_KHR, 0, 0) || m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0) || m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0)); hints.preferFbResolve = m_extensions.amdShaderFragmentMask && (m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR, 0, 0) || m_adapter->matchesDriver(DxvkGpuVendor::Amd, VK_DRIVER_ID_AMD_PROPRIETARY_KHR, 0, 0)); return hints; } void DxvkDevice::recycleCommandList(const Rc& cmdList) { m_recycledCommandLists.returnObject(cmdList); } void DxvkDevice::recycleDescriptorPool(const Rc& pool) { m_recycledDescriptorPools.returnObject(pool); } DxvkDeviceQueue DxvkDevice::getQueue( uint32_t family, uint32_t index) const { VkQueue queue = VK_NULL_HANDLE; m_vkd->vkGetDeviceQueue(m_vkd->device(), family, index, &queue); return DxvkDeviceQueue { queue, family, index }; } }