From 40444c1f5075756593d7e5f6673f25851c23efcb Mon Sep 17 00:00:00 2001 From: Robin Kertels Date: Tue, 13 Jul 2021 21:06:34 +0200 Subject: [PATCH] [d3d9] Unify texture uploads --- src/d3d9/d3d9_device.cpp | 270 +++++++++++++++++---------------------- src/d3d9/d3d9_device.h | 9 ++ 2 files changed, 123 insertions(+), 156 deletions(-) diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index b16152c0..6b1e0979 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -677,15 +677,17 @@ namespace dxvk { const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTextureInfo->GetFormatMapping().FormatColor); - VkOffset3D srcBlockOffset = { 0u, 0u, 0u }; + VkOffset3D srcOffset = { 0u, 0u, 0u }; VkOffset3D dstOffset = { 0u, 0u, 0u }; VkExtent3D texLevelExtent = srcTextureInfo->GetExtentMip(src->GetSubresource()); - VkExtent3D texLevelBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize); - - VkExtent3D copyExtent = texLevelExtent; + VkExtent3D extent = texLevelExtent; if (pSourceRect != nullptr) { - const VkExtent3D extent = { uint32_t(pSourceRect->right - pSourceRect->left), uint32_t(pSourceRect->bottom - pSourceRect->top), 1 }; + srcOffset = { pSourceRect->left, + pSourceRect->top, + 0u }; + + extent = { uint32_t(pSourceRect->right - pSourceRect->left), uint32_t(pSourceRect->bottom - pSourceRect->top), 1 }; const bool extentAligned = extent.width % formatInfo->blockSize.width == 0 && extent.height % formatInfo->blockSize.height == 0; @@ -698,14 +700,6 @@ namespace dxvk { || pSourceRect->top % formatInfo->blockSize.height != 0 || (extent != texLevelExtent && !extentAligned)) return D3DERR_INVALIDCALL; - - srcBlockOffset = { pSourceRect->left / int32_t(formatInfo->blockSize.width), - pSourceRect->top / int32_t(formatInfo->blockSize.height), - 0u }; - - copyExtent = { extent.width, - extent.height, - 1u }; } if (pDestPoint != nullptr) { @@ -720,37 +714,7 @@ namespace dxvk { 0u }; } - VkExtent3D copyBlockCount = util::computeBlockCount(copyExtent, formatInfo->blockSize); - - const auto dstSubresource = vk::makeSubresourceLayers( - dstTextureInfo->GetSubresourceFromIndex(VK_IMAGE_ASPECT_COLOR_BIT, dst->GetSubresource())); - - DxvkBufferSliceHandle srcSlice = srcTextureInfo->GetMappedSlice(src->GetSubresource()); - VkDeviceSize dirtySize = copyBlockCount.width * copyBlockCount.height * formatInfo->elementSize; - D3D9BufferSlice slice = AllocTempBuffer(dirtySize); - VkDeviceSize pitch = align(texLevelBlockCount.width * formatInfo->elementSize, 4); - VkDeviceSize copySrcOffset = srcBlockOffset.z * texLevelBlockCount.height * pitch - + srcBlockOffset.y * pitch - + srcBlockOffset.x * formatInfo->elementSize; - - void* srcData = reinterpret_cast(srcSlice.mapPtr) + copySrcOffset; - util::packImageData( - slice.mapPtr, srcData, copyBlockCount, formatInfo->elementSize, - pitch, pitch * texLevelBlockCount.height); - - Rc dstImage = dstTextureInfo->GetImage(); - - EmitCs([ - cDstImage = std::move(dstImage), - cSrcSlice = slice.slice, - cDstLayers = dstSubresource, - cDstOffset = dstOffset, - cCopyExtent = copyExtent - ] (DxvkContext* ctx) { - ctx->copyBufferToImage( - cDstImage, cDstLayers, cDstOffset, cCopyExtent, - cSrcSlice.buffer(), cSrcSlice.offset(), 0, 0); - }); + UpdateTextureFromBuffer(dstTextureInfo, srcTextureInfo, dst->GetSubresource(), src->GetSubresource(), srcOffset, extent, dstOffset); dstTextureInfo->SetWrittenByGPU(dst->GetSubresource(), true); @@ -782,7 +746,6 @@ namespace dxvk { return D3DERR_INVALIDCALL; const Rc dstImage = dstTexInfo->GetImage(); - const DxvkFormatInfo* formatInfo = imageFormatInfo(dstTexInfo->GetFormatMapping().FormatColor); uint32_t mipLevels = dstTexInfo->Desc()->MipLevels; uint32_t arraySlices = std::min(srcTexInfo->Desc()->ArraySize, dstTexInfo->Desc()->ArraySize); @@ -803,61 +766,22 @@ namespace dxvk { if (box.Left >= box.Right || box.Top >= box.Bottom || box.Front >= box.Back) continue; + VkExtent3D mip0Extent = { + uint32_t(box.Right - box.Left), + uint32_t(box.Bottom - box.Top), + uint32_t(box.Back - box.Front) + }; + VkOffset3D mip0Offset = { int32_t(box.Left), int32_t(box.Top), int32_t(box.Front) }; + for (uint32_t dstMip = 0; dstMip < mipLevels; dstMip++) { uint32_t srcMip = dstMip + srcMipOffset; - VkImageSubresourceLayers dstLayers = { VK_IMAGE_ASPECT_COLOR_BIT, dstMip, a, 1 }; + uint32_t srcSubresource = srcTexInfo->CalcSubresource(a, srcMip); + uint32_t dstSubresource = dstTexInfo->CalcSubresource(a, dstMip); + VkExtent3D extent = util::computeMipLevelExtent(mip0Extent, srcMip); + VkOffset3D offset = util::computeMipLevelOffset(mip0Offset, srcMip); - VkOffset3D scaledBoxOffset = { - int32_t(alignDown(box.Left >> srcMip, formatInfo->blockSize.width)), - int32_t(alignDown(box.Top >> srcMip, formatInfo->blockSize.height)), - int32_t(alignDown(box.Front >> srcMip, formatInfo->blockSize.depth)) - }; - VkExtent3D scaledBoxExtent = util::computeMipLevelExtent({ - uint32_t(box.Right - int32_t(alignDown(box.Left, formatInfo->blockSize.width))), - uint32_t(box.Bottom - int32_t(alignDown(box.Top, formatInfo->blockSize.height))), - uint32_t(box.Back - int32_t(alignDown(box.Front, formatInfo->blockSize.depth))) - }, srcMip); - VkExtent3D scaledBoxExtentBlockCount = util::computeBlockCount(scaledBoxExtent, formatInfo->blockSize); - VkExtent3D scaledAlignedBoxExtent = util::computeBlockExtent(scaledBoxExtentBlockCount, formatInfo->blockSize); - - VkExtent3D texLevelExtent = dstImage->mipLevelExtent(dstMip); - VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize); - - scaledAlignedBoxExtent.width = std::min(texLevelExtent.width - scaledBoxOffset.x, scaledAlignedBoxExtent.width); - scaledAlignedBoxExtent.height = std::min(texLevelExtent.height - scaledBoxOffset.y, scaledAlignedBoxExtent.height); - scaledAlignedBoxExtent.depth = std::min(texLevelExtent.depth - scaledBoxOffset.z, scaledAlignedBoxExtent.depth); - - VkDeviceSize dirtySize = scaledBoxExtentBlockCount.width * scaledBoxExtentBlockCount.height * scaledBoxExtentBlockCount.depth * formatInfo->elementSize; - D3D9BufferSlice slice = AllocTempBuffer(dirtySize); - VkOffset3D boxOffsetBlockCount = util::computeBlockOffset(scaledBoxOffset, formatInfo->blockSize); - VkDeviceSize pitch = align(texLevelExtentBlockCount.width * formatInfo->elementSize, 4); - VkDeviceSize copySrcOffset = boxOffsetBlockCount.z * texLevelExtentBlockCount.height * pitch - + boxOffsetBlockCount.y * pitch - + boxOffsetBlockCount.x * formatInfo->elementSize; - - void* srcData = reinterpret_cast(srcTexInfo->GetMappedSlice(srcTexInfo->CalcSubresource(a, srcMip)).mapPtr) + copySrcOffset; - util::packImageData( - slice.mapPtr, srcData, scaledBoxExtentBlockCount, formatInfo->elementSize, - pitch, pitch * texLevelExtentBlockCount.height); - - scaledAlignedBoxExtent.width = std::min(texLevelExtent.width, scaledAlignedBoxExtent.width); - scaledAlignedBoxExtent.height = std::min(texLevelExtent.height, scaledAlignedBoxExtent.height); - scaledAlignedBoxExtent.depth = std::min(texLevelExtent.depth, scaledAlignedBoxExtent.depth); - - EmitCs([ - cDstImage = dstImage, - cSrcSlice = slice.slice, - cDstLayers = dstLayers, - cExtent = scaledAlignedBoxExtent, - cOffset = scaledBoxOffset - ] (DxvkContext* ctx) { - ctx->copyBufferToImage( - cDstImage, cDstLayers, - cOffset, cExtent, - cSrcSlice.buffer(), cSrcSlice.offset(), 0, 0); - }); - - dstTexInfo->SetWrittenByGPU(dstTexInfo->CalcSubresource(a, dstMip), true); + UpdateTextureFromBuffer(dstTexInfo, srcTexInfo, dstSubresource, srcSubresource, offset, extent, offset); + dstTexInfo->SetWrittenByGPU(dstSubresource, true); } } @@ -4443,65 +4367,97 @@ namespace dxvk { HRESULT D3D9DeviceEx::FlushImage( D3D9CommonTexture* pResource, UINT Subresource) { + const Rc image = pResource->GetImage(); - - // Now that data has been written into the buffer, - // we need to copy its contents into the image - const DxvkBufferSliceHandle srcSlice = pResource->GetMappedSlice(Subresource); - auto formatInfo = imageFormatInfo(image->info().format); auto subresource = pResource->GetSubresourceFromIndex( formatInfo->aspectMask, Subresource); - VkImageSubresourceLayers subresourceLayers = { - subresource.aspectMask, - subresource.mipLevel, - subresource.arrayLayer, 1 }; + const D3DBOX& box = pResource->GetDirtyBox(subresource.arrayLayer); - auto convertFormat = pResource->GetFormatMapping().ConversionFormatInfo; + VkExtent3D mip0Extent = { box.Right - box.Left, box.Bottom - box.Top, box.Back - box.Front }; + VkExtent3D extent = util::computeMipLevelExtent(mip0Extent, subresource.mipLevel); + VkOffset3D mip0Offset = { int32_t(box.Left), int32_t(box.Top), int32_t(box.Front) }; + VkOffset3D offset = util::computeMipLevelOffset(mip0Offset, subresource.mipLevel); + + UpdateTextureFromBuffer(pResource, pResource, Subresource, Subresource, offset, extent, offset); + + if (pResource->IsAutomaticMip()) + MarkTextureMipsDirty(pResource); + + return D3D_OK; + } + + void D3D9DeviceEx::UpdateTextureFromBuffer( + D3D9CommonTexture* pDestTexture, + D3D9CommonTexture* pSrcTexture, + UINT DestSubresource, + UINT SrcSubresource, + VkOffset3D SrcOffset, + VkExtent3D SrcExtent, + VkOffset3D DestOffset + ) { + const Rc image = pDestTexture->GetImage(); + + // Now that data has been written into the buffer, + // we need to copy its contents into the image + const DxvkBufferSliceHandle srcSlice = pSrcTexture->GetMappedSlice(SrcSubresource); + + auto formatInfo = imageFormatInfo(image->info().format); + auto srcSubresource = pSrcTexture->GetSubresourceFromIndex( + formatInfo->aspectMask, SrcSubresource); + + auto dstSubresource = pDestTexture->GetSubresourceFromIndex( + formatInfo->aspectMask, DestSubresource); + VkImageSubresourceLayers dstLayers = { dstSubresource.aspectMask, dstSubresource.mipLevel, dstSubresource.arrayLayer, 1 }; + + VkExtent3D dstTexLevelExtent = image->mipLevelExtent(dstSubresource.mipLevel); + VkExtent3D srcTexLevelExtent = util::computeMipLevelExtent(pSrcTexture->GetExtent(), srcSubresource.mipLevel); + VkExtent3D srcTexLevelExtentBlockCount = util::computeBlockCount(srcTexLevelExtent, formatInfo->blockSize); + + auto convertFormat = pDestTexture->GetFormatMapping().ConversionFormatInfo; if (likely(convertFormat.FormatType == D3D9ConversionFormat_None)) { - VkImageSubresourceLayers dstLayers = { VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel, subresource.arrayLayer, 1 }; - - const D3DBOX& box = pResource->GetDirtyBox(subresource.arrayLayer); - VkOffset3D scaledBoxOffset = { - int32_t(alignDown(box.Left >> subresource.mipLevel, formatInfo->blockSize.width)), - int32_t(alignDown(box.Top >> subresource.mipLevel, formatInfo->blockSize.height)), - int32_t(alignDown(box.Front >> subresource.mipLevel, formatInfo->blockSize.depth)) + VkOffset3D alignedDestOffset = { + int32_t(alignDown(DestOffset.x, formatInfo->blockSize.width)), + int32_t(alignDown(DestOffset.y, formatInfo->blockSize.height)), + int32_t(alignDown(DestOffset.z, formatInfo->blockSize.depth)) }; - VkExtent3D scaledBoxExtent = util::computeMipLevelExtent({ - uint32_t(box.Right - int32_t(alignDown(box.Left, formatInfo->blockSize.width))), - uint32_t(box.Bottom - int32_t(alignDown(box.Top, formatInfo->blockSize.height))), - uint32_t(box.Back - int32_t(alignDown(box.Front, formatInfo->blockSize.depth))) - }, subresource.mipLevel); - VkExtent3D scaledBoxExtentBlockCount = util::computeBlockCount(scaledBoxExtent, formatInfo->blockSize); - VkExtent3D scaledAlignedBoxExtent = util::computeBlockExtent(scaledBoxExtentBlockCount, formatInfo->blockSize); + VkOffset3D alignedSrcOffset = { + int32_t(alignDown(SrcOffset.x, formatInfo->blockSize.width)), + int32_t(alignDown(SrcOffset.y, formatInfo->blockSize.height)), + int32_t(alignDown(SrcOffset.z, formatInfo->blockSize.depth)) + }; + SrcExtent.width += SrcOffset.x - alignedSrcOffset.x; + SrcExtent.height += SrcOffset.y - alignedSrcOffset.y; + SrcExtent.depth += SrcOffset.z - alignedSrcOffset.z; + VkExtent3D extentBlockCount = util::computeBlockCount(SrcExtent, formatInfo->blockSize); + VkExtent3D alignedExtent = util::computeBlockExtent(extentBlockCount, formatInfo->blockSize); - VkExtent3D texLevelExtent = image->mipLevelExtent(subresource.mipLevel); - VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize); + alignedExtent = util::snapExtent3D(alignedDestOffset, alignedExtent, dstTexLevelExtent); + alignedExtent = util::snapExtent3D(alignedSrcOffset, alignedExtent, srcTexLevelExtent); - scaledAlignedBoxExtent.width = std::min(texLevelExtent.width - scaledBoxOffset.x, scaledAlignedBoxExtent.width); - scaledAlignedBoxExtent.height = std::min(texLevelExtent.height - scaledBoxOffset.y, scaledAlignedBoxExtent.height); - scaledAlignedBoxExtent.depth = std::min(texLevelExtent.depth - scaledBoxOffset.z, scaledAlignedBoxExtent.depth); + VkOffset3D srcOffsetBlockCount = util::computeBlockOffset(alignedSrcOffset, formatInfo->blockSize); + VkExtent3D srcTexLevelExtentBlockCount = util::computeBlockCount(srcTexLevelExtent, formatInfo->blockSize); + VkDeviceSize pitch = align(srcTexLevelExtentBlockCount.width * formatInfo->elementSize, 4); + VkDeviceSize copySrcOffset = srcOffsetBlockCount.z * srcTexLevelExtentBlockCount.height * pitch + + srcOffsetBlockCount.y * pitch + + srcOffsetBlockCount.x * formatInfo->elementSize; - VkOffset3D boxOffsetBlockCount = util::computeBlockOffset(scaledBoxOffset, formatInfo->blockSize); - VkDeviceSize pitch = align(texLevelExtentBlockCount.width * formatInfo->elementSize, 4); - VkDeviceSize copySrcOffset = boxOffsetBlockCount.z * texLevelExtentBlockCount.height * pitch - + boxOffsetBlockCount.y * pitch - + boxOffsetBlockCount.x * formatInfo->elementSize; - - VkDeviceSize rowAlignment = 0; + VkDeviceSize rowAlignment = 1; DxvkBufferSlice copySrcSlice; - if (pResource->DoesStagingBufferUploads(Subresource)) { - VkDeviceSize dirtySize = scaledBoxExtentBlockCount.width * scaledBoxExtentBlockCount.height * scaledBoxExtentBlockCount.depth * formatInfo->elementSize; + if (pSrcTexture->DoesStagingBufferUploads(SrcSubresource)) { + VkDeviceSize dirtySize = extentBlockCount.width * extentBlockCount.height * extentBlockCount.depth * formatInfo->elementSize; D3D9BufferSlice slice = AllocTempBuffer(dirtySize); copySrcSlice = slice.slice; void* srcData = reinterpret_cast(srcSlice.mapPtr) + copySrcOffset; util::packImageData( - slice.mapPtr, srcData, scaledBoxExtentBlockCount, formatInfo->elementSize, - pitch, pitch * texLevelExtentBlockCount.height); + slice.mapPtr, srcData, extentBlockCount, formatInfo->elementSize, + pitch, pitch * srcTexLevelExtentBlockCount.height); } else { - copySrcSlice = DxvkBufferSlice(pResource->GetBuffer(Subresource), copySrcOffset, srcSlice.length); + TrackTextureMappingBufferSequenceNumber(pSrcTexture, SrcSubresource); + + copySrcSlice = DxvkBufferSlice(pSrcTexture->GetBuffer(SrcSubresource), copySrcOffset, srcSlice.length); rowAlignment = pitch; // row alignment can act as the pitch parameter } @@ -4509,8 +4465,8 @@ namespace dxvk { cSrcSlice = std::move(copySrcSlice), cDstImage = image, cDstLayers = dstLayers, - cDstLevelExtent = scaledAlignedBoxExtent, - cOffset = scaledBoxOffset, + cDstLevelExtent = alignedExtent, + cOffset = alignedDestOffset, cRowAlignment = rowAlignment ] (DxvkContext* ctx) { ctx->copyBufferToImage( @@ -4521,39 +4477,41 @@ namespace dxvk { }); } else { - const DxvkFormatInfo* formatInfo = imageFormatInfo(pResource->GetFormatMapping().FormatColor); - VkExtent3D texLevelExtent = image->mipLevelExtent(subresource.mipLevel); - VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(texLevelExtent, formatInfo->blockSize); + const DxvkFormatInfo* formatInfo = imageFormatInfo(pDestTexture->GetFormatMapping().FormatColor); + // Add more blocks for the other planes that we might have. // TODO: PLEASE CLEAN ME - texLevelExtentBlockCount.height *= std::min(convertFormat.PlaneCount, 2u); + srcTexLevelExtentBlockCount.height *= std::min(convertFormat.PlaneCount, 2u); + + if (unlikely(SrcOffset.x != 0 || SrcOffset.y != 0 || SrcOffset.z != 0 + || DestOffset.x != 0 || DestOffset.y != 0 || DestOffset.z != 0 + || SrcExtent != srcTexLevelExtent)) { + Logger::warn("Offset and rect not supported with the texture converter."); + } + + if (unlikely(srcTexLevelExtent != dstTexLevelExtent)) { + Logger::err("Different extents are not supported with the texture converter."); + return; + } // the converter can not handle the 4 aligned pitch so we always repack into a staging buffer D3D9BufferSlice slice = AllocTempBuffer(srcSlice.length); - VkDeviceSize pitch = align(texLevelExtentBlockCount.width * formatInfo->elementSize, 4); + VkDeviceSize pitch = align(srcTexLevelExtentBlockCount.width * formatInfo->elementSize, 4); util::packImageData( - slice.mapPtr, srcSlice.mapPtr, texLevelExtentBlockCount, formatInfo->elementSize, - pitch, std::min(convertFormat.PlaneCount, 2u) * pitch * texLevelExtentBlockCount.height); + slice.mapPtr, srcSlice.mapPtr, srcTexLevelExtentBlockCount, formatInfo->elementSize, + pitch, std::min(convertFormat.PlaneCount, 2u) * pitch * srcTexLevelExtentBlockCount.height); Flush(); SynchronizeCsThread(DxvkCsThread::SynchronizeAll); m_converter->ConvertFormat( convertFormat, - image, subresourceLayers, + image, dstLayers, slice.slice); } - - if (pResource->IsAutomaticMip()) - MarkTextureMipsDirty(pResource); - - TrackTextureMappingBufferSequenceNumber(pResource, Subresource); - - return D3D_OK; } - void D3D9DeviceEx::EmitGenerateMips( D3D9CommonTexture* pResource) { if (pResource->IsManaged()) diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h index 3b38825a..fe8e972f 100644 --- a/src/d3d9/d3d9_device.h +++ b/src/d3d9/d3d9_device.h @@ -704,6 +704,15 @@ namespace dxvk { D3D9CommonTexture* pResource, UINT Subresource); + void UpdateTextureFromBuffer( + D3D9CommonTexture* pDestTexture, + D3D9CommonTexture* pSrcTexture, + UINT DestSubresource, + UINT SrcSubresource, + VkOffset3D SrcOffset, + VkExtent3D SrcExtent, + VkOffset3D DestOffset); + void EmitGenerateMips( D3D9CommonTexture* pResource);