mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-11-30 22:24:15 +01:00
[d3d11] Use EmitCs for resource updates
This commit is contained in:
parent
a84e45bdd2
commit
f25b3c8b32
@ -547,8 +547,8 @@ namespace dxvk {
|
||||
const auto bufferResource = static_cast<D3D11Buffer*>(pDstResource);
|
||||
const auto bufferSlice = bufferResource->GetBufferSlice();
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
VkDeviceSize size = bufferSlice.length();
|
||||
VkDeviceSize offset = bufferSlice.offset();
|
||||
VkDeviceSize size = bufferSlice.length();
|
||||
|
||||
if (pDstBox != nullptr) {
|
||||
offset = pDstBox->left;
|
||||
@ -565,13 +565,26 @@ namespace dxvk {
|
||||
|
||||
if (((size == bufferSlice.length())
|
||||
&& (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
|
||||
m_context->invalidateBuffer(bufferSlice.buffer());
|
||||
std::memcpy(bufferSlice.mapPtr(0), pSrcData, size);
|
||||
auto physicalSlice = bufferSlice.buffer()->allocPhysicalSlice();
|
||||
std::memcpy(physicalSlice.mapPtr(0), pSrcData, size);
|
||||
|
||||
EmitCs([
|
||||
cDstBuffer = bufferSlice.buffer(),
|
||||
cPhysicalSlice = std::move(physicalSlice)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cDstBuffer, cPhysicalSlice);
|
||||
});
|
||||
} else {
|
||||
m_context->updateBuffer(
|
||||
bufferSlice.buffer(),
|
||||
bufferSlice.offset() + offset,
|
||||
size, pSrcData);
|
||||
EmitCs([
|
||||
cDataBuffer = Rc<DxvkDataBuffer>(new DxvkDataBuffer(pSrcData, size)),
|
||||
cBufferSlice = bufferSlice.subSlice(offset, size)
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->updateBuffer(
|
||||
cBufferSlice.buffer(),
|
||||
cBufferSlice.offset(),
|
||||
cBufferSlice.length(),
|
||||
cDataBuffer->data());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const D3D11TextureInfo* textureInfo
|
||||
@ -604,10 +617,36 @@ namespace dxvk {
|
||||
subresource.mipLevel,
|
||||
subresource.arrayLayer, 1 };
|
||||
|
||||
m_context->updateImage(
|
||||
textureInfo->image, layers,
|
||||
offset, extent, pSrcData,
|
||||
auto formatInfo = imageFormatInfo(
|
||||
textureInfo->image->info().format);
|
||||
|
||||
const VkExtent3D regionExtent = util::computeBlockCount(extent, formatInfo->blockSize);
|
||||
|
||||
const VkDeviceSize bytesPerRow = regionExtent.width * formatInfo->elementSize;
|
||||
const VkDeviceSize bytesPerLayer = regionExtent.height * bytesPerRow;
|
||||
const VkDeviceSize bytesTotal = regionExtent.depth * bytesPerLayer;
|
||||
|
||||
Rc<DxvkDataBuffer> imageDataBuffer = new DxvkDataBuffer(bytesTotal);
|
||||
|
||||
util::packImageData(
|
||||
reinterpret_cast<char*>(imageDataBuffer->data()),
|
||||
reinterpret_cast<const char*>(pSrcData),
|
||||
regionExtent, formatInfo->elementSize,
|
||||
SrcRowPitch, SrcDepthPitch);
|
||||
|
||||
EmitCs([
|
||||
cDstImage = textureInfo->image,
|
||||
cDstLayers = layers,
|
||||
cDstOffset = offset,
|
||||
cDstExtent = extent,
|
||||
cSrcData = std::move(imageDataBuffer),
|
||||
cSrcBytesPerRow = bytesPerRow,
|
||||
cSrcBytesPerLayer = bytesPerLayer
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->updateImage(cDstImage, cDstLayers,
|
||||
cDstOffset, cDstExtent, cSrcData->data(),
|
||||
cSrcBytesPerRow, cSrcBytesPerLayer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
if (pMappedResource == nullptr)
|
||||
return S_OK;
|
||||
return S_FALSE;
|
||||
|
||||
if (buffer->isInUse()) {
|
||||
// Don't wait if the application tells us not to
|
||||
@ -98,7 +98,7 @@ namespace dxvk {
|
||||
// be preserved. The No Overwrite mode does not require any
|
||||
// sort of synchronization, but should be used with care.
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
m_context->invalidateBuffer(buffer);
|
||||
m_context->invalidateBuffer(buffer, buffer->allocPhysicalSlice());
|
||||
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
this->Flush();
|
||||
this->Synchronize();
|
||||
@ -142,30 +142,51 @@ namespace dxvk {
|
||||
levelExtent.depth / formatInfo->blockSize.depth };
|
||||
|
||||
// When using any map mode which requires the image contents
|
||||
// to be preserved, copy image contents into the buffer.
|
||||
// to be preserved, copy the image's contents into the buffer.
|
||||
if (MapType != D3D11_MAP_WRITE_DISCARD) {
|
||||
const VkImageSubresourceLayers subresourceLayers = {
|
||||
textureInfo->mappedSubresource.aspectMask,
|
||||
textureInfo->mappedSubresource.mipLevel,
|
||||
textureInfo->mappedSubresource.arrayLayer, 1 };
|
||||
|
||||
m_context->copyImageToBuffer(
|
||||
textureInfo->imageBuffer, 0, { 0u, 0u },
|
||||
textureInfo->image, subresourceLayers,
|
||||
VkOffset3D { 0, 0, 0 }, levelExtent);
|
||||
EmitCs([
|
||||
cImageBuffer = textureInfo->imageBuffer,
|
||||
cImage = textureInfo->image,
|
||||
cSubresources = subresourceLayers,
|
||||
cLevelExtent = levelExtent
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->copyImageToBuffer(
|
||||
cImageBuffer, 0, { 0u, 0u },
|
||||
cImage, cSubresources,
|
||||
VkOffset3D { 0, 0, 0 },
|
||||
cLevelExtent);
|
||||
});
|
||||
}
|
||||
|
||||
if (textureInfo->imageBuffer->isInUse()) {
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
m_context->invalidateBuffer(textureInfo->imageBuffer);
|
||||
} else {
|
||||
DxvkPhysicalBufferSlice physicalSlice;
|
||||
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
physicalSlice = textureInfo->imageBuffer->allocPhysicalSlice();
|
||||
|
||||
EmitCs([
|
||||
cImageBuffer = textureInfo->imageBuffer,
|
||||
cPhysicalSlice = physicalSlice
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice);
|
||||
});
|
||||
} else {
|
||||
// TODO sync with CS thread here
|
||||
|
||||
if (textureInfo->image->isInUse()) {
|
||||
this->Flush();
|
||||
this->Synchronize();
|
||||
}
|
||||
|
||||
physicalSlice = textureInfo->imageBuffer->slice();
|
||||
}
|
||||
|
||||
// Set up map pointer. Data is tightly packed within the mapped buffer.
|
||||
pMappedResource->pData = textureInfo->imageBuffer->mapPtr(0);
|
||||
pMappedResource->pData = physicalSlice.mapPtr(0);
|
||||
pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width;
|
||||
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
|
||||
return S_OK;
|
||||
@ -193,10 +214,16 @@ namespace dxvk {
|
||||
textureInfo->mappedSubresource.mipLevel,
|
||||
textureInfo->mappedSubresource.arrayLayer, 1 };
|
||||
|
||||
m_context->copyBufferToImage(
|
||||
textureInfo->image, subresourceLayers,
|
||||
VkOffset3D { 0, 0, 0 }, levelExtent,
|
||||
textureInfo->imageBuffer, 0, { 0u, 0u });
|
||||
EmitCs([
|
||||
cSrcBuffer = textureInfo->imageBuffer,
|
||||
cDstImage = textureInfo->image,
|
||||
cDstLayers = subresourceLayers,
|
||||
cDstLevelExtent = levelExtent
|
||||
] (DxvkContext* ctx) {
|
||||
ctx->copyBufferToImage(cDstImage, cDstLayers,
|
||||
VkOffset3D { 0, 0, 0 }, cDstLevelExtent,
|
||||
cSrcBuffer, 0, { 0u, 0u });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,6 +262,18 @@ namespace dxvk {
|
||||
return m_buffer->info();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Buffer sub slice
|
||||
*
|
||||
* Takes a sub slice from this slice.
|
||||
* \param [in] offset Sub slice offset
|
||||
* \param [in] length Sub slice length
|
||||
* \returns The sub slice object
|
||||
*/
|
||||
DxvkBufferSlice subSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
return DxvkBufferSlice(m_buffer, offset, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether the slice is valid
|
||||
*
|
||||
|
@ -729,9 +729,11 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::invalidateBuffer(const Rc<DxvkBuffer>& buffer) {
|
||||
void DxvkContext::invalidateBuffer(
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice) {
|
||||
// Allocate new backing resource
|
||||
buffer->rename(buffer->allocPhysicalSlice());
|
||||
buffer->rename(slice);
|
||||
|
||||
// We also need to update all bindings that the buffer
|
||||
// may be bound to either directly or through views.
|
||||
@ -884,53 +886,23 @@ namespace dxvk {
|
||||
const DxvkFormatInfo* formatInfo
|
||||
= imageFormatInfo(image->info().format);
|
||||
|
||||
VkExtent3D elementCount = imageExtent;
|
||||
elementCount.depth *= subresources.layerCount;
|
||||
|
||||
// Align image extent to a full block. This is necessary in
|
||||
// case the image size is not a multiple of the block size.
|
||||
elementCount.width += formatInfo->blockSize.width - 1;
|
||||
elementCount.height += formatInfo->blockSize.height - 1;
|
||||
elementCount.depth += formatInfo->blockSize.depth - 1;
|
||||
|
||||
elementCount.width /= formatInfo->blockSize.width;
|
||||
elementCount.height /= formatInfo->blockSize.height;
|
||||
elementCount.depth /= formatInfo->blockSize.depth;
|
||||
|
||||
VkDeviceSize bytesPerRow = elementCount.width * formatInfo->elementSize;
|
||||
VkDeviceSize bytesPerLayer = elementCount.height * bytesPerRow;
|
||||
VkDeviceSize bytesTotal = elementCount.depth * bytesPerLayer;
|
||||
VkExtent3D elementCount = util::computeBlockCount(
|
||||
imageExtent, formatInfo->blockSize);
|
||||
elementCount.depth *= subresources.layerCount;
|
||||
|
||||
// Allocate staging buffer memory for the image data. The
|
||||
// pixels or blocks will be tightly packed within the buffer.
|
||||
DxvkStagingBufferSlice slice = m_cmd->stagedAlloc(bytesTotal);
|
||||
const DxvkStagingBufferSlice slice = m_cmd->stagedAlloc(
|
||||
formatInfo->elementSize * util::flattenImageExtent(elementCount));
|
||||
|
||||
auto dstData = reinterpret_cast<char*>(slice.mapPtr);
|
||||
auto srcData = reinterpret_cast<const char*>(data);
|
||||
|
||||
// If the application provides tightly packed data as well,
|
||||
// we can minimize the number of memcpy calls in order to
|
||||
// improve performance.
|
||||
bool useDirectCopy = true;
|
||||
|
||||
useDirectCopy &= (pitchPerLayer == bytesPerLayer) || (elementCount.depth == 1);
|
||||
useDirectCopy &= (pitchPerRow == bytesPerRow) || (elementCount.height == 1);
|
||||
|
||||
if (useDirectCopy) {
|
||||
std::memcpy(dstData, srcData, bytesTotal);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < elementCount.depth; i++) {
|
||||
for (uint32_t j = 0; j < elementCount.height; j++) {
|
||||
std::memcpy(
|
||||
dstData + j * bytesPerRow,
|
||||
srcData + j * pitchPerRow,
|
||||
bytesPerRow);
|
||||
}
|
||||
|
||||
srcData += pitchPerLayer;
|
||||
dstData += bytesPerLayer;
|
||||
}
|
||||
}
|
||||
util::packImageData(dstData, srcData,
|
||||
elementCount, formatInfo->elementSize,
|
||||
pitchPerRow, pitchPerLayer);
|
||||
|
||||
// Prepare the image layout. If the given extent covers
|
||||
// the entire image, we may discard its previous contents.
|
||||
|
@ -352,7 +352,7 @@ namespace dxvk {
|
||||
/**
|
||||
* \brief Invalidates a buffer's contents
|
||||
*
|
||||
* Discards a buffer's contents by allocating a new
|
||||
* Discards a buffer's contents by replacing the
|
||||
* backing resource. This allows the host to access
|
||||
* the buffer while the GPU is still accessing the
|
||||
* original backing resource.
|
||||
@ -360,9 +360,11 @@ namespace dxvk {
|
||||
* \warning If the buffer is used by another context,
|
||||
* invalidating it will result in undefined behaviour.
|
||||
* \param [in] buffer The buffer to invalidate
|
||||
* \param [in] slice New physical buffer slice
|
||||
*/
|
||||
void invalidateBuffer(
|
||||
const Rc<DxvkBuffer>& buffer);
|
||||
const Rc<DxvkBuffer>& buffer,
|
||||
const DxvkPhysicalBufferSlice& slice);
|
||||
|
||||
/**
|
||||
* \brief Resolves a multisampled image resource
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "dxvk_util.h"
|
||||
|
||||
namespace dxvk::util {
|
||||
@ -34,4 +36,36 @@ namespace dxvk::util {
|
||||
return mipCnt;
|
||||
}
|
||||
|
||||
|
||||
void packImageData(
|
||||
char* dstData,
|
||||
const char* srcData,
|
||||
VkExtent3D blockCount,
|
||||
VkDeviceSize blockSize,
|
||||
VkDeviceSize pitchPerRow,
|
||||
VkDeviceSize pitchPerLayer) {
|
||||
const VkDeviceSize bytesPerRow = blockCount.width * blockSize;
|
||||
const VkDeviceSize bytesPerLayer = blockCount.height * bytesPerRow;
|
||||
const VkDeviceSize bytesTotal = blockCount.depth * bytesPerLayer;
|
||||
|
||||
const bool directCopy = (bytesPerRow == pitchPerRow ) || (blockCount.height == 1)
|
||||
&& (bytesPerLayer == pitchPerLayer) || (blockCount.depth == 1);
|
||||
|
||||
if (directCopy) {
|
||||
std::memcpy(dstData, srcData, bytesTotal);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < blockCount.depth; i++) {
|
||||
for (uint32_t j = 0; j < blockCount.height; j++) {
|
||||
std::memcpy(
|
||||
dstData + j * bytesPerRow,
|
||||
srcData + j * pitchPerRow,
|
||||
bytesPerRow);
|
||||
}
|
||||
|
||||
srcData += pitchPerLayer;
|
||||
dstData += bytesPerLayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,24 @@ namespace dxvk::util {
|
||||
*/
|
||||
uint32_t computeMipLevelCount(VkExtent3D imageSize);
|
||||
|
||||
/**
|
||||
* \brief Writes tightly packed image data to a buffer
|
||||
*
|
||||
* \param [in] dstData Destination buffer pointer
|
||||
* \param [in] srcData Pointer to source data
|
||||
* \param [in] blockCount Number of blocks to copy
|
||||
* \param [in] blockSize Number of bytes per block
|
||||
* \param [in] pitchPerRow Number of bytes between rows
|
||||
* \param [in] pitchPerLayer Number of bytes between layers
|
||||
*/
|
||||
void packImageData(
|
||||
char* dstData,
|
||||
const char* srcData,
|
||||
VkExtent3D blockCount,
|
||||
VkDeviceSize blockSize,
|
||||
VkDeviceSize pitchPerRow,
|
||||
VkDeviceSize pitchPerLayer);
|
||||
|
||||
/**
|
||||
* \brief Computes block count for compressed images
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user