1
0
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:
Philip Rebohle 2018-01-20 21:42:11 +01:00
parent a84e45bdd2
commit f25b3c8b32
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 173 additions and 69 deletions

View File

@ -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);
});
}
}

View File

@ -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 });
});
}
}

View File

@ -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
*

View File

@ -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.

View File

@ -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

View File

@ -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;
}
}
}
}

View File

@ -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
*