From a8b578b2a21b4ccbec1898a0cc798a7d5d7ec7e8 Mon Sep 17 00:00:00 2001 From: Robin Kertels Date: Fri, 19 Aug 2022 21:59:54 +0200 Subject: [PATCH] [d3d9] Fix crash when auto generating mip maps for unmappable textures --- src/d3d9/d3d9_common_texture.cpp | 32 ++++++++++++++++---------------- src/d3d9/d3d9_common_texture.h | 20 ++++++++++---------- src/d3d9/d3d9_device.cpp | 20 +++++++++++--------- src/d3d9/d3d9_swapchain.cpp | 3 ++- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/d3d9/d3d9_common_texture.cpp b/src/d3d9/d3d9_common_texture.cpp index 2d1b2317e..cdcd469f1 100644 --- a/src/d3d9/d3d9_common_texture.cpp +++ b/src/d3d9/d3d9_common_texture.cpp @@ -180,7 +180,11 @@ namespace dxvk { return memory.Ptr(); } - void D3D9CommonTexture::CreateBufferSubresource(UINT Subresource) { + void D3D9CommonTexture::CreateBufferSubresource(UINT Subresource, bool Initialize) { + if (likely(m_buffers[Subresource] != nullptr)) { + return; + } + DxvkBufferCreateInfo info; info.size = GetMipSize(Subresource); info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT @@ -201,6 +205,16 @@ namespace dxvk { m_buffers[Subresource] = m_device->GetDXVKDevice()->createBuffer(info, memType); m_mappedSlices[Subresource] = m_buffers[Subresource]->getSliceHandle(); + + if (Initialize) { + if (m_data[Subresource]) { + m_data[Subresource].Map(); + memcpy(m_mappedSlices[Subresource].mapPtr, m_data[Subresource].Ptr(), info.size); + } else { + memset(m_mappedSlices[Subresource].mapPtr, 0, info.size); + } + } + m_data[Subresource] = {}; } @@ -642,21 +656,7 @@ namespace dxvk { } } - const Rc& D3D9CommonTexture::GetBuffer(UINT Subresource, bool Initialize) { - if (unlikely(m_buffers[Subresource] == nullptr)) { - CreateBufferSubresource(Subresource); - - if (Initialize) { - if (m_data[Subresource]) { - m_data[Subresource].Map(); - memcpy(m_mappedSlices[Subresource].mapPtr, m_data[Subresource].Ptr(), GetMipSize(Subresource)); - } else { - memset(m_mappedSlices[Subresource].mapPtr, 0, GetMipSize(Subresource)); - } - } - m_data[Subresource] = {}; - } - + const Rc& D3D9CommonTexture::GetBuffer(UINT Subresource) { return m_buffers[Subresource]; } diff --git a/src/d3d9/d3d9_common_texture.h b/src/d3d9/d3d9_common_texture.h index 667d3f9d7..58c0827ba 100644 --- a/src/d3d9/d3d9_common_texture.h +++ b/src/d3d9/d3d9_common_texture.h @@ -153,7 +153,7 @@ namespace dxvk { */ void* GetData(UINT Subresource); - const Rc& GetBuffer(UINT Subresource, bool Initialize); + const Rc& GetBuffer(UINT Subresource); DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) { @@ -466,6 +466,14 @@ namespace dxvk { */ VkDeviceSize GetMipSize(UINT Subresource) const; + /** + * \brief Creates a buffer + * Creates mapping and staging buffers for a given subresource + * allocates new buffers if necessary + * \returns Whether an allocation happened + */ + void CreateBufferSubresource(UINT Subresource, bool Initialize); + private: D3D9DeviceEx* m_device; @@ -542,14 +550,6 @@ namespace dxvk { D3DRESOURCETYPE Dimension, UINT Layer); - /** - * \brief Creates a buffer - * Creates mapping and staging buffers for a given subresource - * allocates new buffers if necessary - * \returns Whether an allocation happened - */ - void CreateBufferSubresource(UINT Subresource); - /** * \brief Creates buffers * Creates mapping and staging buffers for all subresources @@ -559,7 +559,7 @@ namespace dxvk { // D3D9Initializer will handle clearing the buffers const uint32_t count = CountSubresources(); for (uint32_t i = 0; i < count; i++) - CreateBufferSubresource(i); + CreateBufferSubresource(i, false); } void AllocData(); diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index a55b0bad0..2592e7858 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -889,7 +889,8 @@ namespace dxvk { VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel()); VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(src->GetMipLevel()); - Rc dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource(), dstTexExtent.width > srcTexExtent.width || dstTexExtent.height > srcTexExtent.height); + dstTexInfo->CreateBufferSubresource(dst->GetSubresource(), dstTexExtent.width > srcTexExtent.width || dstTexExtent.height > srcTexExtent.height); + Rc dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource()); Rc srcImage = srcTexInfo->GetImage(); const DxvkFormatInfo* srcFormatInfo = lookupFormatInfo(srcImage->info().format); @@ -4260,12 +4261,17 @@ namespace dxvk { bool needsReadback = pResource->NeedsReadback(Subresource) || renderable; pResource->SetNeedsReadback(Subresource, false); + if (unlikely(pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED || needsReadback)) { + // Create mapping buffer if it doesn't exist yet. (POOL_DEFAULT) + pResource->CreateBufferSubresource(Subresource, !needsReadback); + } + void* mapPtr; if ((Flags & D3DLOCK_DISCARD) && needsReadback) { // We do not have to preserve the contents of the // buffer if the entire image gets discarded. - const Rc mappedBuffer = pResource->GetBuffer(Subresource, false); + const Rc mappedBuffer = pResource->GetBuffer(Subresource); DxvkBufferSliceHandle physSlice = pResource->DiscardMapSlice(Subresource); mapPtr = physSlice.mapPtr; @@ -4276,16 +4282,11 @@ namespace dxvk { ctx->invalidateBuffer(cImageBuffer, cBufferSlice); }); } else { - if (unlikely(pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED)) { - // Create mapping buffer if it doesn't exist yet. (POOL_DEFAULT) - pResource->GetBuffer(Subresource, !needsReadback); - } - // Don't use MapTexture here to keep the mapped list small while the resource is still locked. mapPtr = pResource->GetData(Subresource); if (needsReadback) { - const Rc mappedBuffer = pResource->GetBuffer(Subresource, false); + const Rc mappedBuffer = pResource->GetBuffer(Subresource); if (unlikely(needsReadback) && pResource->GetImage() != nullptr) { Rc resourceImage = pResource->GetImage(); @@ -4523,7 +4524,8 @@ namespace dxvk { auto convertFormat = pDestTexture->GetFormatMapping().ConversionFormatInfo; if (unlikely(pSrcTexture->NeedsReadback(SrcSubresource))) { - const Rc& buffer = pSrcTexture->GetBuffer(SrcSubresource, false); + pSrcTexture->CreateBufferSubresource(SrcSubresource, true); + const Rc& buffer = pSrcTexture->GetBuffer(SrcSubresource); WaitForResource(buffer, pSrcTexture->GetMappingBufferSequenceNumber(SrcSubresource), 0); pSrcTexture->SetNeedsReadback(SrcSubresource, false); } diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp index 8268e8002..634567d80 100644 --- a/src/d3d9/d3d9_swapchain.cpp +++ b/src/d3d9/d3d9_swapchain.cpp @@ -180,7 +180,8 @@ namespace dxvk { VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel()); VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(0); - Rc dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource(), dstTexExtent.width > srcTexExtent.width || dstTexExtent.height > srcTexExtent.height); + dstTexInfo->CreateBufferSubresource(dst->GetSubresource(), dstTexExtent.width > srcTexExtent.width || dstTexExtent.height > srcTexExtent.height); + Rc dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource()); Rc srcImage = srcTexInfo->GetImage(); if (srcImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT) {