diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 0e823f410..d9cc61723 100644 --- a/src/d3d11/d3d11_swapchain.cpp +++ b/src/d3d11/d3d11_swapchain.cpp @@ -140,12 +140,12 @@ namespace dxvk { void** ppBuffer) { InitReturnPtr(ppBuffer); - if (BufferId > 0) { - Logger::err("D3D11: GetImage: BufferId > 0 not supported"); + if (BufferId > m_backBuffers.size()) { + Logger::err(str::format("D3D11: Invalid buffer index: ", BufferId)); return DXGI_ERROR_UNSUPPORTED; } - return m_backBuffer->QueryInterface(riid, ppBuffer); + return m_backBuffers[BufferId]->QueryInterface(riid, ppBuffer); } @@ -396,7 +396,10 @@ namespace dxvk { if (m_hud != nullptr) m_hud->render(m_context, info.format, info.imageExtent); - + + if (!SyncInterval || i == SyncInterval - 1) + RotateBackBuffer(); + SubmitPresent(immediateContext, sync, i); } @@ -559,11 +562,25 @@ namespace dxvk { void D3D11SwapChain::CreateBackBuffer() { + bool sequentialPresent = false; + + if (IsSequentialSwapChain()) { + if (!(sequentialPresent = SupportsSparseImages())) { + Logger::warn("Sequential present mode requeted, but sparse images not supported" + "by the Vulkan implementation. Falling back to Discard semantics."); + } + } + // Explicitly destroy current swap image before // creating a new one to free up resources - m_swapImage = nullptr; - m_swapImageView = nullptr; - m_backBuffer = nullptr; + m_swapImages.clear(); + m_backBuffers.clear(); + m_swapImageView = nullptr; + + uint32_t bufferCount = 1u; + + if (sequentialPresent) + bufferCount = m_desc.BufferCount; // Create new back buffer D3D11_COMMON_TEXTURE_DESC desc; @@ -592,27 +609,47 @@ namespace dxvk { if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE) desc.MiscFlags |= D3D11_RESOURCE_MISC_GDI_COMPATIBLE; + if (sequentialPresent) + desc.MiscFlags |= D3D11_RESOURCE_MISC_TILED; + DXGI_USAGE dxgiUsage = DXGI_USAGE_BACK_BUFFER; if (m_desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD || m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD) dxgiUsage |= DXGI_USAGE_DISCARD_ON_PRESENT; - m_backBuffer = new D3D11Texture2D(m_parent, this, &desc, dxgiUsage); - m_swapImage = GetCommonTexture(m_backBuffer.ptr())->GetImage(); + for (uint32_t i = 0; i < bufferCount; i++) { + m_backBuffers.push_back(new D3D11Texture2D(m_parent, this, &desc, dxgiUsage)); + m_swapImages.push_back(GetCommonTexture(m_backBuffers.back().ptr())->GetImage()); + + dxgiUsage |= DXGI_USAGE_READ_ONLY; + } + + // If necessary, create a sparse page allocator + m_sparseFrameIndex = 0; + + if (sequentialPresent) { + m_sparsePagesPerImage = m_swapImages.front()->getSparsePageTable()->getPageCount(); + + m_sparseAllocator = m_device->createSparsePageAllocator(); + m_sparseAllocator->setCapacity(m_sparsePagesPerImage * bufferCount); + } else { + m_sparsePagesPerImage = 0; + m_sparseAllocator = nullptr; + } // Create an image view that allows the // image to be bound as a shader resource. DxvkImageViewCreateInfo viewInfo; viewInfo.type = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = m_swapImage->info().format; + viewInfo.format = m_swapImages.front()->info().format; viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.minLevel = 0; viewInfo.numLevels = 1; viewInfo.minLayer = 0; viewInfo.numLayers = 1; - m_swapImageView = m_device->createImageView(m_swapImage, viewInfo); + m_swapImageView = m_device->createImageView(m_swapImages.front(), viewInfo); // Initialize the image so that we can use it. Clearing // to black prevents garbled output for the first frame. @@ -626,8 +663,30 @@ namespace dxvk { m_context->beginRecording( m_device->createCommandList()); - m_context->initImage(m_swapImage, - subresources, VK_IMAGE_LAYOUT_UNDEFINED); + for (uint32_t i = 0; i < m_swapImages.size(); i++) { + if (sequentialPresent) { + DxvkSparseBindInfo sparseBind; + sparseBind.dstResource = m_swapImages[i]; + sparseBind.srcAllocator = m_sparseAllocator; + + for (uint32_t j = 0; j < m_sparsePagesPerImage; j++) { + auto& bind = sparseBind.binds.emplace_back(); + bind.mode = DxvkSparseBindMode::Bind; + bind.srcPage = j + i * m_sparsePagesPerImage; + bind.dstPage = j; + } + + m_context->updatePageTable(sparseBind, + DxvkSparseBindFlag::SkipSynchronization); + m_context->initSparseImage(m_swapImages[i]); + + Rc view = m_device->createImageView(m_swapImages.front(), viewInfo); + m_context->clearRenderTarget(view, VK_IMAGE_ASPECT_COLOR_BIT, VkClearValue()); + } else { + m_context->initImage(m_swapImages[i], + subresources, VK_IMAGE_LAYOUT_UNDEFINED); + } + } m_device->submitCommandList( m_context->endRecording(), @@ -738,6 +797,51 @@ namespace dxvk { } + void D3D11SwapChain::RotateBackBuffer() { + uint32_t bufferCount = m_swapImages.size(); + + if (bufferCount < 2) + return; + + m_sparseFrameIndex += 1; + m_sparseFrameIndex %= bufferCount; + + for (uint32_t i = 0; i < bufferCount; i++) { + uint32_t firstImage = (m_sparseFrameIndex + i) % bufferCount; + + DxvkSparseBindInfo sparseBind; + sparseBind.dstResource = m_swapImages[i]; + sparseBind.srcAllocator = m_sparseAllocator; + + for (uint32_t j = 0; j < m_sparsePagesPerImage; j++) { + auto& bind = sparseBind.binds.emplace_back(); + bind.mode = DxvkSparseBindMode::Bind; + bind.srcPage = j + firstImage * m_sparsePagesPerImage; + bind.dstPage = j; + } + + m_context->updatePageTable(sparseBind, 0); + } + } + + + bool D3D11SwapChain::IsSequentialSwapChain() const { + return m_desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL + || m_desc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + } + + + bool D3D11SwapChain::SupportsSparseImages() const { + const auto& properties = m_device->properties().core.properties; + const auto& features = m_device->features().core.features; + + return features.sparseBinding + && features.sparseResidencyImage2D + && features.sparseResidencyAliased + && properties.sparseProperties.residencyStandard2DBlockShape; + } + + std::string D3D11SwapChain::GetApiName() const { Com device; m_parent->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast(&device)); diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index 00073d769..df9f5f164 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -95,42 +95,46 @@ namespace dxvk { Com m_dxgiDevice; - D3D11Device* m_parent; - Com m_surfaceFactory; + D3D11Device* m_parent; + Com m_surfaceFactory; - DXGI_SWAP_CHAIN_DESC1 m_desc; + DXGI_SWAP_CHAIN_DESC1 m_desc; - Rc m_device; - Rc m_context; + Rc m_device; + Rc m_context; - Rc m_presenter; + Rc m_presenter; - Rc m_swapImage; - Rc m_swapImageView; - Rc m_blitter; + uint32_t m_sparseFrameIndex = 0u; + uint32_t m_sparsePagesPerImage = 0u; + Rc m_sparseAllocator; - Rc m_hud; + std::vector> m_swapImages; + Rc m_swapImageView; + Rc m_blitter; - Com m_backBuffer; - DxvkSubmitStatus m_presentStatus; + Rc m_hud; + + std::vector> m_backBuffers; + DxvkSubmitStatus m_presentStatus; std::vector> m_imageViews; - uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS; - uint32_t m_frameLatency = DefaultFrameLatency; - uint32_t m_frameLatencyCap = 0; - HANDLE m_frameLatencyEvent = nullptr; - Rc m_frameLatencySignal; + uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS; + uint32_t m_frameLatency = DefaultFrameLatency; + uint32_t m_frameLatencyCap = 0; + HANDLE m_frameLatencyEvent = nullptr; + Rc m_frameLatencySignal; - bool m_dirty = true; + bool m_dirty = true; - VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; std::optional m_hdrMetadata; - bool m_dirtyHdrMetadata = true; + bool m_dirtyHdrMetadata = true; - dxvk::mutex m_frameStatisticsLock; - DXGI_VK_FRAME_STATISTICS m_frameStatistics = { }; + dxvk::mutex m_frameStatisticsLock; + DXGI_VK_FRAME_STATISTICS m_frameStatistics = { }; HRESULT PresentImage(UINT SyncInterval); @@ -172,6 +176,12 @@ namespace dxvk { VkFullScreenExclusiveEXT PickFullscreenMode(); + void RotateBackBuffer(); + + bool IsSequentialSwapChain() const; + + bool SupportsSparseImages() const; + std::string GetApiName() const; }; diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index 7a8c60439..26e7bea6c 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -249,6 +249,10 @@ namespace dxvk { if (imageInfo.sharing.mode == DxvkSharedHandleMode::Export) ExportImageInfo(); + + // Hide some internal flags as necessary + if (DxgiUsage & DXGI_USAGE_BACK_BUFFER) + m_desc.MiscFlags &= ~D3D11_RESOURCE_MISC_TILED; }