1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-21 04:54:15 +01:00

[dxvk] Fix misaligned image uploads on transfer queue

This commit is contained in:
Philip Rebohle 2024-10-16 11:22:50 +02:00 committed by Philip Rebohle
parent d2155c7f8c
commit f8b9efd11e
3 changed files with 50 additions and 28 deletions

View File

@ -155,8 +155,8 @@ namespace dxvk {
VkDeviceSize dataSize = 0u;
for (uint32_t mip = 0; mip < image->info().mipLevels; mip++) {
dataSize += image->info().numLayers * util::computeImageDataSize(
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
dataSize += image->info().numLayers * align(util::computeImageDataSize(
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask), CACHE_LINE_SIZE);
}
stagingSlice = m_stagingBuffer.alloc(dataSize);
@ -181,7 +181,7 @@ namespace dxvk {
pInitialData[index].pSysMem, pInitialData[index].SysMemPitch, pInitialData[index].SysMemSlicePitch,
0, 0, pTexture->GetVkImageType(), mipLevelExtent, 1, formatInfo, formatInfo->aspectMask);
dataOffset += mipSizePerLayer;
dataOffset += align(mipSizePerLayer, CACHE_LINE_SIZE);
}
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
@ -202,7 +202,7 @@ namespace dxvk {
ctx->uploadImage(cImage,
cStagingSlice.buffer(),
cStagingSlice.offset(),
cFormat);
CACHE_LINE_SIZE, cFormat);
});
}
} else {

View File

@ -2047,6 +2047,7 @@ namespace dxvk {
const Rc<DxvkImage>& image,
const Rc<DxvkBuffer>& source,
VkDeviceSize sourceOffset,
VkDeviceSize subresourceAlignment,
VkFormat format) {
// Always use framebuffer path for depth-stencil images since we know
// they are writeable and can't use Vulkan transfer queues. Stencil
@ -2054,9 +2055,9 @@ namespace dxvk {
bool useFb = !formatsAreCopyCompatible(image->info().format, format);
if (useFb)
uploadImageFb(image, source, sourceOffset, format);
uploadImageFb(image, source, sourceOffset, subresourceAlignment, format);
else
uploadImageHw(image, source, sourceOffset);
uploadImageHw(image, source, sourceOffset, subresourceAlignment);
}
@ -4316,20 +4317,30 @@ namespace dxvk {
const Rc<DxvkImage>& image,
const Rc<DxvkBuffer>& source,
VkDeviceSize sourceOffset,
VkDeviceSize subresourceAlignment,
VkFormat format) {
if (!format)
format = image->info().format;
for (uint32_t i = 0; i < image->info().mipLevels; i++) {
VkExtent3D mipExtent = image->mipLevelExtent(i);
for (uint32_t m = 0; m < image->info().mipLevels; m++) {
VkExtent3D mipExtent = image->mipLevelExtent(m);
copyBufferToImageFb(image,
vk::pickSubresourceLayers(image->getAvailableSubresources(), i),
VkOffset3D { 0, 0, 0 }, mipExtent,
source, sourceOffset, 0, 0, format);
sourceOffset += image->info().numLayers * util::computeImageDataSize(
VkDeviceSize mipSize = util::computeImageDataSize(
format, mipExtent, image->formatInfo()->aspectMask);
for (uint32_t l = 0; l < image->info().numLayers; l++) {
VkImageSubresourceLayers layers = { };
layers.aspectMask = image->formatInfo()->aspectMask;
layers.mipLevel = m;
layers.baseArrayLayer = l;
layers.layerCount = 1;
copyBufferToImageFb(image, layers,
VkOffset3D { 0, 0, 0 }, mipExtent,
source, sourceOffset, 0, 0, format);
sourceOffset += align(mipSize, subresourceAlignment);
}
}
}
@ -4337,7 +4348,8 @@ namespace dxvk {
void DxvkContext::uploadImageHw(
const Rc<DxvkImage>& image,
const Rc<DxvkBuffer>& source,
VkDeviceSize sourceOffset) {
VkDeviceSize sourceOffset,
VkDeviceSize subresourceAlignment) {
// Initialize all subresources of the image at once
VkImageLayout transferLayout = image->pickLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
@ -4348,18 +4360,25 @@ namespace dxvk {
// Copy image data, one mip at a time
VkDeviceSize dataOffset = sourceOffset;
for (uint32_t i = 0; i < image->info().mipLevels; i++) {
VkExtent3D mipExtent = image->mipLevelExtent(i);
for (uint32_t m = 0; m < image->info().mipLevels; m++) {
VkExtent3D mipExtent = image->mipLevelExtent(m);
VkDeviceSize mipSize = image->info().numLayers * util::computeImageDataSize(
VkDeviceSize mipSize = util::computeImageDataSize(
image->info().format, mipExtent, image->formatInfo()->aspectMask);
copyImageBufferData<true>(DxvkCmdBuffer::SdmaBuffer,
image, vk::pickSubresourceLayers(image->getAvailableSubresources(), i),
VkOffset3D { 0, 0, 0 }, mipExtent, transferLayout,
source->getSliceHandle(dataOffset, mipSize), 0, 0);
for (uint32_t l = 0; l < image->info().numLayers; l++) {
VkImageSubresourceLayers layers = { };
layers.aspectMask = image->formatInfo()->aspectMask;
layers.mipLevel = m;
layers.baseArrayLayer = l;
layers.layerCount = 1;
dataOffset += mipSize;
copyImageBufferData<true>(DxvkCmdBuffer::SdmaBuffer,
image, layers, VkOffset3D { 0, 0, 0 }, mipExtent, transferLayout,
source->getSliceHandle(dataOffset, mipSize), 0, 0);
dataOffset += align(mipSize, subresourceAlignment);
}
}
if (m_device->hasDedicatedTransferQueue()) {

View File

@ -1101,20 +1101,21 @@ namespace dxvk {
/**
* \brief Uses transfer queue to initialize image
*
* Only safe to use if the image is not in use by the GPU. Data is
* assumed to be tightly packed, with all layers of the top-level mip
* stored first, then the next mip etc. If the given format does not
* match the image format and is not \c VK_FORMAT_UNDEFINED, the data
* will be converted to the image format before performing the upload.
* Only safe to use if the image is not in use by the GPU.
* Data for each subresource is tightly packed, but individual
* subresources must be aligned to \c subresourceAlignment in
* order to meet Vulkan requirements when using transfer queues.
* \param [in] image The image to initialize
* \param [in] source Staging buffer containing data
* \param [in] sourceOffset Offset into staging buffer
* \param [in] subresourceAlignment Subresource alignment
* \param [in] format Actual data format
*/
void uploadImage(
const Rc<DxvkImage>& image,
const Rc<DxvkBuffer>& source,
VkDeviceSize sourceOffset,
VkDeviceSize subresourceAlignment,
VkFormat format);
/**
@ -1595,11 +1596,13 @@ namespace dxvk {
const Rc<DxvkImage>& image,
const Rc<DxvkBuffer>& source,
VkDeviceSize sourceOffset,
VkDeviceSize subresourceAlignment,
VkFormat format);
void uploadImageHw(
const Rc<DxvkImage>& image,
const Rc<DxvkBuffer>& source,
VkDeviceSize subresourceAlignment,
VkDeviceSize sourceOffset);
void performClear(