1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-01 16:24:12 +01:00

[dxvk] Add copyBufferRegion and copyImageRegion methods

These new methods can support overlapped subresource copies by
creating a temporary resource and effectively using two copy
operations. This is required for D3D11 overlapped copies.
This commit is contained in:
Philip Rebohle 2018-09-18 16:20:57 +02:00
parent 3f47fdab4d
commit e3c2815782
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 147 additions and 0 deletions

View File

@ -567,6 +567,36 @@ namespace dxvk {
}
void DxvkContext::copyBufferRegion(
const Rc<DxvkBuffer>& dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize srcOffset,
VkDeviceSize numBytes) {
VkDeviceSize loOvl = std::max(dstOffset, srcOffset);
VkDeviceSize hiOvl = std::min(dstOffset, srcOffset) + numBytes;
if (hiOvl > loOvl) {
DxvkBufferCreateInfo bufInfo;
bufInfo.size = numBytes;
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
| VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
bufInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
bufInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
| VK_ACCESS_TRANSFER_READ_BIT;
auto tmpBuffer = m_device->createBuffer(
bufInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkDeviceSize tmpOffset = 0;
this->copyBuffer(tmpBuffer, tmpOffset, dstBuffer, srcOffset, numBytes);
this->copyBuffer(dstBuffer, dstOffset, tmpBuffer, tmpOffset, numBytes);
} else {
this->copyBuffer(dstBuffer, dstOffset, dstBuffer, srcOffset, numBytes);
}
}
void DxvkContext::copyBufferToImage(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
@ -783,6 +813,72 @@ namespace dxvk {
}
void DxvkContext::copyImageRegion(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
VkOffset3D srcOffset,
VkExtent3D extent) {
VkOffset3D loOvl = {
std::max(dstOffset.x, srcOffset.x),
std::max(dstOffset.y, srcOffset.y),
std::max(dstOffset.z, srcOffset.z) };
VkOffset3D hiOvl = {
std::min(dstOffset.x, srcOffset.x) + int32_t(extent.width),
std::min(dstOffset.y, srcOffset.y) + int32_t(extent.height),
std::min(dstOffset.z, srcOffset.z) + int32_t(extent.depth) };
bool overlap = hiOvl.x > loOvl.x
&& hiOvl.y > loOvl.y
&& hiOvl.z > loOvl.z;
if (overlap) {
DxvkImageCreateInfo imgInfo;
imgInfo.type = dstImage->info().type;
imgInfo.format = dstImage->info().format;
imgInfo.flags = 0;
imgInfo.sampleCount = dstImage->info().sampleCount;
imgInfo.extent = extent;
imgInfo.numLayers = dstSubresource.layerCount;
imgInfo.mipLevels = 1;
imgInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imgInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imgInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
| VK_ACCESS_TRANSFER_READ_BIT;
imgInfo.tiling = dstImage->info().tiling;
imgInfo.layout = VK_IMAGE_LAYOUT_GENERAL;
auto tmpImage = m_device->createImage(
imgInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkImageSubresourceLayers tmpSubresource;
tmpSubresource.aspectMask = dstSubresource.aspectMask;
tmpSubresource.mipLevel = 0;
tmpSubresource.baseArrayLayer = 0;
tmpSubresource.layerCount = dstSubresource.layerCount;
VkOffset3D tmpOffset = { 0, 0, 0 };
this->copyImage(
tmpImage, tmpSubresource, tmpOffset,
dstImage, dstSubresource, srcOffset,
extent);
this->copyImage(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset,
extent);
} else {
this->copyImage(
dstImage, dstSubresource, dstOffset,
dstImage, dstSubresource, srcOffset,
extent);
}
}
void DxvkContext::copyImageToBuffer(
const Rc<DxvkBuffer>& dstBuffer,
VkDeviceSize dstOffset,

View File

@ -263,6 +263,24 @@ namespace dxvk {
VkDeviceSize srcOffset,
VkDeviceSize numBytes);
/**
* \brief Copies overlapping buffer region
*
* Can be used to copy potentially overlapping
* buffer regions within the same buffer. If
* the source and destination regions do not
* overlap, it will behave as \ref copyBuffer.
* \param [in] dstBuffer The buffer
* \param [in] dstOffset Offset of target region
* \param [in] srcOffset Offset of source region
* \param [in] numBytes Number of bytes to copy
*/
void copyBufferRegion(
const Rc<DxvkBuffer>& dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize srcOffset,
VkDeviceSize numBytes);
/**
* \brief Copies data from a buffer to an image
*
@ -303,6 +321,22 @@ namespace dxvk {
VkOffset3D srcOffset,
VkExtent3D extent);
/**
* \brief Copies overlapping image region
*
* \param [in] dstImage The image
* \param [in] dstSubresource The image subresource
* \param [in] dstOffset Destination region offset
* \param [in] srcOffset Source region offset
* \param [in] extent Size of the copy region
*/
void copyImageRegion(
const Rc<DxvkImage>& dstImage,
VkImageSubresourceLayers dstSubresource,
VkOffset3D dstOffset,
VkOffset3D srcOffset,
VkExtent3D extent);
/**
* \brief Copies data from an image into a buffer
*

View File

@ -233,6 +233,23 @@ inline bool operator != (
}
inline bool operator == (
const VkImageSubresourceLayers& a,
const VkImageSubresourceLayers& b) {
return a.aspectMask == b.aspectMask
&& a.mipLevel == b.mipLevel
&& a.baseArrayLayer == b.baseArrayLayer
&& a.layerCount == b.layerCount;
}
inline bool operator != (
const VkImageSubresourceLayers& a,
const VkImageSubresourceLayers& b) {
return !operator == (a, b);
}
inline bool operator == (VkExtent3D a, VkExtent3D b) {
return a.width == b.width
&& a.height == b.height