diff options
author | Philip Rebohle <philip.rebohle@tu-dortmund.de> | 2023-08-16 18:16:07 +0300 |
---|---|---|
committer | Philip Rebohle <philip.rebohle@tu-dortmund.de> | 2023-08-16 18:16:07 +0300 |
commit | 04694fb0b8aedcdf013da259f64d57835c7a1a83 (patch) | |
tree | 6366bdcc9527af3c007476e1b4989a73f07ac21a | |
parent | 981336c402e505d8268ba33d1a5a89fabb836939 (diff) |
[d3d11] Implement DXGI_SWAP_EFFECT_SEQUENTIAL and FLIP_SEQUENTIALdxgi-sequential
Requires sparse since we have no other means to swap the backing image.
-rw-r--r-- | src/d3d11/d3d11_swapchain.cpp | 130 | ||||
-rw-r--r-- | src/d3d11/d3d11_swapchain.h | 54 | ||||
-rw-r--r-- | src/d3d11/d3d11_texture.cpp | 4 |
3 files changed, 153 insertions, 35 deletions
diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp index 0e823f41..d9cc6172 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<DxvkImageView> 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<IDXGIDXVKDevice> device; m_parent->QueryInterface(__uuidof(IDXGIDXVKDevice), reinterpret_cast<void**>(&device)); diff --git a/src/d3d11/d3d11_swapchain.h b/src/d3d11/d3d11_swapchain.h index 00073d76..df9f5f16 100644 --- a/src/d3d11/d3d11_swapchain.h +++ b/src/d3d11/d3d11_swapchain.h @@ -95,42 +95,46 @@ namespace dxvk { Com<D3D11DXGIDevice, false> m_dxgiDevice; - D3D11Device* m_parent; - Com<IDXGIVkSurfaceFactory> m_surfaceFactory; + D3D11Device* m_parent; + Com<IDXGIVkSurfaceFactory> m_surfaceFactory; - DXGI_SWAP_CHAIN_DESC1 m_desc; + DXGI_SWAP_CHAIN_DESC1 m_desc; - Rc<DxvkDevice> m_device; - Rc<DxvkContext> m_context; + Rc<DxvkDevice> m_device; + Rc<DxvkContext> m_context; - Rc<Presenter> m_presenter; + Rc<Presenter> m_presenter; - Rc<DxvkImage> m_swapImage; - Rc<DxvkImageView> m_swapImageView; - Rc<DxvkSwapchainBlitter> m_blitter; + uint32_t m_sparseFrameIndex = 0u; + uint32_t m_sparsePagesPerImage = 0u; + Rc<DxvkSparsePageAllocator> m_sparseAllocator; - Rc<hud::Hud> m_hud; + std::vector<Rc<DxvkImage>> m_swapImages; + Rc<DxvkImageView> m_swapImageView; + Rc<DxvkSwapchainBlitter> m_blitter; - Com<D3D11Texture2D, false> m_backBuffer; - DxvkSubmitStatus m_presentStatus; + Rc<hud::Hud> m_hud; + + std::vector<Com<D3D11Texture2D, false>> m_backBuffers; + DxvkSubmitStatus m_presentStatus; std::vector<Rc<DxvkImageView>> 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<sync::CallbackFence> 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<sync::CallbackFence> 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<VkHdrMetadataEXT> 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 7a8c6043..26e7bea6 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; } |