diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 13f42e1057..709e4c31b4 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -2,8 +2,8 @@ #include "d3d9_surface.h" #include "d3d9_monitor.h" -#include -#include +#include +#include namespace dxvk { @@ -14,6 +14,12 @@ namespace dxvk { } + struct D3D9PresentInfo { + float scale[2]; + float offset[2]; + }; + + D3D9SwapChainEx::D3D9SwapChainEx( D3D9DeviceEx* pDevice, D3DPRESENT_PARAMETERS* pPresentParams, @@ -27,7 +33,7 @@ namespace dxvk { m_presentParams = *pPresentParams; m_window = m_presentParams.hDeviceWindow; - UpdatePresentExtent(nullptr); + UpdatePresentRegion(nullptr, nullptr); if (!pDevice->GetOptions()->deferSurfaceCreation) CreatePresenter(); @@ -109,11 +115,12 @@ namespace dxvk { recreate |= m_presenter == nullptr; recreate |= window != m_window; + m_window = window; + m_dirty |= vsync != m_vsync; - m_dirty |= UpdatePresentExtent(pSourceRect); + m_dirty |= UpdatePresentRegion(pSourceRect, pDestRect); m_dirty |= recreate; m_vsync = vsync; - m_window = window; if (recreate) CreatePresenter(); @@ -314,7 +321,7 @@ namespace dxvk { } m_presentParams = *pPresentParams; - UpdatePresentExtent(nullptr); + UpdatePresentRegion(nullptr, nullptr); CreateBackBuffer(); return D3D_OK; } @@ -463,18 +470,27 @@ namespace dxvk { m_context->bindRenderTargets(renderTargets, false); VkViewport viewport; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = float(m_swapImage->info().extent.width); - viewport.height = float(m_swapImage->info().extent.height); + viewport.x = float(m_dstRect.left); + viewport.y = float(m_dstRect.top); + viewport.width = float(info.imageExtent.width - m_dstRect.left); + viewport.height = float(info.imageExtent.height - m_dstRect.top); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; + + D3D9PresentInfo presentInfoConsts; + presentInfoConsts.scale[0] = float(m_srcRect.right - m_srcRect.left) / float(m_swapImage->info().extent.width); + presentInfoConsts.scale[1] = float(m_srcRect.bottom - m_srcRect.top) / float(m_swapImage->info().extent.height); + + presentInfoConsts.offset[0] = float(m_srcRect.left) / float(m_swapImage->info().extent.width); + presentInfoConsts.offset[1] = float(m_srcRect.top) / float(m_swapImage->info().extent.height); + + m_context->pushConstants(0, sizeof(D3D9PresentInfo), &presentInfoConsts); VkRect2D scissor; scissor.offset.x = 0; scissor.offset.y = 0; - scissor.extent.width = info.imageExtent.width; - scissor.extent.height = info.imageExtent.height; + scissor.extent.width = info.imageExtent.width - m_dstRect.left; + scissor.extent.height = info.imageExtent.height - m_dstRect.top; m_context->setViewports(1, &viewport, &scissor); @@ -530,7 +546,7 @@ namespace dxvk { m_presentStatus.result = VK_SUCCESS; vk::PresenterDesc presenterDesc; - presenterDesc.imageExtent = m_presentExtent; + 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); @@ -551,7 +567,7 @@ namespace dxvk { presenterDevice.adapter = m_device->adapter()->handle(); vk::PresenterDesc presenterDesc; - presenterDesc.imageExtent = m_presentExtent; + 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); @@ -864,8 +880,8 @@ namespace dxvk { void D3D9SwapChainEx::InitShaders() { - const SpirvCodeBuffer vsCode(dxgi_presenter_vert); - const SpirvCodeBuffer fsCode(dxgi_presenter_frag); + const SpirvCodeBuffer vsCode(d3d9_presenter_vert); + const SpirvCodeBuffer fsCode(d3d9_presenter_frag); const std::array fsResourceSlots = {{ { BindingIds::Image, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_2D }, @@ -874,7 +890,9 @@ namespace dxvk { m_vertShader = m_device->createShader( VK_SHADER_STAGE_VERTEX_BIT, - 0, nullptr, { 0u, 1u }, + 0, nullptr, + { 0u, 1u, + 0u, sizeof(D3D9PresentInfo) }, vsCode); m_fragShader = m_device->createShader( @@ -1071,17 +1089,43 @@ namespace dxvk { return SetMonitorDisplayMode(GetDefaultMonitor(), &mode); } - bool D3D9SwapChainEx::UpdatePresentExtent(const RECT* pSourceRect) { - VkExtent2D oldExtent = m_presentExtent; - - if (pSourceRect != nullptr) - m_presentExtent = VkExtent2D{ uint32_t(pSourceRect->right - pSourceRect->left), uint32_t(pSourceRect->bottom - pSourceRect->top) }; + bool 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); + + dstRect.top = 0; + dstRect.left = 0; + dstRect.right = LONG(width); + dstRect.bottom = LONG(height); + } else - m_presentExtent = VkExtent2D{ m_presentParams.BackBufferWidth, m_presentParams.BackBufferHeight }; + dstRect = *pDestRect; - m_presentExtent = VkExtent2D{ std::max(m_presentExtent.width, 1u), std::max(m_presentExtent.height, 1u) }; + bool recreate = + m_dstRect.left != dstRect.left + || m_dstRect.top != dstRect.top + || m_dstRect.right != dstRect.right + || m_dstRect.bottom != dstRect.bottom; + + m_dstRect = dstRect; + + return recreate; + } - return m_presentExtent != oldExtent; + VkExtent2D D3D9SwapChainEx::GetPresentExtent() { + return VkExtent2D{ uint32_t(m_dstRect.right - m_dstRect.left), uint32_t(m_dstRect.bottom - m_dstRect.top) }; } void D3D9SwapChainEx::UpdateMonitorInfo() { diff --git a/src/d3d9/d3d9_swapchain.h b/src/d3d9/d3d9_swapchain.h index ca381f800b..e99baa79f0 100644 --- a/src/d3d9/d3d9_swapchain.h +++ b/src/d3d9/d3d9_swapchain.h @@ -122,7 +122,9 @@ namespace dxvk { DxvkBlendMode m_blendMode; D3D9Surface* m_backBuffer = nullptr; - VkExtent2D m_presentExtent; + + RECT m_srcRect; + RECT m_dstRect; DxvkSubmitStatus m_presentStatus; @@ -196,7 +198,9 @@ namespace dxvk { void UpdateMonitorInfo(); - bool UpdatePresentExtent(const RECT* pSourceRect); + bool UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect); + + VkExtent2D GetPresentExtent(); }; diff --git a/src/d3d9/meson.build b/src/d3d9/meson.build index 81f77b3cb8..b0707fdc23 100644 --- a/src/d3d9/meson.build +++ b/src/d3d9/meson.build @@ -1,8 +1,8 @@ d3d9_res = wrc_generator.process('version.rc') d3d9_shaders = files([ - '../dxgi/shaders/dxgi_presenter_frag.frag', - '../dxgi/shaders/dxgi_presenter_vert.vert', + 'shaders/d3d9_presenter_frag.frag', + 'shaders/d3d9_presenter_vert.vert', ]) d3d9_src = [ diff --git a/src/d3d9/shaders/d3d9_presenter_frag.frag b/src/d3d9/shaders/d3d9_presenter_frag.frag new file mode 100644 index 0000000000..e52a0d765a --- /dev/null +++ b/src/d3d9/shaders/d3d9_presenter_frag.frag @@ -0,0 +1,21 @@ +#version 450 + +layout(constant_id = 1) const bool s_gamma_bound = true; + +layout(binding = 0) uniform sampler2D s_image; +layout(binding = 1) uniform sampler1D s_gamma; + +layout(location = 0) in vec2 i_texcoord; +layout(location = 0) out vec4 o_color; + +void main() { + o_color = texture(s_image, i_texcoord); + + if (s_gamma_bound) { + o_color = vec4( + texture(s_gamma, o_color.r).r, + texture(s_gamma, o_color.g).g, + texture(s_gamma, o_color.b).b, + o_color.a); + } +} \ No newline at end of file diff --git a/src/d3d9/shaders/d3d9_presenter_vert.vert b/src/d3d9/shaders/d3d9_presenter_vert.vert new file mode 100644 index 0000000000..eb5edc3cfa --- /dev/null +++ b/src/d3d9/shaders/d3d9_presenter_vert.vert @@ -0,0 +1,21 @@ +#version 450 + +layout(location = 0) out vec2 o_texcoord; + +layout(push_constant) uniform present_info_t { + vec2 scale; + vec2 offset; +} u_presentInfo; + +void main() { + vec2 coord = vec2( + float(gl_VertexIndex & 2), + float(gl_VertexIndex & 1) * 2.0f); + + gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f); + + coord *= u_presentInfo.scale; + coord += u_presentInfo.offset; + + o_texcoord = coord; +} \ No newline at end of file