From d39cf311899a0f10e082c09588689b78ad6d0d5e Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Fri, 5 Jun 2020 02:34:44 +0100 Subject: [PATCH] [d3d9] Implement uploadAllManagedSubresources option Nekopara locks mip 1, then unlocks mip 0 and expects it to upload all the mips. --- src/d3d9/d3d9_common_texture.h | 6 ++++++ src/d3d9/d3d9_device.cpp | 10 ++++++++-- src/d3d9/d3d9_options.cpp | 1 + src/d3d9/d3d9_options.h | 4 ++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/d3d9/d3d9_common_texture.h b/src/d3d9/d3d9_common_texture.h index fcca8924..df3f3cd4 100644 --- a/src/d3d9/d3d9_common_texture.h +++ b/src/d3d9/d3d9_common_texture.h @@ -355,6 +355,12 @@ namespace dxvk { bool GetUploading(UINT Subresource) const { return m_uploading.get(Subresource); } void SetNeedsUpload(UINT Subresource, bool upload) { m_needsUpload.set(Subresource, upload); } + void MarkAllForUpload() { + for (uint32_t i = 0; i < m_needsUpload.dwordCount() - 1; i++) + m_needsUpload.dword(i) = std::numeric_limits::max(); + + m_needsUpload.dword(m_needsUpload.dwordCount() - 1) = CountSubresources() % 32; + } bool NeedsAnyUpload() { return m_needsUpload.any(); } void ClearNeedsUpload() { return m_needsUpload.clearAll(); } diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 8c613c78..ad47f3c1 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -4120,7 +4120,7 @@ namespace dxvk { UINT Subresource = pResource->CalcSubresource(Face, MipLevel); // We weren't locked anyway! - if (unlikely(!pResource->GetLocked(Subresource))) + if (unlikely(!pResource->GetLocked(Subresource) && !m_d3d9Options.uploadAllManagedSubresources)) return D3DERR_INVALIDCALL; pResource->SetLocked(Subresource, false); @@ -4129,7 +4129,10 @@ namespace dxvk { if (!pResource->GetReadOnlyLocked(Subresource)) { // Only flush buffer -> image if we actually have an image if (pResource->IsManaged() && !m_d3d9Options.evictManagedOnUnlock) { - pResource->SetNeedsUpload(Subresource, true); + if (unlikely(m_d3d9Options.uploadAllManagedSubresources)) + pResource->MarkAllForUpload(); + else + pResource->SetNeedsUpload(Subresource, true); for (uint32_t tex = m_activeTextures; tex; tex &= tex - 1) { // Guaranteed to not be nullptr... @@ -4167,6 +4170,9 @@ namespace dxvk { // we need to copy its contents into the image const Rc copyBuffer = pResource->GetBuffer(Subresource); + if (unlikely(copyBuffer == nullptr)) + return D3D_OK; + auto formatInfo = imageFormatInfo(image->info().format); auto subresource = pResource->GetSubresourceFromIndex( formatInfo->aspectMask, Subresource); diff --git a/src/d3d9/d3d9_options.cpp b/src/d3d9/d3d9_options.cpp index 4da9f936..1dc814e5 100644 --- a/src/d3d9/d3d9_options.cpp +++ b/src/d3d9/d3d9_options.cpp @@ -71,6 +71,7 @@ namespace dxvk { this->enumerateByDisplays = config.getOption ("d3d9.enumerateByDisplays", true); this->longMad = config.getOption ("d3d9.longMad", false); this->tearFree = config.getOption ("d3d9.tearFree", Tristate::Auto); + this->uploadAllManagedSubresources = config.getOption("d3d9.uploadAllManagedSubresources", false); // If we are not Nvidia, enable general hazards. this->generalHazards = adapter == nullptr || !adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0); diff --git a/src/d3d9/d3d9_options.h b/src/d3d9/d3d9_options.h index 5f36a9a4..00e1f188 100644 --- a/src/d3d9/d3d9_options.h +++ b/src/d3d9/d3d9_options.h @@ -147,6 +147,10 @@ namespace dxvk { /// Tear-free mode if vsync is disabled /// Tearing mode if vsync is enabled Tristate tearFree; + + /// Upload all subresources of managed resources when unlocked. + /// Workaround for a game bug in Nekopara. + bool uploadAllManagedSubresources; }; } \ No newline at end of file