mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-14 04:29:15 +01:00
[d3d11] Implement dirty trackig for default-mapped images
Avoids GPU synchronization when using WriteToSubresource, and also reduces bandwidth.
This commit is contained in:
parent
40ffac72d9
commit
fdcbdeb28f
@ -481,8 +481,15 @@ namespace dxvk {
|
||||
if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER) {
|
||||
// If the image can be written by the GPU, we need to update the
|
||||
// mapped staging buffer to reflect the current image contents.
|
||||
if (pResource->Desc()->Usage == D3D11_USAGE_DEFAULT)
|
||||
ReadbackImageBuffer(pResource, Subresource);
|
||||
if (pResource->Desc()->Usage == D3D11_USAGE_DEFAULT) {
|
||||
bool needsReadback = !pResource->NeedsDirtyRegionTracking();
|
||||
|
||||
needsReadback |= MapType == D3D11_MAP_READ
|
||||
|| MapType == D3D11_MAP_READ_WRITE;
|
||||
|
||||
if (needsReadback)
|
||||
ReadbackImageBuffer(pResource, Subresource);
|
||||
}
|
||||
}
|
||||
|
||||
if (MapType == D3D11_MAP_READ) {
|
||||
@ -591,14 +598,16 @@ namespace dxvk {
|
||||
m_mappedImageCount -= 1;
|
||||
|
||||
if ((mapType != D3D11_MAP_READ) && (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER)) {
|
||||
// Now that data has been written into the buffer,
|
||||
// we need to copy its contents into the image
|
||||
VkImageAspectFlags aspectMask = lookupFormatInfo(pResource->GetPackedFormat())->aspectMask;
|
||||
VkImageSubresource subresource = pResource->GetSubresourceFromIndex(aspectMask, Subresource);
|
||||
if (pResource->NeedsDirtyRegionTracking()) {
|
||||
for (uint32_t i = 0; i < pResource->GetDirtyRegionCount(Subresource); i++) {
|
||||
D3D11_COMMON_TEXTURE_REGION region = pResource->GetDirtyRegion(Subresource, i);
|
||||
UpdateDirtyImageRegion(pResource, Subresource, ®ion);
|
||||
}
|
||||
|
||||
UpdateImage(pResource, &subresource, VkOffset3D { 0, 0, 0 },
|
||||
pResource->MipLevelExtent(subresource.mipLevel),
|
||||
DxvkBufferSlice(pResource->GetMappedBuffer(Subresource)));
|
||||
pResource->ClearDirtyRegions(Subresource);
|
||||
} else {
|
||||
UpdateDirtyImageRegion(pResource, Subresource, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,6 +646,67 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::UpdateDirtyImageRegion(
|
||||
D3D11CommonTexture* pResource,
|
||||
UINT Subresource,
|
||||
const D3D11_COMMON_TEXTURE_REGION* pRegion) {
|
||||
auto formatInfo = lookupFormatInfo(pResource->GetPackedFormat());
|
||||
auto subresource = vk::makeSubresourceLayers(
|
||||
pResource->GetSubresourceFromIndex(formatInfo->aspectMask, Subresource));
|
||||
|
||||
// Update the entire image if no dirty region was specified
|
||||
D3D11_COMMON_TEXTURE_REGION region;
|
||||
|
||||
if (pRegion) {
|
||||
region = *pRegion;
|
||||
} else {
|
||||
region.Offset = VkOffset3D { 0, 0, 0 };
|
||||
region.Extent = pResource->MipLevelExtent(subresource.mipLevel);
|
||||
}
|
||||
|
||||
auto subresourceLayout = pResource->GetSubresourceLayout(formatInfo->aspectMask, Subresource);
|
||||
|
||||
// Update dirty region one aspect at a time, due to
|
||||
// how the data is laid out in the staging buffer.
|
||||
for (uint32_t i = 0; i < pResource->GetPlaneCount(); i++) {
|
||||
subresource.aspectMask = formatInfo->aspectMask;
|
||||
|
||||
if (formatInfo->flags.test(DxvkFormatFlag::MultiPlane))
|
||||
subresource.aspectMask = vk::getPlaneAspect(i);
|
||||
|
||||
EmitCs([
|
||||
cDstImage = pResource->GetImage(),
|
||||
cDstSubresource = subresource,
|
||||
cDstOffset = region.Offset,
|
||||
cDstExtent = region.Extent,
|
||||
cSrcBuffer = pResource->GetMappedBuffer(Subresource),
|
||||
cSrcOffset = pResource->ComputeMappedOffset(Subresource, i, region.Offset),
|
||||
cSrcRowPitch = subresourceLayout.RowPitch,
|
||||
cSrcDepthPitch = subresourceLayout.DepthPitch,
|
||||
cPackedFormat = pResource->GetPackedFormat()
|
||||
] (DxvkContext* ctx) {
|
||||
if (cDstSubresource.aspectMask != (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
||||
ctx->copyBufferToImage(
|
||||
cDstImage, cDstSubresource, cDstOffset, cDstExtent,
|
||||
cSrcBuffer, cSrcOffset, cSrcRowPitch, cSrcDepthPitch);
|
||||
} else {
|
||||
ctx->copyPackedBufferToDepthStencilImage(
|
||||
cDstImage, cDstSubresource,
|
||||
VkOffset2D { cDstOffset.x, cDstOffset.y },
|
||||
VkExtent2D { cDstExtent.width, cDstExtent.height },
|
||||
cSrcBuffer, 0,
|
||||
VkOffset2D { cDstOffset.x, cDstOffset.y },
|
||||
VkExtent2D { cDstExtent.width, cDstExtent.height },
|
||||
cPackedFormat);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (pResource->HasSequenceNumber())
|
||||
TrackTextureSequenceNumber(pResource, Subresource);
|
||||
}
|
||||
|
||||
|
||||
void D3D11ImmediateContext::UpdateMappedBuffer(
|
||||
D3D11Buffer* pDstBuffer,
|
||||
UINT Offset,
|
||||
|
@ -124,6 +124,11 @@ namespace dxvk {
|
||||
D3D11CommonTexture* pResource,
|
||||
UINT Subresource);
|
||||
|
||||
void UpdateDirtyImageRegion(
|
||||
D3D11CommonTexture* pResource,
|
||||
UINT Subresource,
|
||||
const D3D11_COMMON_TEXTURE_REGION* pRegion);
|
||||
|
||||
void UpdateMappedBuffer(
|
||||
D3D11Buffer* pDstBuffer,
|
||||
UINT Offset,
|
||||
|
@ -2348,6 +2348,10 @@ namespace dxvk {
|
||||
dataOffset += util::computeImageDataSize(
|
||||
pTexture->GetPackedFormat(), extent, aspect);
|
||||
}
|
||||
|
||||
// Track dirty texture region if necessary
|
||||
if constexpr (std::is_const<Void>::value)
|
||||
pTexture->AddDirtyRegion(Subresource, offset, extent);
|
||||
}
|
||||
|
||||
|
||||
|
@ -342,13 +342,13 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves dirty regions
|
||||
* \brief Queries a dirty regions
|
||||
*
|
||||
* \param [in] Subresource Subresource index
|
||||
* \param [in] Region Region index
|
||||
* \returns Dirty region
|
||||
*/
|
||||
D3D11_COMMON_TEXTURE_REGION GetDirtyRegionCount(UINT Subresource, UINT Region) {
|
||||
D3D11_COMMON_TEXTURE_REGION GetDirtyRegion(UINT Subresource, UINT Region) {
|
||||
return m_buffers[Subresource].dirtyRegions[Region];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user