[d3d9] Fix crash when auto generating mip maps for unmappable textures

This commit is contained in:
Robin Kertels 2022-08-19 21:59:54 +02:00 committed by Joshie
parent 3c38bdbd0e
commit a8b578b2a2
4 changed files with 39 additions and 36 deletions

View File

@ -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<DxvkBuffer>& 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<DxvkBuffer>& D3D9CommonTexture::GetBuffer(UINT Subresource) {
return m_buffers[Subresource];
}

View File

@ -153,7 +153,7 @@ namespace dxvk {
*/
void* GetData(UINT Subresource);
const Rc<DxvkBuffer>& GetBuffer(UINT Subresource, bool Initialize);
const Rc<DxvkBuffer>& 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();

View File

@ -889,7 +889,8 @@ namespace dxvk {
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(src->GetMipLevel());
Rc<DxvkBuffer> 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<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());
Rc<DxvkImage> 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<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource, false);
const Rc<DxvkBuffer> 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<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource, false);
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource);
if (unlikely(needsReadback) && pResource->GetImage() != nullptr) {
Rc<DxvkImage> resourceImage = pResource->GetImage();
@ -4523,7 +4524,8 @@ namespace dxvk {
auto convertFormat = pDestTexture->GetFormatMapping().ConversionFormatInfo;
if (unlikely(pSrcTexture->NeedsReadback(SrcSubresource))) {
const Rc<DxvkBuffer>& buffer = pSrcTexture->GetBuffer(SrcSubresource, false);
pSrcTexture->CreateBufferSubresource(SrcSubresource, true);
const Rc<DxvkBuffer>& buffer = pSrcTexture->GetBuffer(SrcSubresource);
WaitForResource(buffer, pSrcTexture->GetMappingBufferSequenceNumber(SrcSubresource), 0);
pSrcTexture->SetNeedsReadback(SrcSubresource, false);
}

View File

@ -180,7 +180,8 @@ namespace dxvk {
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(0);
Rc<DxvkBuffer> 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<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());
Rc<DxvkImage> srcImage = srcTexInfo->GetImage();
if (srcImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT) {