Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/doitsujin/dxvk.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Rebohle <philip.rebohle@tu-dortmund.de>2023-08-16 18:16:07 +0300
committerPhilip Rebohle <philip.rebohle@tu-dortmund.de>2023-08-16 18:16:07 +0300
commit04694fb0b8aedcdf013da259f64d57835c7a1a83 (patch)
tree6366bdcc9527af3c007476e1b4989a73f07ac21a
parent981336c402e505d8268ba33d1a5a89fabb836939 (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.cpp130
-rw-r--r--src/d3d11/d3d11_swapchain.h54
-rw-r--r--src/d3d11/d3d11_texture.cpp4
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;
}