[d3d11] Re-implement direct image mapping (disabled by default)

We cannot enable this by default yet because it may break some games.
This commit is contained in:
Philip Rebohle 2018-03-14 16:40:28 +01:00
parent 155bd32e22
commit 3b20c71894
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 76 additions and 55 deletions

View File

@ -189,70 +189,89 @@ namespace dxvk {
if (pMappedResource == nullptr)
return S_FALSE;
// Parameter validation was successful
VkImageSubresource subresource =
pResource->GetSubresourceFromIndex(
VK_IMAGE_ASPECT_COLOR_BIT, Subresource);
pResource->SetMappedSubresource(subresource);
// Query format info in order to compute
// the row pitch and layer pitch properly.
const DxvkFormatInfo* formatInfo = imageFormatInfo(mappedImage->info().format);
const VkExtent3D levelExtent = mappedImage->mipLevelExtent(subresource.mipLevel);
const VkExtent3D blockCount = util::computeBlockCount(
levelExtent, formatInfo->blockSize);
DxvkPhysicalBufferSlice physicalSlice;
// When using any map mode which requires the image contents
// to be preserved, copy the image's contents into the buffer.
if (MapType == D3D11_MAP_WRITE_DISCARD) {
physicalSlice = mappedBuffer->allocPhysicalSlice();
physicalSlice.resource()->acquire();
if (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
const VkImageType imageType = mappedImage->info().type;
EmitCs([
cImageBuffer = mappedBuffer,
cPhysicalSlice = physicalSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice);
cPhysicalSlice.resource()->release();
});
} else {
// We may have to copy the current image contents into the
// mapped buffer if the GPU has write access to the image.
const bool copyExistingData = pResource->Desc()->Usage == D3D11_USAGE_STAGING;
if (copyExistingData) {
const VkImageSubresourceLayers subresourceLayers = {
subresource.aspectMask,
subresource.mipLevel,
subresource.arrayLayer, 1 };
EmitCs([
cImageBuffer = mappedBuffer,
cImage = mappedImage,
cSubresources = subresourceLayers,
cLevelExtent = levelExtent
] (DxvkContext* ctx) {
ctx->copyImageToBuffer(
cImageBuffer, 0, VkExtent2D { 0u, 0u },
cImage, cSubresources, VkOffset3D { 0, 0, 0 },
cLevelExtent);
});
}
if (!WaitForResource(mappedBuffer->resource(), MapFlags))
// Wait for the resource to become available
if (!WaitForResource(mappedImage, MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING;
physicalSlice = mappedBuffer->slice();
// Query the subresource's memory layout and hope that
// the application respects the returned pitch values.
VkSubresourceLayout layout = mappedImage->querySubresourceLayout(subresource);
pMappedResource->pData = mappedImage->mapPtr(layout.offset);
pMappedResource->RowPitch = imageType >= VK_IMAGE_TYPE_2D ? layout.rowPitch : layout.size;
pMappedResource->DepthPitch = imageType >= VK_IMAGE_TYPE_3D ? layout.depthPitch : layout.size;
return S_OK;
} else {
// Query format info which we need to compute
// the row pitch and layer pitch properly.
const DxvkFormatInfo* formatInfo = imageFormatInfo(mappedImage->info().format);
const VkExtent3D levelExtent = mappedImage->mipLevelExtent(subresource.mipLevel);
const VkExtent3D blockCount = util::computeBlockCount(
levelExtent, formatInfo->blockSize);
DxvkPhysicalBufferSlice physicalSlice;
if (MapType == D3D11_MAP_WRITE_DISCARD) {
// We do not have to preserve the contents of the
// buffer if the entire image gets discarded.
physicalSlice = mappedBuffer->allocPhysicalSlice();
physicalSlice.resource()->acquire();
EmitCs([
cImageBuffer = mappedBuffer,
cPhysicalSlice = physicalSlice
] (DxvkContext* ctx) {
ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice);
cPhysicalSlice.resource()->release();
});
} else {
// When using any map mode which requires the image contents
// to be preserved, and if the GPU has write access to the
// image, copy the current image contents into the buffer.
const bool copyExistingData = pResource->Desc()->Usage == D3D11_USAGE_STAGING;
if (copyExistingData) {
const VkImageSubresourceLayers subresourceLayers = {
subresource.aspectMask,
subresource.mipLevel,
subresource.arrayLayer, 1 };
EmitCs([
cImageBuffer = mappedBuffer,
cImage = mappedImage,
cSubresources = subresourceLayers,
cLevelExtent = levelExtent
] (DxvkContext* ctx) {
ctx->copyImageToBuffer(
cImageBuffer, 0, VkExtent2D { 0u, 0u },
cImage, cSubresources, VkOffset3D { 0, 0, 0 },
cLevelExtent);
});
}
if (!WaitForResource(mappedBuffer->resource(), MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING;
physicalSlice = mappedBuffer->slice();
}
// Set up map pointer. Data is tightly packed within the mapped buffer.
pMappedResource->pData = physicalSlice.mapPtr(0);
pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width;
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
return S_OK;
}
// Set up map pointer. Data is tightly packed within the mapped buffer.
pMappedResource->pData = physicalSlice.mapPtr(0);
pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width;
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
return S_OK;
}
@ -286,6 +305,8 @@ namespace dxvk {
cSrcBuffer, 0, { 0u, 0u });
});
}
pResource->ClearMappedSubresource();
}

View File

@ -203,7 +203,7 @@ namespace dxvk {
// 2. Since the image will most likely be read for rendering by the GPU,
// writing the image to device-local image may be more efficient than
// reading its contents from host-visible memory.
if ((m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ) == 0)
if (m_desc.Usage == D3D11_USAGE_DYNAMIC)
return D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
// Images that can be read by the host should be mapped directly in