1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-07 16:54:14 +01:00

[dxvk] Import swap chain images from the back-end

This commit is contained in:
Philip Rebohle 2025-01-12 17:29:53 +01:00 committed by Philip Rebohle
parent 073806df7c
commit ab9646551f
6 changed files with 66 additions and 165 deletions

View File

@ -387,12 +387,11 @@ namespace dxvk {
return DXGI_STATUS_OCCLUDED; return DXGI_STATUS_OCCLUDED;
// Presentation semaphores and WSI swap chain image // Presentation semaphores and WSI swap chain image
PresenterInfo info = m_presenter->info();
PresenterSync sync; PresenterSync sync;
uint32_t imageIndex = 0; Rc<DxvkImage> backBuffer;
VkResult status = m_presenter->acquireNextImage(sync, imageIndex); VkResult status = m_presenter->acquireNextImage(sync, backBuffer);
while (status != VK_SUCCESS) { while (status != VK_SUCCESS) {
RecreateSwapChain(); RecreateSwapChain();
@ -400,8 +399,7 @@ namespace dxvk {
if (!m_presenter->hasSwapChain()) if (!m_presenter->hasSwapChain())
return DXGI_STATUS_OCCLUDED; return DXGI_STATUS_OCCLUDED;
info = m_presenter->info(); status = m_presenter->acquireNextImage(sync, backBuffer);
status = m_presenter->acquireNextImage(sync, imageIndex);
if (status == VK_SUBOPTIMAL_KHR) if (status == VK_SUBOPTIMAL_KHR)
break; break;
@ -418,11 +416,21 @@ namespace dxvk {
// have to synchronize with it first. // have to synchronize with it first.
m_presentStatus.result = VK_NOT_READY; m_presentStatus.result = VK_NOT_READY;
DxvkImageViewKey viewInfo = { };
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.format = backBuffer->info().format;
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.mipIndex = 0u;
viewInfo.mipCount = 1u;
viewInfo.layerIndex = 0u;
viewInfo.layerCount = 1u;
immediateContext->EmitCs([ immediateContext->EmitCs([
cPresentStatus = &m_presentStatus, cPresentStatus = &m_presentStatus,
cDevice = m_device, cDevice = m_device,
cBlitter = m_blitter, cBlitter = m_blitter,
cBackBuffer = m_imageViews.at(imageIndex), cBackBuffer = backBuffer->createView(viewInfo),
cSwapImage = GetBackBufferView(), cSwapImage = GetBackBufferView(),
cSync = sync, cSync = sync,
cHud = m_hud, cHud = m_hud,
@ -507,8 +515,6 @@ namespace dxvk {
if (vr) if (vr)
throw DxvkError(str::format("D3D11SwapChain: Failed to recreate swap chain: ", vr)); throw DxvkError(str::format("D3D11SwapChain: Failed to recreate swap chain: ", vr));
CreateRenderTargetViews();
} }
@ -539,48 +545,6 @@ namespace dxvk {
} }
void D3D11SwapChain::CreateRenderTargetViews() {
PresenterInfo info = m_presenter->info();
m_imageViews.clear();
m_imageViews.resize(info.imageCount);
DxvkImageCreateInfo imageInfo;
imageInfo.type = VK_IMAGE_TYPE_2D;
imageInfo.format = info.format.format;
imageInfo.flags = 0;
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
imageInfo.numLayers = 1;
imageInfo.mipLevels = 1;
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages = 0;
imageInfo.access = 0;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageInfo.shared = VK_TRUE;
imageInfo.debugName = "Swap image";
DxvkImageViewKey viewInfo;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = info.format.format;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
for (uint32_t i = 0; i < info.imageCount; i++) {
VkImage imageHandle = m_presenter->getImage(i).image;
Rc<DxvkImage> image = m_device->importImage(imageInfo,
imageHandle, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_imageViews[i] = image->createView(viewInfo);
}
}
void D3D11SwapChain::CreateBackBuffers() { void D3D11SwapChain::CreateBackBuffers() {
// Explicitly destroy current swap image before // Explicitly destroy current swap image before
// creating a new one to free up resources // creating a new one to free up resources

View File

@ -113,8 +113,6 @@ namespace dxvk {
small_vector<Com<D3D11Texture2D, false>, 4> m_backBuffers; small_vector<Com<D3D11Texture2D, false>, 4> m_backBuffers;
DxvkSubmitStatus m_presentStatus; DxvkSubmitStatus m_presentStatus;
std::vector<Rc<DxvkImageView>> m_imageViews;
uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS; uint64_t m_frameId = DXGI_MAX_SWAP_CHAIN_BUFFERS;
uint32_t m_frameLatency = DefaultFrameLatency; uint32_t m_frameLatency = DefaultFrameLatency;
uint32_t m_frameLatencyCap = 0; uint32_t m_frameLatencyCap = 0;
@ -147,8 +145,6 @@ namespace dxvk {
void CreatePresenter(); void CreatePresenter();
void CreateRenderTargetViews();
void CreateBackBuffers(); void CreateBackBuffers();
void CreateBlitter(); void CreateBlitter();

View File

@ -833,15 +833,15 @@ namespace dxvk {
PresenterInfo info = m_wctx->presenter->info(); PresenterInfo info = m_wctx->presenter->info();
PresenterSync sync = { }; PresenterSync sync = { };
uint32_t imageIndex = 0; Rc<DxvkImage> backBuffer;
VkResult status = m_wctx->presenter->acquireNextImage(sync, imageIndex); VkResult status = m_wctx->presenter->acquireNextImage(sync, backBuffer);
while (status != VK_SUCCESS) { while (status != VK_SUCCESS) {
RecreateSwapChain(); RecreateSwapChain();
info = m_wctx->presenter->info(); info = m_wctx->presenter->info();
status = m_wctx->presenter->acquireNextImage(sync, imageIndex); status = m_wctx->presenter->acquireNextImage(sync, backBuffer);
if (status == VK_SUBOPTIMAL_KHR) if (status == VK_SUBOPTIMAL_KHR)
break; break;
@ -868,6 +868,16 @@ namespace dxvk {
// have to synchronize with it first. // have to synchronize with it first.
m_presentStatus.result = VK_NOT_READY; m_presentStatus.result = VK_NOT_READY;
DxvkImageViewKey viewInfo;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.format = backBuffer->info().format;
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.mipIndex = 0u;
viewInfo.mipCount = 1u;
viewInfo.layerIndex = 0u;
viewInfo.layerCount = 1u;
m_parent->EmitCs([ m_parent->EmitCs([
cPresentStatus = &m_presentStatus, cPresentStatus = &m_presentStatus,
cDevice = m_device, cDevice = m_device,
@ -876,7 +886,7 @@ namespace dxvk {
cColorSpace = m_colorspace, cColorSpace = m_colorspace,
cSrcView = swapImageView, cSrcView = swapImageView,
cSrcRect = srcRect, cSrcRect = srcRect,
cDstView = m_wctx->imageViews.at(imageIndex), cDstView = backBuffer->createView(viewInfo),
cDstRect = dstRect, cDstRect = dstRect,
cRepeat = i, cRepeat = i,
cSync = sync, cSync = sync,
@ -948,8 +958,6 @@ namespace dxvk {
if (vr) if (vr)
throw DxvkError(str::format("D3D9SwapChainEx: Failed to recreate swap chain: ", vr)); throw DxvkError(str::format("D3D9SwapChainEx: Failed to recreate swap chain: ", vr));
CreateRenderTargetViews();
} }
@ -980,47 +988,6 @@ namespace dxvk {
} }
void D3D9SwapChainEx::CreateRenderTargetViews() {
PresenterInfo info = m_wctx->presenter->info();
m_wctx->imageViews.clear();
m_wctx->imageViews.resize(info.imageCount);
DxvkImageCreateInfo imageInfo;
imageInfo.type = VK_IMAGE_TYPE_2D;
imageInfo.format = info.format.format;
imageInfo.flags = 0;
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
imageInfo.extent = { info.imageExtent.width, info.imageExtent.height, 1 };
imageInfo.numLayers = 1;
imageInfo.mipLevels = 1;
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages = 0;
imageInfo.access = 0;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageInfo.shared = VK_TRUE;
DxvkImageViewKey viewInfo;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = info.format.format;
viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
viewInfo.aspects = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.mipIndex = 0;
viewInfo.mipCount = 1;
viewInfo.layerIndex = 0;
viewInfo.layerCount = 1;
for (uint32_t i = 0; i < info.imageCount; i++) {
VkImage imageHandle = m_wctx->presenter->getImage(i).image;
Rc<DxvkImage> image = m_device->importImage(imageInfo,
imageHandle, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_wctx->imageViews[i] = image->createView(viewInfo);
}
}
void D3D9SwapChainEx::DestroyBackBuffers() { void D3D9SwapChainEx::DestroyBackBuffers() {
for (auto& backBuffer : m_backBuffers) for (auto& backBuffer : m_backBuffers)
backBuffer->ClearContainer(); backBuffer->ClearContainer();

View File

@ -52,7 +52,6 @@ namespace dxvk {
struct D3D9WindowContext { struct D3D9WindowContext {
Rc<Presenter> presenter; Rc<Presenter> presenter;
std::vector<Rc<DxvkImageView>> imageViews;
uint64_t frameId = D3D9DeviceEx::MaxFrameLatency; uint64_t frameId = D3D9DeviceEx::MaxFrameLatency;
Rc<sync::Fence> frameLatencySignal; Rc<sync::Fence> frameLatencySignal;
@ -199,8 +198,6 @@ namespace dxvk {
void CreatePresenter(); void CreatePresenter();
void CreateRenderTargetViews();
HRESULT CreateBackBuffers( HRESULT CreateBackBuffers(
uint32_t NumBackBuffers, uint32_t NumBackBuffers,
DWORD Flags); DWORD Flags);

View File

@ -51,12 +51,7 @@ namespace dxvk {
} }
PresenterImage Presenter::getImage(uint32_t index) const { VkResult Presenter::acquireNextImage(PresenterSync& sync, Rc<DxvkImage>& image) {
return m_images.at(index);
}
VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) {
PresenterSync& semaphores = m_semaphores.at(m_frameIndex); PresenterSync& semaphores = m_semaphores.at(m_frameIndex);
sync = semaphores; sync = semaphores;
@ -72,7 +67,7 @@ namespace dxvk {
if (m_acquireStatus != VK_SUCCESS && m_acquireStatus != VK_SUBOPTIMAL_KHR) if (m_acquireStatus != VK_SUCCESS && m_acquireStatus != VK_SUBOPTIMAL_KHR)
return m_acquireStatus; return m_acquireStatus;
index = m_imageIndex; image = m_images.at(m_imageIndex);
return m_acquireStatus; return m_acquireStatus;
} }
@ -362,25 +357,25 @@ namespace dxvk {
// Update actual image count // Update actual image count
m_info.imageCount = images.size(); m_info.imageCount = images.size();
m_images.resize(m_info.imageCount);
for (uint32_t i = 0; i < m_info.imageCount; i++) { for (uint32_t i = 0; i < m_info.imageCount; i++) {
m_images[i].image = images[i]; std::string debugName = str::format("Vulkan swap image ", i);
VkImageViewCreateInfo viewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; DxvkImageCreateInfo imageInfo = { };
viewInfo.image = images[i]; imageInfo.type = VK_IMAGE_TYPE_2D;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; imageInfo.format = swapInfo.imageFormat;
viewInfo.format = m_info.format.format; imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
viewInfo.components = VkComponentMapping { imageInfo.extent = { swapInfo.imageExtent.width, swapInfo.imageExtent.height, 1u };
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, imageInfo.numLayers = swapInfo.imageArrayLayers;
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY }; imageInfo.mipLevels = 1u;
viewInfo.subresourceRange = { imageInfo.usage = swapInfo.imageUsage;
VK_IMAGE_ASPECT_COLOR_BIT, imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
0, 1, 0, 1 }; imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageInfo.shared = VK_TRUE;
if ((status = m_vkd->vkCreateImageView(m_vkd->device(), imageInfo.debugName = debugName.c_str();
&viewInfo, nullptr, &m_images[i].view)))
return status; m_images.push_back(m_device->importImage(imageInfo, images[i],
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
} }
// Create one set of semaphores per swap image, as well as a fence // Create one set of semaphores per swap image, as well as a fence
@ -678,9 +673,6 @@ namespace dxvk {
for (auto& sem : m_semaphores) for (auto& sem : m_semaphores)
waitForSwapchainFence(sem); waitForSwapchainFence(sem);
for (const auto& img : m_images)
m_vkd->vkDestroyImageView(m_vkd->device(), img.view, nullptr);
for (const auto& sem : m_semaphores) { for (const auto& sem : m_semaphores) {
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, nullptr); m_vkd->vkDestroySemaphore(m_vkd->device(), sem.acquire, nullptr);
m_vkd->vkDestroySemaphore(m_vkd->device(), sem.present, nullptr); m_vkd->vkDestroySemaphore(m_vkd->device(), sem.present, nullptr);

View File

@ -16,6 +16,7 @@
#include "../vulkan/vulkan_loader.h" #include "../vulkan/vulkan_loader.h"
#include "dxvk_format.h" #include "dxvk_format.h"
#include "dxvk_image.h"
namespace dxvk { namespace dxvk {
@ -51,14 +52,6 @@ namespace dxvk {
uint32_t syncInterval; uint32_t syncInterval;
}; };
/**
* \brief Swap image and view
*/
struct PresenterImage {
VkImage image = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
};
/** /**
* \brief Presenter semaphores * \brief Presenter semaphores
* *
@ -108,16 +101,6 @@ namespace dxvk {
*/ */
PresenterInfo info() const; PresenterInfo info() const;
/**
* \brief Retrieves image by index
*
* Can be used to create per-image objects.
* \param [in] index Image index
* \returns Image handle
*/
PresenterImage getImage(
uint32_t index) const;
/** /**
* \brief Acquires next image * \brief Acquires next image
* *
@ -126,12 +109,12 @@ namespace dxvk {
* must be recreated and a new image must * must be recreated and a new image must
* be acquired before proceeding. * be acquired before proceeding.
* \param [out] sync Synchronization semaphores * \param [out] sync Synchronization semaphores
* \param [out] index Acquired image index * \param [out] image Acquired swap chain image
* \returns Status of the operation * \returns Status of the operation
*/ */
VkResult acquireNextImage( VkResult acquireNextImage(
PresenterSync& sync, PresenterSync& sync,
uint32_t& index); Rc<DxvkImage>& image);
/** /**
* \brief Presents current image * \brief Presents current image
@ -222,32 +205,31 @@ namespace dxvk {
private: private:
Rc<DxvkDevice> m_device; Rc<DxvkDevice> m_device;
Rc<sync::Signal> m_signal; Rc<sync::Signal> m_signal;
Rc<vk::InstanceFn> m_vki; Rc<vk::InstanceFn> m_vki;
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
PresenterInfo m_info = { }; PresenterInfo m_info = { };
PresenterSurfaceProc m_surfaceProc; PresenterSurfaceProc m_surfaceProc;
VkSurfaceKHR m_surface = VK_NULL_HANDLE; VkSurfaceKHR m_surface = VK_NULL_HANDLE;
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
VkFullScreenExclusiveEXT m_fullscreenMode = VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT; VkFullScreenExclusiveEXT m_fullscreenMode = VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT;
std::vector<PresenterImage> m_images; std::vector<Rc<DxvkImage>> m_images;
std::vector<PresenterSync> m_semaphores; std::vector<PresenterSync> m_semaphores;
std::vector<VkPresentModeKHR> m_dynamicModes; std::vector<VkPresentModeKHR> m_dynamicModes;
uint32_t m_imageIndex = 0; uint32_t m_imageIndex = 0;
uint32_t m_frameIndex = 0; uint32_t m_frameIndex = 0;
VkResult m_acquireStatus = VK_NOT_READY; VkResult m_acquireStatus = VK_NOT_READY;
FpsLimiter m_fpsLimiter;
alignas(CACHE_LINE_SIZE)
dxvk::mutex m_frameMutex; dxvk::mutex m_frameMutex;
dxvk::condition_variable m_frameCond; dxvk::condition_variable m_frameCond;
dxvk::thread m_frameThread; dxvk::thread m_frameThread;
@ -255,6 +237,9 @@ namespace dxvk {
std::atomic<uint64_t> m_lastFrameId = { 0ull }; std::atomic<uint64_t> m_lastFrameId = { 0ull };
alignas(CACHE_LINE_SIZE)
FpsLimiter m_fpsLimiter;
VkResult createSwapChain( VkResult createSwapChain(
const PresenterDesc& desc); const PresenterDesc& desc);