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:
authorJoshua Ashton <joshua@froggi.es>2020-02-27 09:12:30 +0300
committerJoshua Ashton <joshua@froggi.es>2020-02-27 09:12:30 +0300
commitb625558c71b71af8e61441dfc719ef933db758ad (patch)
treed81e2cb06495950beb707da293aea83cc491e533
parent92fd84b4b2f9ee08ed3ab4fa22cec62a8495cc71 (diff)
[d3d9] Refactor swapchain window overrides to have an additional presenter abstractiond3d9-partial-presentation
-rw-r--r--src/d3d9/d3d9_device.h2
-rw-r--r--src/d3d9/d3d9_swapchain.cpp1139
-rw-r--r--src/d3d9/d3d9_swapchain.h194
3 files changed, 722 insertions, 613 deletions
diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h
index 3b0d3e7c..1095e7bf 100644
--- a/src/d3d9/d3d9_device.h
+++ b/src/d3d9/d3d9_device.h
@@ -103,6 +103,8 @@ namespace dxvk {
constexpr static uint32_t NullStreamIdx = caps::MaxStreams;
friend class D3D9SwapChainEx;
+ friend class D3D9Presenter;
+ friend class D3D9PresentationInfo;
public:
D3D9DeviceEx(
diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp
index 5c5d55e1..c74c1f07 100644
--- a/src/d3d9/d3d9_swapchain.cpp
+++ b/src/d3d9/d3d9_swapchain.cpp
@@ -22,25 +22,450 @@ namespace dxvk {
};
+ D3D9PresentationInfo::D3D9PresentationInfo(D3D9DeviceEx* pDevice)
+ : device (pDevice->GetDXVKDevice())
+ , context (device->createContext())
+ , frameLatencySignal(new sync::Fence(D3D9DeviceEx::MaxFrameLatency))
+ , dialog (pDevice->GetOptions()->enableDialogMode)
+ , frameLatencyCap (pDevice->GetOptions()->maxFrameLatency) {
+
+ }
+
+
+ D3D9Presenter::D3D9Presenter(
+ const D3D9PresentationInfo& Info,
+ D3D9SwapChainEx* pParent,
+ HWND hWindow)
+ : m_parent (pParent)
+ , m_window (hWindow)
+ , m_info (Info) {
+ if (!pParent->GetParent()->GetOptions()->deferSurfaceCreation)
+ CreatePresenter();
+ }
+
+
+ D3D9Presenter::~D3D9Presenter() {
+ m_info.device->waitForSubmission(&m_presentStatus);
+ m_info.device->waitForIdle();
+ }
+
+
+ HRESULT D3D9Presenter::Present(
+ UINT SyncInterval,
+ const RECT* pSourceRect,
+ const RECT* pDestRect) {
+ bool vsync = SyncInterval != 0;
+
+ bool recreate = false;
+ recreate |= m_presenter == nullptr;
+ recreate |= m_info.dialog != m_lastDialog;
+ recreate |= m_presentExtent != GetPresentExtent();
+
+ m_dirty |= vsync != m_vsync;
+ m_dirty |= recreate;
+ m_dirty |= m_presenter != nullptr &&
+ !m_presenter->hasSwapChain();
+
+ m_vsync = vsync;
+
+ m_lastDialog = m_info.dialog;
+
+ try {
+ if (recreate)
+ CreatePresenter();
+
+ if (std::exchange(m_dirty, false))
+ RecreateSwapChain(vsync);
+
+ // We aren't going to device loss simply because
+ // 99% of D3D9 games don't handle this properly and
+ // just end up crashing (like with alt-tab loss)
+ if (!m_presenter->hasSwapChain())
+ return D3D_OK;
+
+ PresentImage(SyncInterval, pSourceRect, pDestRect);
+ return D3D_OK;
+ } catch (const DxvkError& e) {
+ Logger::err(e.message());
+ return D3DERR_DEVICEREMOVED;
+ }
+ }
+
+
+ void D3D9Presenter::PresentImage(
+ UINT SyncInterval,
+ const RECT* pSourceRect,
+ const RECT* pDestRect) {
+ m_parent->GetParent()->Flush();
+
+ // Retrieve the image and image view to present
+ auto swapImage = m_parent->m_info.backBuffers[0]->GetCommonTexture()->GetImage();
+ auto swapImageView = m_info.resolveImageView;
+
+ if (swapImageView == nullptr)
+ swapImageView = m_parent->m_info.backBuffers[0]->GetImageView(false);
+
+ // Wait for the sync event so that we respect the maximum frame latency
+ uint64_t frameId = ++m_parent->m_info.frameId;
+ m_parent->m_info.frameLatencySignal->wait(frameId - m_parent->GetActualFrameLatency());
+
+ for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
+ SynchronizePresent();
+
+ m_info.context->beginRecording(
+ m_info.device->createCommandList());
+
+ // Resolve back buffer if it is multisampled. We
+ // only have to do it only for the first frame.
+ if (m_info.resolveImage != nullptr && i == 0) {
+ VkImageSubresourceLayers resolveSubresource;
+ resolveSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ resolveSubresource.mipLevel = 0;
+ resolveSubresource.baseArrayLayer = 0;
+ resolveSubresource.layerCount = 1;
+
+ VkImageResolve resolveRegion;
+ resolveRegion.srcSubresource = resolveSubresource;
+ resolveRegion.srcOffset = VkOffset3D { 0, 0, 0 };
+ resolveRegion.dstSubresource = resolveSubresource;
+ resolveRegion.dstOffset = VkOffset3D { 0, 0, 0 };
+ resolveRegion.extent = swapImage->info().extent;
+
+ m_info.context->resolveImage(
+ m_info.resolveImage, swapImage,
+ resolveRegion, VK_FORMAT_UNDEFINED);
+ }
+
+ // Presentation semaphores and WSI swap chain image
+ vk::PresenterInfo info = m_presenter->info();
+ vk::PresenterSync sync = m_presenter->getSyncSemaphores();
+
+ uint32_t imageIndex = 0;
+
+ VkResult status = m_presenter->acquireNextImage(
+ sync.acquire, VK_NULL_HANDLE, imageIndex);
+
+ while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
+ RecreateSwapChain(m_vsync);
+
+ info = m_presenter->info();
+ sync = m_presenter->getSyncSemaphores();
+
+ status = m_presenter->acquireNextImage(
+ sync.acquire, VK_NULL_HANDLE, imageIndex);
+ }
+
+ const bool partialPresent =
+ m_parent->m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY &&
+ (pDestRect->left != 0 ||
+ pDestRect->top != 0 ||
+ pDestRect->right != m_presentExtent.width ||
+ pDestRect->bottom != m_presentExtent.height);
+
+ if (partialPresent && !m_partialPresented) {
+ const VkImageSubresourceLayers subresourceLayers = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, 0, 1 };
+
+ VkImageBlit region;
+ region.dstOffsets[0] = VkOffset3D{ 0, 0, 0 };
+ region.dstOffsets[1] = VkOffset3D{ int32_t(m_presentExtent.width), int32_t(m_presentExtent.height), 1 };
+ region.dstSubresource = subresourceLayers;
+ region.srcOffsets[0] = region.dstOffsets[0];
+ region.srcOffsets[1] = region.dstOffsets[1];
+ region.srcSubresource = region.dstSubresource;
+
+ const auto& lastImage = m_parent->m_info.backBuffers[m_parent->m_presentParams.BackBufferCount]->GetCommonTexture()->GetImage();
+
+ m_info.context->blitImage(
+ m_copyImage, VkComponentMapping{ },
+ lastImage, VkComponentMapping{ },
+ region, VK_FILTER_NEAREST);
+ }
+
+ // Use an appropriate texture filter depending on whether
+ // the back buffer size matches the swap image size
+ m_info.context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_parent->m_info.vertShader);
+ m_info.context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_parent->m_info.fragShader);
+
+ DxvkRenderTargets renderTargets;
+ renderTargets.color[0].view = partialPresent ? m_copyImageView : m_imageViews.at(imageIndex);
+ renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ m_info.context->bindRenderTargets(renderTargets);
+
+ VkViewport viewport;
+ viewport.x = float(pDestRect->left);
+ viewport.y = float(pDestRect->top);
+ viewport.width = float(pDestRect->right - pDestRect->left);
+ viewport.height = float(pDestRect->bottom - pDestRect->top);
+ viewport.minDepth = 0.0f;
+ viewport.maxDepth = 1.0f;
+
+ VkRect2D scissor;
+ scissor.offset.x = pDestRect->left;
+ scissor.offset.y = pDestRect->top;
+ scissor.extent.width = pDestRect->right - pDestRect->left;
+ scissor.extent.height = pDestRect->bottom - pDestRect->top;
+
+ m_info.context->setViewports(1, &viewport, &scissor);
+
+ // Use an appropriate texture filter depending on whether
+ // the back buffer size matches the swap image size
+ bool fitSize = pSourceRect->right - pSourceRect->left == pDestRect->right - pDestRect->left
+ && pSourceRect->bottom - pSourceRect->top == pDestRect->bottom - pDestRect->top;
+
+ D3D9PresentInfo presentInfoConsts;
+ presentInfoConsts.scale[0] = float(pSourceRect->right - pSourceRect->left) / float(swapImage->info().extent.width);
+ presentInfoConsts.scale[1] = float(pSourceRect->bottom - pSourceRect->top) / float(swapImage->info().extent.height);
+
+ presentInfoConsts.offset[0] = float(pSourceRect->left) / float(swapImage->info().extent.width);
+ presentInfoConsts.offset[1] = float(pSourceRect->top) / float(swapImage->info().extent.height);
+
+ m_info.context->pushConstants(0, sizeof(D3D9PresentInfo), &presentInfoConsts);
+
+ m_info.context->setRasterizerState(m_parent->m_info.rsState);
+ m_info.context->setMultisampleState(m_parent->m_info.msState);
+ m_info.context->setDepthStencilState(m_parent->m_info.dsState);
+ m_info.context->setLogicOpState(m_parent->m_info.loState);
+ m_info.context->setBlendMode(0, m_parent->m_info.blendMode);
+
+ m_info.context->setInputAssemblyState(m_parent->m_info.iaState);
+ m_info.context->setInputLayout(0, nullptr, 0, nullptr);
+
+ m_info.context->bindResourceSampler(D3D9PresentationInfo::BindingIds::Image, fitSize ? m_parent->m_info.samplerFitting : m_parent->m_info.samplerScaling);
+ m_info.context->bindResourceSampler(D3D9PresentationInfo::BindingIds::Gamma, m_parent->m_info.gammaSampler);
+
+ m_info.context->bindResourceView(D3D9PresentationInfo::BindingIds::Image, swapImageView, nullptr);
+ m_info.context->bindResourceView(D3D9PresentationInfo::BindingIds::Gamma, m_parent->m_info.gammaTextureView, nullptr);
+
+ m_info.context->draw(3, 1, 0, 0);
+
+ if (m_parent->m_info.hud != nullptr)
+ m_parent->m_info.hud->render(m_info.context, info.format, info.imageExtent);
+
+ if (partialPresent) {
+ const VkImageSubresourceLayers subresourceLayers = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, 0, 1 };
+
+ m_info.context->copyImage(
+ m_imageViews.at(imageIndex)->image(), subresourceLayers, VkOffset3D{ 0, 0, 0 },
+ m_copyImage, subresourceLayers, VkOffset3D{ 0, 0, 0 },
+ VkExtent3D{ m_presentExtent.width, m_presentExtent.height, 1 });
+ }
+
+ m_partialPresented = partialPresent;
+
+ if (i + 1 >= SyncInterval)
+ m_info.context->signal(m_parent->m_info.frameLatencySignal, frameId);
+
+ SubmitPresent(sync, i);
+ }
+
+ // Rotate swap chain buffers so that the back
+ // buffer at index 0 becomes the front buffer.
+ for (uint32_t i = 1; i < m_info.backBuffers.size(); i++)
+ m_info.backBuffers[i]->Swap(m_info.backBuffers[i - 1].ptr());
+
+ m_parent->GetParent()->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
+ }
+
+
+ void D3D9Presenter::SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId) {
+ // Present from CS thread so that we don't
+ // have to synchronize with it first.
+ m_presentStatus.result = VK_NOT_READY;
+
+ m_parent->GetParent()->EmitCs([this,
+ cFrameId = FrameId,
+ cSync = Sync,
+ cHud = m_info.hud,
+ cCommandList = m_info.context->endRecording()
+ ] (DxvkContext* ctx) {
+ m_info.device->submitCommandList(cCommandList,
+ cSync.acquire, cSync.present);
+
+ if (cHud != nullptr && !cFrameId)
+ cHud->update();
+
+ m_info.device->presentImage(m_presenter,
+ cSync.present, &m_presentStatus);
+ });
+
+ m_parent->GetParent()->FlushCsChunk();
+ }
+
+
+ void D3D9Presenter::SynchronizePresent() {
+ // Recreate swap chain if the previous present call failed
+ VkResult status = m_info.device->waitForSubmission(&m_presentStatus);
+
+ if (status != VK_SUCCESS)
+ RecreateSwapChain(m_vsync);
+ }
+
+
+ void D3D9Presenter::RecreateSwapChain(BOOL Vsync) {
+ // Ensure that we can safely destroy the swap chain
+ m_info.device->waitForSubmission(&m_presentStatus);
+ m_info.device->waitForIdle();
+
+ m_presentStatus.result = VK_SUCCESS;
+
+ vk::PresenterDesc presenterDesc;
+ presenterDesc.imageExtent = m_presentExtent;
+ presenterDesc.imageCount = m_parent->PickImageCount(m_parent->m_presentParams.BackBufferCount + 1);
+ presenterDesc.numFormats = m_parent->PickFormats(EnumerateFormat(m_parent->m_presentParams.BackBufferFormat), presenterDesc.formats);
+ presenterDesc.numPresentModes = m_parent->PickPresentModes(Vsync, presenterDesc.presentModes);
+ presenterDesc.fullScreenExclusive = m_parent->PickFullscreenMode();
+
+ if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS)
+ throw DxvkError("D3D9SwapChainEx: Failed to recreate swap chain");
+
+ CreateRenderTargetViews();
+ }
+
+
+ void D3D9Presenter::CreatePresenter() {
+ // Ensure that we can safely destroy the presenter + swapchain
+ m_info.device->waitForSubmission(&m_presentStatus);
+ m_info.device->waitForIdle();
+
+ // Toss the current presenter now so we can re-make a new one.
+ // We can't have multiple surfaces on a window!
+ m_presenter = nullptr;
+
+ m_presentExtent = GetPresentExtent();
+
+ DxvkDeviceQueue graphicsQueue = m_info.device->queues().graphics;
+
+ vk::PresenterDevice presenterDevice;
+ presenterDevice.queueFamily = graphicsQueue.queueFamily;
+ presenterDevice.queue = graphicsQueue.queueHandle;
+ presenterDevice.adapter = m_info.device->adapter()->handle();
+
+ vk::PresenterDesc presenterDesc;
+ presenterDesc.imageExtent = m_presentExtent;
+ presenterDesc.imageCount = m_parent->PickImageCount(m_parent->m_presentParams.BackBufferCount + 1);
+ presenterDesc.numFormats = m_parent->PickFormats(EnumerateFormat(m_parent->m_presentParams.BackBufferFormat), presenterDesc.formats);
+ presenterDesc.numPresentModes = m_parent->PickPresentModes(false, presenterDesc.presentModes);
+ presenterDesc.fullScreenExclusive = m_parent->PickFullscreenMode();
+
+ m_presenter = new vk::Presenter(m_window,
+ m_info.device->adapter()->vki(),
+ m_info.device->vkd(),
+ presenterDevice,
+ presenterDesc);
+
+ CreateRenderTargetViews();
+ }
+
+
+ void D3D9Presenter::CreateRenderTargetViews() {
+ vk::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
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ imageInfo.stages = 0;
+ imageInfo.access = 0;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = info.format.format;
+ viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+
+ for (uint32_t i = 0; i < info.imageCount; i++) {
+ VkImage imageHandle = m_presenter->getImage(i).image;
+
+ Rc<DxvkImage> image = new DxvkImage(
+ m_info.device->vkd(), imageInfo, imageHandle);
+
+ m_imageViews[i] = new DxvkImageView(
+ m_info.device->vkd(), image, viewInfo);
+ }
+
+
+ if (m_parent->m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY)
+ CreateCopyImage();
+ }
+
+
+ void D3D9Presenter::CreateCopyImage() {
+ vk::PresenterInfo info = m_presenter->info();
+
+ 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
+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ imageInfo.stages = 0;
+ imageInfo.access = 0;
+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageInfo.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+
+ DxvkImageViewCreateInfo viewInfo;
+ viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = info.format.format;
+ viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
+ viewInfo.minLevel = 0;
+ viewInfo.numLevels = 1;
+ viewInfo.minLayer = 0;
+ viewInfo.numLayers = 1;
+
+ m_copyImage = m_info.device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
+
+ m_copyImageView = m_info.device->createImageView(m_copyImage, viewInfo);
+ }
+
+
+ VkExtent2D D3D9Presenter::GetPresentExtent() {
+ UINT width, height;
+ GetWindowClientSize(m_window, &width, &height);
+
+ return VkExtent2D {
+ std::max<uint32_t>(width, 1u),
+ std::max<uint32_t>(height, 1u) };
+ }
+
+
D3D9SwapChainEx::D3D9SwapChainEx(
D3D9DeviceEx* pDevice,
D3DPRESENT_PARAMETERS* pPresentParams,
const D3DDISPLAYMODEEX* pFullscreenDisplayMode)
: D3D9SwapChainExBase(pDevice)
- , m_device (pDevice->GetDXVKDevice())
- , m_context (m_device->createContext())
- , m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency)
- , m_frameLatencySignal(new sync::Fence(m_frameId))
- , m_dialog (pDevice->GetOptions()->enableDialogMode) {
+ , m_info(pDevice) {
UpdateMonitorInfo();
this->NormalizePresentParameters(pPresentParams);
m_presentParams = *pPresentParams;
- m_window = m_presentParams.hDeviceWindow;
- UpdatePresentRegion(nullptr, nullptr);
- if (!pDevice->GetOptions()->deferSurfaceCreation)
- CreatePresenter();
+ m_mainPresenter = new D3D9Presenter(m_info, this, m_presentParams.hDeviceWindow);
+ m_presenters.push_front(m_mainPresenter);
CreateBackBuffers(m_presentParams.BackBufferCount);
CreateHud();
@@ -58,9 +483,6 @@ namespace dxvk {
D3D9SwapChainEx::~D3D9SwapChainEx() {
RestoreDisplayMode(m_monitor);
-
- m_device->waitForSubmission(&m_presentStatus);
- m_device->waitForIdle();
}
@@ -91,69 +513,64 @@ namespace dxvk {
DWORD dwFlags) {
auto lock = m_parent->LockDevice();
- uint32_t presentInterval = m_presentParams.PresentationInterval;
+ RECT srcRect;
+ if (pSourceRect == nullptr) {
+ srcRect.top = 0;
+ srcRect.left = 0;
+ srcRect.right = m_presentParams.BackBufferWidth;
+ srcRect.bottom = m_presentParams.BackBufferHeight;
+
+ pSourceRect = &srcRect;
+ }
+
+ RECT dstRect;
+ if (pDestRect == nullptr) {
+ UINT width, height;
+ GetWindowClientSize(m_presentParams.hDeviceWindow, &width, &height);
+
+ dstRect.top = 0;
+ dstRect.left = 0;
+ dstRect.right = LONG(width);
+ dstRect.bottom = LONG(height);
+
+ pDestRect = &dstRect;
+ }
+
+ uint32_t syncInterval = m_presentParams.PresentationInterval;
// This is not true directly in d3d9 to to timing differences that don't matter for us.
// For our purposes...
// D3DPRESENT_INTERVAL_DEFAULT (0) == D3DPRESENT_INTERVAL_ONE (1) which means VSYNC.
- presentInterval = std::max(presentInterval, 1u);
+ syncInterval = std::max(syncInterval, 1u);
- if (presentInterval == D3DPRESENT_INTERVAL_IMMEDIATE || (dwFlags & D3DPRESENT_FORCEIMMEDIATE))
- presentInterval = 0;
+ if (syncInterval == D3DPRESENT_INTERVAL_IMMEDIATE || (dwFlags & D3DPRESENT_FORCEIMMEDIATE))
+ syncInterval = 0;
auto options = m_parent->GetOptions();
if (options->presentInterval >= 0)
- presentInterval = options->presentInterval;
-
- bool vsync = presentInterval != 0;
-
- HWND window = m_presentParams.hDeviceWindow;
- if (hDestWindowOverride != nullptr)
- window = hDestWindowOverride;
-
- bool recreate = false;
- recreate |= m_presenter == nullptr;
- recreate |= window != m_window;
- recreate |= m_dialog != m_lastDialog;
-
- m_window = window;
+ syncInterval = options->presentInterval;
- m_dirty |= vsync != m_vsync;
- m_dirty |= recreate;
- m_dirty |= m_presenter != nullptr &&
- !m_presenter->hasSwapChain();
+ HWND presentWindow = hDestWindowOverride != nullptr
+ ? hDestWindowOverride
+ : m_presentParams.hDeviceWindow;
- VkExtent2D presentExtent = GetPresentExtent();
- if (m_presentExtent != presentExtent) {
- m_dirty = true;
- m_presentExtent = presentExtent;
+ if (likely(presentWindow == m_presentParams.hDeviceWindow)) {
+ // Fast path for this to avoid looking stuff up.
+ return m_mainPresenter->Present(syncInterval, pSourceRect, pDestRect);
}
+ else {
+ // Find and present if we have a presenter for this window...
+ for (auto& presenter : m_presenters) {
+ if (presenter->GetWindow() == presentWindow)
+ return presenter->Present(syncInterval, pSourceRect, pDestRect);
+ }
- m_vsync = vsync;
-
- m_lastDialog = m_dialog;
-
- UpdatePresentRegion(pSourceRect, pDestRect);
-
- try {
- if (recreate)
- CreatePresenter();
-
- if (std::exchange(m_dirty, false))
- RecreateSwapChain(vsync);
-
- // We aren't going to device loss simply because
- // 99% of D3D9 games don't handle this properly and
- // just end up crashing (like with alt-tab loss)
- if (!m_presenter->hasSwapChain())
- return D3D_OK;
+ // Didn't find one? We need one for this window.
+ Rc<D3D9Presenter> presenter = new D3D9Presenter(m_info, this, presentWindow);
+ m_presenters.push_back(presenter);
- PresentImage(presentInterval);
- return D3D_OK;
- } catch (const DxvkError& e) {
- Logger::err(e.message());
- return D3DERR_DEVICEREMOVED;
+ return presenter->Present(syncInterval, pSourceRect, pDestRect);
}
}
@@ -177,7 +594,7 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
- D3D9CommonTexture* srcTexInfo = m_backBuffers[m_presentParams.BackBufferCount]->GetCommonTexture();
+ D3D9CommonTexture* srcTexInfo = m_info.backBuffers[m_presentParams.BackBufferCount]->GetCommonTexture();
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM))
return D3DERR_INVALIDCALL;
@@ -207,7 +624,7 @@ namespace dxvk {
resolveInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
resolveInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- Rc<DxvkImage> resolvedSrc = m_device->createImage(
+ Rc<DxvkImage> resolvedSrc = m_info.device->createImage(
resolveInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
m_parent->EmitCs([
@@ -262,7 +679,7 @@ namespace dxvk {
blitCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
blitCreateInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- Rc<DxvkImage> blittedSrc = m_device->createImage(
+ Rc<DxvkImage> blittedSrc = m_info.device->createImage(
blitCreateInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
const DxvkFormatInfo* dstFormatInfo = imageFormatInfo(blittedSrc->info().format);
@@ -348,7 +765,7 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
}
- *ppBackBuffer = m_backBuffers[iBackBuffer].ref();
+ *ppBackBuffer = m_info.backBuffers[iBackBuffer].ref();
return D3D_OK;
}
@@ -465,13 +882,29 @@ namespace dxvk {
D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
auto lock = m_parent->LockDevice();
- this->SynchronizePresent();
+ for (auto& presenter : m_presenters)
+ presenter->SynchronizePresent();
+
this->NormalizePresentParameters(pPresentParams);
- m_dirty |= m_presentParams.BackBufferFormat != pPresentParams->BackBufferFormat
- || m_presentParams.BackBufferWidth != pPresentParams->BackBufferWidth
- || m_presentParams.BackBufferHeight != pPresentParams->BackBufferHeight
- || m_presentParams.BackBufferCount != pPresentParams->BackBufferCount;
+ if (m_presentParams.BackBufferFormat != pPresentParams->BackBufferFormat ||
+ m_presentParams.BackBufferCount != pPresentParams->BackBufferCount) {
+ for (auto& presenter : m_presenters)
+ presenter->MarkDirty();
+ }
+
+ HWND window = m_presentParams.hDeviceWindow;
+
+ m_mainPresenter = nullptr;
+
+ // Recreate the primary presenter if we need a new one.
+ auto devicePresenter = m_presenters.begin();
+ if ((*devicePresenter)->GetWindow() != window) {
+ m_presenters.erase(devicePresenter);
+
+ m_mainPresenter = new D3D9Presenter(m_info, this, m_presentParams.hDeviceWindow);
+ m_presenters.push_front(m_mainPresenter);
+ }
bool changeFullscreen = m_presentParams.Windowed != pPresentParams->Windowed;
@@ -483,14 +916,14 @@ namespace dxvk {
RECT newRect = { 0, 0, 0, 0 };
RECT oldRect = { 0, 0, 0, 0 };
- ::GetWindowRect(m_window, &oldRect);
+ ::GetWindowRect(window, &oldRect);
::SetRect(&newRect, 0, 0, pPresentParams->BackBufferWidth, pPresentParams->BackBufferHeight);
::AdjustWindowRectEx(&newRect,
- ::GetWindowLongW(m_window, GWL_STYLE), FALSE,
- ::GetWindowLongW(m_window, GWL_EXSTYLE));
+ ::GetWindowLongW(window, GWL_STYLE), FALSE,
+ ::GetWindowLongW(window, GWL_EXSTYLE));
::SetRect(&newRect, 0, 0, newRect.right - newRect.left, newRect.bottom - newRect.top);
::OffsetRect(&newRect, oldRect.left, oldRect.top);
- ::MoveWindow(m_window, newRect.left, newRect.top,
+ ::MoveWindow(window, newRect.left, newRect.top,
newRect.right - newRect.left, newRect.bottom - newRect.top, TRUE);
}
else {
@@ -503,7 +936,7 @@ namespace dxvk {
RECT rect;
GetMonitorRect(GetDefaultMonitor(), &rect);
- ::SetWindowPos(m_window, HWND_TOPMOST,
+ ::SetWindowPos(window, HWND_TOPMOST,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
}
@@ -513,7 +946,6 @@ namespace dxvk {
if (changeFullscreen)
SetGammaRamp(0, &m_ramp);
- UpdatePresentRegion(nullptr, nullptr);
CreateBackBuffers(m_presentParams.BackBufferCount);
}
@@ -566,11 +998,13 @@ namespace dxvk {
if (hWindow == nullptr)
hWindow = m_parent->GetWindow();
- if (m_presentParams.hDeviceWindow == hWindow) {
- m_presenter = nullptr;
-
- m_device->waitForSubmission(&m_presentStatus);
- m_device->waitForIdle();
+ for (auto iter = m_presenters.begin(); iter != m_presenters.end();) {
+ if ((*iter)->GetWindow() == hWindow) {
+ Logger::warn(str::format("Multiple swapchains made for window: ", std::hex, hWindow, " My device window: ", m_presentParams.hDeviceWindow));
+ iter = m_presenters.erase(iter);
+ }
+ else
+ iter++;
}
}
@@ -581,7 +1015,7 @@ namespace dxvk {
// However it doesn't appear to error at all in any of my tests of these
// cases described in the documentation.
- m_dialog = bEnableDialogs;
+ m_info.dialog = bEnableDialogs;
return D3D_OK;
}
@@ -591,7 +1025,7 @@ namespace dxvk {
if (iBackBuffer >= m_presentParams.BackBufferCount)
return nullptr;
- return m_backBuffers[iBackBuffer].ptr();
+ return m_info.backBuffers[iBackBuffer].ptr();
}
@@ -626,352 +1060,14 @@ namespace dxvk {
}
- void D3D9SwapChainEx::PresentImage(UINT SyncInterval) {
- m_parent->Flush();
-
- // Retrieve the image and image view to present
- auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
- auto swapImageView = m_resolveImageView;
-
- if (swapImageView == nullptr)
- swapImageView = m_backBuffers[0]->GetImageView(false);
-
- // Wait for the sync event so that we respect the maximum frame latency
- uint64_t frameId = ++m_frameId;
- m_frameLatencySignal->wait(frameId - GetActualFrameLatency());
-
- for (uint32_t i = 0; i < SyncInterval || i < 1; i++) {
- SynchronizePresent();
-
- m_context->beginRecording(
- m_device->createCommandList());
-
- // Resolve back buffer if it is multisampled. We
- // only have to do it only for the first frame.
- if (m_resolveImage != nullptr && i == 0) {
- VkImageSubresourceLayers resolveSubresource;
- resolveSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- resolveSubresource.mipLevel = 0;
- resolveSubresource.baseArrayLayer = 0;
- resolveSubresource.layerCount = 1;
-
- VkImageResolve resolveRegion;
- resolveRegion.srcSubresource = resolveSubresource;
- resolveRegion.srcOffset = VkOffset3D { 0, 0, 0 };
- resolveRegion.dstSubresource = resolveSubresource;
- resolveRegion.dstOffset = VkOffset3D { 0, 0, 0 };
- resolveRegion.extent = swapImage->info().extent;
-
- m_context->resolveImage(
- m_resolveImage, swapImage,
- resolveRegion, VK_FORMAT_UNDEFINED);
- }
-
- // Presentation semaphores and WSI swap chain image
- vk::PresenterInfo info = m_presenter->info();
- vk::PresenterSync sync = m_presenter->getSyncSemaphores();
-
- uint32_t imageIndex = 0;
-
- VkResult status = m_presenter->acquireNextImage(
- sync.acquire, VK_NULL_HANDLE, imageIndex);
-
- while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
- RecreateSwapChain(m_vsync);
-
- info = m_presenter->info();
- sync = m_presenter->getSyncSemaphores();
-
- status = m_presenter->acquireNextImage(
- sync.acquire, VK_NULL_HANDLE, imageIndex);
- }
-
- const bool partialPresent =
- m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY &&
- (m_dstRect.left != 0 ||
- m_dstRect.top != 0 ||
- m_dstRect.right != m_presentExtent.width ||
- m_dstRect.bottom != m_presentExtent.height);
-
- if (partialPresent && !m_partialPresented) {
- const VkImageSubresourceLayers subresourceLayers = {
- VK_IMAGE_ASPECT_COLOR_BIT,
- 0, 0, 1 };
-
- VkImageBlit region;
- region.dstOffsets[0] = VkOffset3D{ 0, 0, 0 };
- region.dstOffsets[1] = VkOffset3D{ int32_t(m_presentExtent.width), int32_t(m_presentExtent.height), 1 };
- region.dstSubresource = subresourceLayers;
- region.srcOffsets[0] = region.dstOffsets[0];
- region.srcOffsets[1] = region.dstOffsets[1];
- region.srcSubresource = region.dstSubresource;
-
- const auto& lastImage = m_backBuffers[m_presentParams.BackBufferCount]->GetCommonTexture()->GetImage();
-
- m_context->blitImage(
- m_copyImage, VkComponentMapping{ },
- lastImage, VkComponentMapping{ },
- region, VK_FILTER_NEAREST);
- }
-
- // Use an appropriate texture filter depending on whether
- // the back buffer size matches the swap image size
- m_context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vertShader);
- m_context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_fragShader);
-
- DxvkRenderTargets renderTargets;
- renderTargets.color[0].view = partialPresent ? m_copyImageView : m_imageViews.at(imageIndex);
- renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- m_context->bindRenderTargets(renderTargets);
-
- VkViewport viewport;
- viewport.x = float(m_dstRect.left);
- viewport.y = float(m_dstRect.top);
- viewport.width = float(m_dstRect.right - m_dstRect.left);
- viewport.height = float(m_dstRect.bottom - m_dstRect.top);
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
-
- VkRect2D scissor;
- scissor.offset.x = m_dstRect.left;
- scissor.offset.y = m_dstRect.top;
- scissor.extent.width = m_dstRect.right - m_dstRect.left;
- scissor.extent.height = m_dstRect.bottom - m_dstRect.top;
-
- m_context->setViewports(1, &viewport, &scissor);
-
- // Use an appropriate texture filter depending on whether
- // the back buffer size matches the swap image size
- bool fitSize = m_srcRect.right - m_srcRect.left == m_dstRect.right - m_dstRect.left
- && m_srcRect.bottom - m_srcRect.top == m_dstRect.bottom - m_dstRect.top;
-
- D3D9PresentInfo presentInfoConsts;
- presentInfoConsts.scale[0] = float(m_srcRect.right - m_srcRect.left) / float(swapImage->info().extent.width);
- presentInfoConsts.scale[1] = float(m_srcRect.bottom - m_srcRect.top) / float(swapImage->info().extent.height);
-
- presentInfoConsts.offset[0] = float(m_srcRect.left) / float(swapImage->info().extent.width);
- presentInfoConsts.offset[1] = float(m_srcRect.top) / float(swapImage->info().extent.height);
-
- m_context->pushConstants(0, sizeof(D3D9PresentInfo), &presentInfoConsts);
-
- m_context->setRasterizerState(m_rsState);
- m_context->setMultisampleState(m_msState);
- m_context->setDepthStencilState(m_dsState);
- m_context->setLogicOpState(m_loState);
- m_context->setBlendMode(0, m_blendMode);
-
- m_context->setInputAssemblyState(m_iaState);
- m_context->setInputLayout(0, nullptr, 0, nullptr);
-
- m_context->bindResourceSampler(BindingIds::Image, fitSize ? m_samplerFitting : m_samplerScaling);
- m_context->bindResourceSampler(BindingIds::Gamma, m_gammaSampler);
-
- m_context->bindResourceView(BindingIds::Image, swapImageView, nullptr);
- m_context->bindResourceView(BindingIds::Gamma, m_gammaTextureView, nullptr);
-
- m_context->draw(3, 1, 0, 0);
-
- if (m_hud != nullptr)
- m_hud->render(m_context, info.format, info.imageExtent);
-
- if (partialPresent) {
- const VkImageSubresourceLayers subresourceLayers = {
- VK_IMAGE_ASPECT_COLOR_BIT,
- 0, 0, 1 };
-
- m_context->copyImage(
- m_imageViews.at(imageIndex)->image(), subresourceLayers, VkOffset3D{ 0, 0, 0 },
- m_copyImage, subresourceLayers, VkOffset3D{ 0, 0, 0 },
- VkExtent3D{ m_presentExtent.width, m_presentExtent.height, 1 });
- }
-
- m_partialPresented = partialPresent;
-
- if (i + 1 >= SyncInterval)
- m_context->signal(m_frameLatencySignal, frameId);
-
- SubmitPresent(sync, i);
- }
-
- // Rotate swap chain buffers so that the back
- // buffer at index 0 becomes the front buffer.
- for (uint32_t i = 1; i < m_backBuffers.size(); i++)
- m_backBuffers[i]->Swap(m_backBuffers[i - 1].ptr());
-
- m_parent->m_flags.set(D3D9DeviceFlag::DirtyFramebuffer);
- }
-
-
- void D3D9SwapChainEx::SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId) {
- // Present from CS thread so that we don't
- // have to synchronize with it first.
- m_presentStatus.result = VK_NOT_READY;
-
- m_parent->EmitCs([this,
- cFrameId = FrameId,
- cSync = Sync,
- cHud = m_hud,
- cCommandList = m_context->endRecording()
- ] (DxvkContext* ctx) {
- m_device->submitCommandList(cCommandList,
- cSync.acquire, cSync.present);
-
- if (cHud != nullptr && !cFrameId)
- cHud->update();
-
- m_device->presentImage(m_presenter,
- cSync.present, &m_presentStatus);
- });
-
- m_parent->FlushCsChunk();
- }
-
-
- void D3D9SwapChainEx::SynchronizePresent() {
- // Recreate swap chain if the previous present call failed
- VkResult status = m_device->waitForSubmission(&m_presentStatus);
-
- if (status != VK_SUCCESS)
- RecreateSwapChain(m_vsync);
- }
-
-
- void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
- // Ensure that we can safely destroy the swap chain
- m_device->waitForSubmission(&m_presentStatus);
- m_device->waitForIdle();
-
- m_presentStatus.result = VK_SUCCESS;
-
- vk::PresenterDesc presenterDesc;
- presenterDesc.imageExtent = GetPresentExtent();
- presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
- presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
- presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
- presenterDesc.fullScreenExclusive = PickFullscreenMode();
-
- if (m_presenter->recreateSwapChain(presenterDesc) != VK_SUCCESS)
- throw DxvkError("D3D9SwapChainEx: Failed to recreate swap chain");
-
- CreateRenderTargetViews();
- }
-
-
- void D3D9SwapChainEx::CreatePresenter() {
- DxvkDeviceQueue graphicsQueue = m_device->queues().graphics;
-
- vk::PresenterDevice presenterDevice;
- presenterDevice.queueFamily = graphicsQueue.queueFamily;
- presenterDevice.queue = graphicsQueue.queueHandle;
- presenterDevice.adapter = m_device->adapter()->handle();
-
- vk::PresenterDesc presenterDesc;
- presenterDesc.imageExtent = GetPresentExtent();
- presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
- presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
- presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
- presenterDesc.fullScreenExclusive = PickFullscreenMode();
-
- m_presenter = new vk::Presenter(m_window,
- m_device->adapter()->vki(),
- m_device->vkd(),
- presenterDevice,
- presenterDesc);
-
- CreateRenderTargetViews();
- }
-
-
- void D3D9SwapChainEx::CreateRenderTargetViews() {
- vk::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
- | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- imageInfo.stages = 0;
- imageInfo.access = 0;
- imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
- imageInfo.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- DxvkImageViewCreateInfo viewInfo;
- viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = info.format.format;
- viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.minLevel = 0;
- viewInfo.numLevels = 1;
- viewInfo.minLayer = 0;
- viewInfo.numLayers = 1;
-
- for (uint32_t i = 0; i < info.imageCount; i++) {
- VkImage imageHandle = m_presenter->getImage(i).image;
-
- Rc<DxvkImage> image = new DxvkImage(
- m_device->vkd(), imageInfo, imageHandle);
-
- m_imageViews[i] = new DxvkImageView(
- m_device->vkd(), image, viewInfo);
- }
-
-
- if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY)
- CreateCopyImage();
- }
-
-
- void D3D9SwapChainEx::CreateCopyImage() {
- vk::PresenterInfo info = m_presenter->info();
-
- 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
- | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
- | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- imageInfo.stages = 0;
- imageInfo.access = 0;
- imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
- imageInfo.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-
- DxvkImageViewCreateInfo viewInfo;
- viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = info.format.format;
- viewInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
- viewInfo.minLevel = 0;
- viewInfo.numLevels = 1;
- viewInfo.minLayer = 0;
- viewInfo.numLayers = 1;
-
- m_copyImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
-
- m_copyImageView = m_device->createImageView(m_copyImage, viewInfo);
- }
-
-
void D3D9SwapChainEx::CreateBackBuffers(uint32_t NumBackBuffers) {
// Explicitly destroy current swap image before
// creating a new one to free up resources
- m_resolveImage = nullptr;
- m_resolveImageView = nullptr;
+ m_info.resolveImage = nullptr;
+ m_info.resolveImageView = nullptr;
- m_backBuffers.clear();
- m_backBuffers.resize(NumBackBuffers + 1);
+ m_info.backBuffers.clear();
+ m_info.backBuffers.resize(NumBackBuffers + 1);
// Create new back buffer
D3D9_COMMON_TEXTURE_DESC desc;
@@ -987,10 +1083,10 @@ namespace dxvk {
desc.Usage = D3DUSAGE_RENDERTARGET;
desc.Discard = FALSE;
- for (uint32_t i = 0; i < m_backBuffers.size(); i++)
- m_backBuffers[i] = new D3D9Surface(m_parent, &desc);
+ for (uint32_t i = 0; i < m_info.backBuffers.size(); i++)
+ m_info.backBuffers[i] = new D3D9Surface(m_parent, &desc);
- auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
+ auto swapImage = m_info.backBuffers[0]->GetCommonTexture()->GetImage();
// If the image is multisampled, we need to create
// another image which we'll use as a resolve target
@@ -1016,12 +1112,12 @@ namespace dxvk {
resolveInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
resolveInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- m_resolveImage = m_device->createImage(
+ m_info.resolveImage = m_info.device->createImage(
resolveInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
DxvkImageViewCreateInfo viewInfo;
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = m_resolveImage->info().format;
+ viewInfo.format = m_info.resolveImage->info().format;
viewInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.minLevel = 0;
@@ -1029,7 +1125,7 @@ namespace dxvk {
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
- m_resolveImageView = m_device->createImageView(m_resolveImage, viewInfo);
+ m_info.resolveImageView = m_info.device->createImageView(m_info.resolveImage, viewInfo);
}
@@ -1048,17 +1144,17 @@ namespace dxvk {
clearColor.float32[2] = 0.0f;
clearColor.float32[3] = 0.0f;
- m_context->beginRecording(
- m_device->createCommandList());
+ m_info.context->beginRecording(
+ m_info.device->createCommandList());
- for (uint32_t i = 0; i < m_backBuffers.size(); i++) {
- m_context->clearColorImage(
- m_backBuffers[i]->GetCommonTexture()->GetImage(),
+ for (uint32_t i = 0; i < m_info.backBuffers.size(); i++) {
+ m_info.context->clearColorImage(
+ m_info.backBuffers[i]->GetCommonTexture()->GetImage(),
clearColor, subresources);
}
- m_device->submitCommandList(
- m_context->endRecording(),
+ m_info.device->submitCommandList(
+ m_info.context->endRecording(),
VK_NULL_HANDLE,
VK_NULL_HANDLE);
}
@@ -1067,8 +1163,8 @@ namespace dxvk {
void D3D9SwapChainEx::CreateGammaTexture(
UINT NumControlPoints,
const D3D9_VK_GAMMA_CP* pControlPoints) {
- if (m_gammaTexture == nullptr
- || m_gammaTexture->info().extent.width != NumControlPoints) {
+ if (m_info.gammaTexture == nullptr
+ || m_info.gammaTexture->info().extent.width != NumControlPoints) {
DxvkImageCreateInfo imgInfo;
imgInfo.type = VK_IMAGE_TYPE_1D;
imgInfo.format = VK_FORMAT_R16G16B16A16_UNORM;
@@ -1086,7 +1182,7 @@ namespace dxvk {
imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imgInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- m_gammaTexture = m_device->createImage(
+ m_info.gammaTexture = m_info.device->createImage(
imgInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
DxvkImageViewCreateInfo viewInfo;
@@ -1099,55 +1195,55 @@ namespace dxvk {
viewInfo.minLayer = 0;
viewInfo.numLayers = 1;
- m_gammaTextureView = m_device->createImageView(m_gammaTexture, viewInfo);
+ m_info.gammaTextureView = m_info.device->createImageView(m_info.gammaTexture, viewInfo);
}
- m_context->beginRecording(
- m_device->createCommandList());
+ m_info.context->beginRecording(
+ m_info.device->createCommandList());
- m_context->updateImage(m_gammaTexture,
+ m_info.context->updateImage(m_info.gammaTexture,
VkImageSubresourceLayers { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
VkOffset3D { 0, 0, 0 },
VkExtent3D { NumControlPoints, 1, 1 },
pControlPoints, 0, 0);
- m_device->submitCommandList(
- m_context->endRecording(),
+ m_info.device->submitCommandList(
+ m_info.context->endRecording(),
VK_NULL_HANDLE,
VK_NULL_HANDLE);
}
void D3D9SwapChainEx::DestroyGammaTexture() {
- m_gammaTexture = nullptr;
- m_gammaTextureView = nullptr;
+ m_info.gammaTexture = nullptr;
+ m_info.gammaTextureView = nullptr;
}
void D3D9SwapChainEx::CreateHud() {
- m_hud = hud::Hud::createHud(m_device);
+ m_info.hud = hud::Hud::createHud(m_info.device);
- if (m_hud != nullptr) {
- m_hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
- m_hud->addItem<hud::HudSamplerCount>("samplers", -1, m_parent);
+ if (m_info.hud != nullptr) {
+ m_info.hud->addItem<hud::HudClientApiItem>("api", 1, GetApiName());
+ m_info.hud->addItem<hud::HudSamplerCount>("samplers", -1, m_parent);
}
}
void D3D9SwapChainEx::InitRenderState() {
- m_iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
- m_iaState.primitiveRestart = VK_FALSE;
- m_iaState.patchVertexCount = 0;
+ m_info.iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+ m_info.iaState.primitiveRestart = VK_FALSE;
+ m_info.iaState.patchVertexCount = 0;
- m_rsState.polygonMode = VK_POLYGON_MODE_FILL;
- m_rsState.cullMode = VK_CULL_MODE_BACK_BIT;
- m_rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- m_rsState.depthClipEnable = VK_FALSE;
- m_rsState.depthBiasEnable = VK_FALSE;
- m_rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT;
+ m_info.rsState.polygonMode = VK_POLYGON_MODE_FILL;
+ m_info.rsState.cullMode = VK_CULL_MODE_BACK_BIT;
+ m_info.rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+ m_info.rsState.depthClipEnable = VK_FALSE;
+ m_info.rsState.depthBiasEnable = VK_FALSE;
+ m_info.rsState.sampleCount = VK_SAMPLE_COUNT_1_BIT;
- m_msState.sampleMask = 0xffffffff;
- m_msState.enableAlphaToCoverage = VK_FALSE;
+ m_info.msState.sampleMask = 0xffffffff;
+ m_info.msState.enableAlphaToCoverage = VK_FALSE;
VkStencilOpState stencilOp;
stencilOp.failOp = VK_STENCIL_OP_KEEP;
@@ -1158,24 +1254,24 @@ namespace dxvk {
stencilOp.writeMask = 0xFFFFFFFF;
stencilOp.reference = 0;
- m_dsState.enableDepthTest = VK_FALSE;
- m_dsState.enableDepthWrite = VK_FALSE;
- m_dsState.enableStencilTest = VK_FALSE;
- m_dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
- m_dsState.stencilOpFront = stencilOp;
- m_dsState.stencilOpBack = stencilOp;
+ m_info.dsState.enableDepthTest = VK_FALSE;
+ m_info.dsState.enableDepthWrite = VK_FALSE;
+ m_info.dsState.enableStencilTest = VK_FALSE;
+ m_info.dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS;
+ m_info.dsState.stencilOpFront = stencilOp;
+ m_info.dsState.stencilOpBack = stencilOp;
- m_loState.enableLogicOp = VK_FALSE;
- m_loState.logicOp = VK_LOGIC_OP_NO_OP;
-
- m_blendMode.enableBlending = VK_FALSE;
- m_blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
- m_blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- m_blendMode.colorBlendOp = VK_BLEND_OP_ADD;
- m_blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
- m_blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- m_blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
- m_blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT
+ m_info.loState.enableLogicOp = VK_FALSE;
+ m_info.loState.logicOp = VK_LOGIC_OP_NO_OP;
+
+ m_info.blendMode.enableBlending = VK_FALSE;
+ m_info.blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
+ m_info.blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ m_info.blendMode.colorBlendOp = VK_BLEND_OP_ADD;
+ m_info.blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
+ m_info.blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ m_info.blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
+ m_info.blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT
| VK_COLOR_COMPONENT_G_BIT
| VK_COLOR_COMPONENT_B_BIT
| VK_COLOR_COMPONENT_A_BIT;
@@ -1199,16 +1295,16 @@ namespace dxvk {
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.borderColor = VkClearColorValue();
samplerInfo.usePixelCoord = VK_FALSE;
- m_samplerFitting = m_device->createSampler(samplerInfo);
+ m_info.samplerFitting = m_info.device->createSampler(samplerInfo);
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
- m_samplerScaling = m_device->createSampler(samplerInfo);
+ m_info.samplerScaling = m_info.device->createSampler(samplerInfo);
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
- m_gammaSampler = m_device->createSampler(samplerInfo);
+ m_info.gammaSampler = m_info.device->createSampler(samplerInfo);
}
@@ -1217,18 +1313,18 @@ namespace dxvk {
const SpirvCodeBuffer fsCode(d3d9_presenter_frag);
const std::array<DxvkResourceSlot, 2> fsResourceSlots = {{
- { BindingIds::Image, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_2D },
- { BindingIds::Gamma, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_1D },
+ { D3D9PresentationInfo::BindingIds::Image, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_2D },
+ { D3D9PresentationInfo::BindingIds::Gamma, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_1D },
}};
- m_vertShader = m_device->createShader(
+ m_info.vertShader = m_info.device->createShader(
VK_SHADER_STAGE_VERTEX_BIT,
0, nullptr,
{ 0u, 1u,
0u, sizeof(D3D9PresentInfo) },
vsCode);
- m_fragShader = m_device->createShader(
+ m_info.fragShader = m_info.device->createShader(
VK_SHADER_STAGE_FRAGMENT_BIT,
fsResourceSlots.size(),
fsResourceSlots.data(),
@@ -1251,8 +1347,8 @@ namespace dxvk {
uint32_t D3D9SwapChainEx::GetActualFrameLatency() {
uint32_t maxFrameLatency = m_parent->GetFrameLatency();
- if (m_frameLatencyCap)
- maxFrameLatency = std::min(maxFrameLatency, m_frameLatencyCap);
+ if (m_info.frameLatencyCap)
+ maxFrameLatency = std::min(maxFrameLatency, m_info.frameLatencyCap);
maxFrameLatency = std::min(maxFrameLatency, m_presentParams.BackBufferCount + 1);
return maxFrameLatency;
@@ -1325,8 +1421,10 @@ namespace dxvk {
HRESULT D3D9SwapChainEx::EnterFullscreenMode(
D3DPRESENT_PARAMETERS* pPresentParams,
const D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
+ HWND window = m_presentParams.hDeviceWindow;
+
// Find a display mode that matches what we need
- ::GetWindowRect(m_window, &m_windowState.rect);
+ ::GetWindowRect(window, &m_windowState.rect);
if (FAILED(ChangeDisplayMode(pPresentParams, pFullscreenDisplayMode))) {
Logger::err("D3D9: EnterFullscreenMode: Failed to change display mode");
@@ -1334,8 +1432,8 @@ namespace dxvk {
}
// Change the window flags to remove the decoration etc.
- LONG style = ::GetWindowLongW(m_window, GWL_STYLE);
- LONG exstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE);
+ LONG style = ::GetWindowLongW(window, GWL_STYLE);
+ LONG exstyle = ::GetWindowLongW(window, GWL_EXSTYLE);
m_windowState.style = style;
m_windowState.exstyle = exstyle;
@@ -1343,14 +1441,14 @@ namespace dxvk {
style &= ~WS_OVERLAPPEDWINDOW;
exstyle &= ~WS_EX_OVERLAPPEDWINDOW;
- ::SetWindowLongW(m_window, GWL_STYLE, style);
- ::SetWindowLongW(m_window, GWL_EXSTYLE, exstyle);
+ ::SetWindowLongW(window, GWL_STYLE, style);
+ ::SetWindowLongW(window, GWL_EXSTYLE, exstyle);
// Move the window so that it covers the entire output
RECT rect;
GetMonitorRect(GetDefaultMonitor(), &rect);
- ::SetWindowPos(m_window, HWND_TOPMOST,
+ ::SetWindowPos(window, HWND_TOPMOST,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
@@ -1361,7 +1459,9 @@ namespace dxvk {
HRESULT D3D9SwapChainEx::LeaveFullscreenMode() {
- if (!IsWindow(m_window))
+ HWND window = m_presentParams.hDeviceWindow;
+
+ if (!IsWindow(window))
return D3DERR_INVALIDCALL;
if (FAILED(RestoreDisplayMode(m_monitor)))
@@ -1371,19 +1471,19 @@ namespace dxvk {
// Only restore the window style if the application hasn't
// changed them. This is in line with what native D3D9 does.
- LONG curStyle = ::GetWindowLongW(m_window, GWL_STYLE) & ~WS_VISIBLE;
- LONG curExstyle = ::GetWindowLongW(m_window, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
+ LONG curStyle = ::GetWindowLongW(window, GWL_STYLE) & ~WS_VISIBLE;
+ LONG curExstyle = ::GetWindowLongW(window, GWL_EXSTYLE) & ~WS_EX_TOPMOST;
if (curStyle == (m_windowState.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW))
&& curExstyle == (m_windowState.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) {
- ::SetWindowLongW(m_window, GWL_STYLE, m_windowState.style);
- ::SetWindowLongW(m_window, GWL_EXSTYLE, m_windowState.exstyle);
+ ::SetWindowLongW(window, GWL_STYLE, m_windowState.style);
+ ::SetWindowLongW(window, GWL_EXSTYLE, m_windowState.exstyle);
}
// Restore window position and apply the style
const RECT rect = m_windowState.rect;
- ::SetWindowPos(m_window, 0,
+ ::SetWindowPos(window, 0,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
@@ -1434,39 +1534,6 @@ namespace dxvk {
return SetMonitorDisplayMode(GetDefaultMonitor(), &mode);
}
- void D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) {
- if (pSourceRect == nullptr) {
- m_srcRect.top = 0;
- m_srcRect.left = 0;
- m_srcRect.right = m_presentParams.BackBufferWidth;
- m_srcRect.bottom = m_presentParams.BackBufferHeight;
- }
- else
- m_srcRect = *pSourceRect;
-
- RECT dstRect;
- if (pDestRect == nullptr) {
- // TODO: Should we hook WM_SIZE message for this?
- UINT width, height;
- GetWindowClientSize(m_window, &width, &height);
-
- m_dstRect.top = 0;
- m_dstRect.left = 0;
- m_dstRect.right = LONG(width);
- m_dstRect.bottom = LONG(height);
- }
- else
- m_dstRect = *pDestRect;
- }
-
- VkExtent2D D3D9SwapChainEx::GetPresentExtent() {
- UINT width, height;
- GetWindowClientSize(m_window, &width, &height);
-
- return VkExtent2D {
- std::max<uint32_t>(width, 1u),
- std::max<uint32_t>(height, 1u) };
- }
void D3D9SwapChainEx::UpdateMonitorInfo() {
m_monInfo.cbSize = sizeof(m_monInfo);
@@ -1477,7 +1544,7 @@ namespace dxvk {
VkFullScreenExclusiveEXT D3D9SwapChainEx::PickFullscreenMode() {
- return m_dialog
+ return m_info.dialog
? VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT
: VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT;
}
diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h
index 81fe2212..8b330126 100644
--- a/src/d3d9/d3d9_swapchain.h
+++ b/src/d3d9/d3d9_swapchain.h
@@ -9,10 +9,12 @@
#include "../util/sync/sync_signal.h"
#include <vector>
+#include <list>
namespace dxvk {
class D3D9Surface;
+ class D3D9SwapChainEx;
/**
* \brief Gamma control point
@@ -25,6 +27,116 @@ namespace dxvk {
uint16_t R, G, B, A;
};
+ class D3D9PresentationInfo {
+
+ public:
+
+ enum BindingIds : uint32_t {
+ Image = 0,
+ Gamma = 1,
+ };
+
+ D3D9PresentationInfo(D3D9DeviceEx* pDevice);
+
+ Rc<DxvkDevice> device;
+ Rc<DxvkContext> context;
+ Rc<hud::Hud> hud;
+
+ std::vector<Com<D3D9Surface, false>> backBuffers;
+
+ Rc<DxvkShader> vertShader;
+ Rc<DxvkShader> fragShader;
+
+ Rc<DxvkSampler> samplerFitting;
+ Rc<DxvkSampler> samplerScaling;
+
+ Rc<DxvkSampler> gammaSampler;
+ Rc<DxvkImage> gammaTexture;
+ Rc<DxvkImageView> gammaTextureView;
+
+ Rc<DxvkImage> resolveImage;
+ Rc<DxvkImageView> resolveImageView;
+
+ DxvkInputAssemblyState iaState = {};
+ DxvkRasterizerState rsState = {};
+ DxvkMultisampleState msState = {};
+ DxvkDepthStencilState dsState = {};
+ DxvkLogicOpState loState = {};
+ DxvkBlendMode blendMode = {};
+
+ uint64_t frameId = D3D9DeviceEx::MaxFrameLatency;
+ uint32_t frameLatencyCap = 0;
+ Rc<sync::Fence> frameLatencySignal;
+
+ bool dialog;
+ };
+
+ class D3D9Presenter : public RcObject {
+
+ public:
+
+ D3D9Presenter(
+ const D3D9PresentationInfo& Info,
+ D3D9SwapChainEx* pParent,
+ HWND hWindow);
+
+ ~D3D9Presenter();
+
+ HRESULT Present(
+ UINT SyncInterval,
+ const RECT* pSourceRect,
+ const RECT* pDestRect);
+
+ void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);
+
+ void SynchronizePresent();
+
+ void RecreateSwapChain(BOOL Vsync);
+
+ void CreatePresenter();
+
+ void CreateRenderTargetViews();
+
+ void CreateCopyImage();
+
+ VkExtent2D GetPresentExtent();
+
+ HWND GetWindow() const { return m_window; }
+
+ void MarkDirty() { m_dirty = true; }
+
+ private:
+
+ void PresentImage(
+ UINT SyncInterval,
+ const RECT* pSourceRect,
+ const RECT* pDestRect);
+
+ D3D9SwapChainEx* m_parent;
+
+ HWND m_window;
+
+ Rc<vk::Presenter> m_presenter;
+
+ VkExtent2D m_presentExtent = {};
+
+ DxvkSubmitStatus m_presentStatus;
+
+ bool m_dirty = true;
+ bool m_vsync = true;
+
+ bool m_partialPresented = false;
+ bool m_lastDialog = false;
+
+ Rc<DxvkImage> m_copyImage;
+ Rc<DxvkImageView> m_copyImageView;
+
+ std::vector<Rc<DxvkImageView>> m_imageViews;
+
+ const D3D9PresentationInfo& m_info;
+
+ };
+
using D3D9SwapChainExBase = D3D9DeviceChild<IDirect3DSwapChain9Ex>;
class D3D9SwapChainEx final : public D3D9SwapChainExBase {
static constexpr uint32_t NumControlPoints = 256;
@@ -85,11 +197,7 @@ namespace dxvk {
private:
- enum BindingIds : uint32_t {
- Image = 0,
- Gamma = 1,
- };
-
+ friend class D3D9Presenter;
struct WindowState {
LONG style = 0;
@@ -97,84 +205,20 @@ namespace dxvk {
RECT rect = { 0, 0, 0, 0 };
};
+ D3D9PresentationInfo m_info;
+
D3DPRESENT_PARAMETERS m_presentParams;
D3DGAMMARAMP m_ramp;
- Rc<DxvkDevice> m_device;
- Rc<DxvkContext> m_context;
-
- Rc<vk::Presenter> m_presenter;
-
- Rc<DxvkShader> m_vertShader;
- Rc<DxvkShader> m_fragShader;
-
- Rc<DxvkSampler> m_samplerFitting;
- Rc<DxvkSampler> m_samplerScaling;
-
- Rc<DxvkSampler> m_gammaSampler;
- Rc<DxvkImage> m_gammaTexture;
- Rc<DxvkImageView> m_gammaTextureView;
-
- Rc<DxvkImage> m_resolveImage;
- Rc<DxvkImageView> m_resolveImageView;
-
- Rc<DxvkImage> m_copyImage;
- Rc<DxvkImageView> m_copyImageView;
-
- Rc<hud::Hud> m_hud;
-
- DxvkInputAssemblyState m_iaState;
- DxvkRasterizerState m_rsState;
- DxvkMultisampleState m_msState;
- DxvkDepthStencilState m_dsState;
- DxvkLogicOpState m_loState;
- DxvkBlendMode m_blendMode;
-
- std::vector<Com<D3D9Surface, false>> m_backBuffers;
-
- RECT m_srcRect;
- RECT m_dstRect;
- VkExtent2D m_presentExtent;
+ Rc<D3D9Presenter> m_mainPresenter;
+ std::list<Rc<D3D9Presenter>> m_presenters;
- DxvkSubmitStatus m_presentStatus;
-
- std::vector<Rc<DxvkImageView>> m_imageViews;
-
-
- uint64_t m_frameId = D3D9DeviceEx::MaxFrameLatency;
- uint32_t m_frameLatencyCap = 0;
- Rc<sync::Fence> m_frameLatencySignal;
-
- bool m_dirty = true;
- bool m_vsync = true;
-
- bool m_dialog;
- bool m_lastDialog = false;
-
- bool m_partialPresented = false;
-
- HWND m_window = nullptr;
HMONITOR m_monitor = nullptr;
MONITORINFOEXW m_monInfo;
WindowState m_windowState;
- void PresentImage(UINT PresentInterval);
-
- void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);
-
- void SynchronizePresent();
-
- void RecreateSwapChain(
- BOOL Vsync);
-
- void CreatePresenter();
-
- void CreateRenderTargetViews();
-
- void CreateCopyImage();
-
void CreateBackBuffers(
uint32_t NumBackBuffers);
@@ -223,10 +267,6 @@ namespace dxvk {
void UpdateMonitorInfo();
- void UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect);
-
- VkExtent2D GetPresentExtent();
-
VkFullScreenExclusiveEXT PickFullscreenMode();
std::string GetApiName();