#include "dxvk_cmdlist.h" #include "dxvk_device.h" namespace dxvk { DxvkCommandList::DxvkCommandList( DxvkDevice* device, uint32_t queueFamily) : m_vkd (device->vkd()), m_cmdBuffersUsed(0), m_descriptorPoolTracker(device), m_stagingAlloc (device) { VkFenceCreateInfo fenceInfo; fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.pNext = nullptr; fenceInfo.flags = 0; if (m_vkd->vkCreateFence(m_vkd->device(), &fenceInfo, nullptr, &m_fence) != VK_SUCCESS) throw DxvkError("DxvkCommandList: Failed to create fence"); VkCommandPoolCreateInfo poolInfo; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.pNext = nullptr; poolInfo.flags = 0; poolInfo.queueFamilyIndex = queueFamily; if (m_vkd->vkCreateCommandPool(m_vkd->device(), &poolInfo, nullptr, &m_pool) != VK_SUCCESS) throw DxvkError("DxvkCommandList: Failed to create command pool"); VkCommandBufferAllocateInfo cmdInfo; cmdInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cmdInfo.pNext = nullptr; cmdInfo.commandPool = m_pool; cmdInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmdInfo.commandBufferCount = 1; if (m_vkd->vkAllocateCommandBuffers(m_vkd->device(), &cmdInfo, &m_execBuffer) != VK_SUCCESS || m_vkd->vkAllocateCommandBuffers(m_vkd->device(), &cmdInfo, &m_initBuffer) != VK_SUCCESS) throw DxvkError("DxvkCommandList: Failed to allocate command buffer"); } DxvkCommandList::~DxvkCommandList() { this->reset(); m_vkd->vkDestroyCommandPool(m_vkd->device(), m_pool, nullptr); m_vkd->vkDestroyFence (m_vkd->device(), m_fence, nullptr); } VkResult DxvkCommandList::submit( VkQueue queue, VkSemaphore waitSemaphore, VkSemaphore wakeSemaphore) { std::array cmdBuffers; uint32_t cmdBufferCount = 0; if (m_cmdBuffersUsed.test(DxvkCmdBuffer::InitBuffer)) cmdBuffers[cmdBufferCount++] = m_initBuffer; if (m_cmdBuffersUsed.test(DxvkCmdBuffer::ExecBuffer)) cmdBuffers[cmdBufferCount++] = m_execBuffer; const VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; VkSubmitInfo info; info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; info.pNext = nullptr; info.waitSemaphoreCount = waitSemaphore == VK_NULL_HANDLE ? 0 : 1; info.pWaitSemaphores = &waitSemaphore; info.pWaitDstStageMask = &waitStageMask; info.commandBufferCount = cmdBufferCount; info.pCommandBuffers = cmdBuffers.data(); info.signalSemaphoreCount = wakeSemaphore == VK_NULL_HANDLE ? 0 : 1; info.pSignalSemaphores = &wakeSemaphore; return m_vkd->vkQueueSubmit(queue, 1, &info, m_fence); } VkResult DxvkCommandList::synchronize() { VkResult status = VK_TIMEOUT; while (status == VK_TIMEOUT) { status = m_vkd->vkWaitForFences( m_vkd->device(), 1, &m_fence, VK_FALSE, 1'000'000'000ull); } return status; } void DxvkCommandList::beginRecording() { VkCommandBufferBeginInfo info; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; info.pNext = nullptr; info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; info.pInheritanceInfo = nullptr; if (m_vkd->vkResetCommandPool(m_vkd->device(), m_pool, 0) != VK_SUCCESS) Logger::err("DxvkCommandList: Failed to reset command buffer"); if (m_vkd->vkBeginCommandBuffer(m_execBuffer, &info) != VK_SUCCESS || m_vkd->vkBeginCommandBuffer(m_initBuffer, &info) != VK_SUCCESS) Logger::err("DxvkCommandList: Failed to begin command buffer"); if (m_vkd->vkResetFences(m_vkd->device(), 1, &m_fence) != VK_SUCCESS) Logger::err("DxvkCommandList: Failed to reset fence"); // Unconditionally mark the exec buffer as used. There // is virtually no use case where this isn't correct. m_cmdBuffersUsed.set(DxvkCmdBuffer::ExecBuffer); } void DxvkCommandList::endRecording() { if (m_vkd->vkEndCommandBuffer(m_execBuffer) != VK_SUCCESS || m_vkd->vkEndCommandBuffer(m_initBuffer) != VK_SUCCESS) Logger::err("DxvkCommandList::endRecording: Failed to record command buffer"); } void DxvkCommandList::reset() { m_statCounters.reset(); m_bufferTracker.reset(); m_gpuQueryTracker.reset(); m_gpuEventTracker.reset(); m_eventTracker.reset(); m_stagingAlloc.reset(); m_descriptorPoolTracker.reset(); m_resources.reset(); } DxvkStagingBufferSlice DxvkCommandList::stagedAlloc(VkDeviceSize size) { return m_stagingAlloc.alloc(size); } void DxvkCommandList::stagedBufferCopy( DxvkCmdBuffer cmdBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const DxvkStagingBufferSlice& dataSlice) { m_cmdBuffersUsed.set(cmdBuffer); VkBufferCopy region; region.srcOffset = dataSlice.offset; region.dstOffset = dstOffset; region.size = dataSize; m_vkd->vkCmdCopyBuffer(getCmdBuffer(cmdBuffer), dataSlice.buffer, dstBuffer, 1, ®ion); } void DxvkCommandList::stagedBufferImageCopy( VkImage dstImage, VkImageLayout dstImageLayout, const VkBufferImageCopy& dstImageRegion, const DxvkStagingBufferSlice& dataSlice) { m_vkd->vkCmdCopyBufferToImage(m_execBuffer, dataSlice.buffer, dstImage, dstImageLayout, 1, &dstImageRegion); } }