mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +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 bufferResource = static_cast<D3D11Buffer*>(pDstResource);
|
||||||
const auto bufferSlice = bufferResource->GetBufferSlice();
|
const auto bufferSlice = bufferResource->GetBufferSlice();
|
||||||
|
|
||||||
VkDeviceSize offset = 0;
|
VkDeviceSize offset = bufferSlice.offset();
|
||||||
VkDeviceSize size = bufferSlice.length();
|
VkDeviceSize size = bufferSlice.length();
|
||||||
|
|
||||||
if (pDstBox != nullptr) {
|
if (pDstBox != nullptr) {
|
||||||
offset = pDstBox->left;
|
offset = pDstBox->left;
|
||||||
@ -565,13 +565,26 @@ namespace dxvk {
|
|||||||
|
|
||||||
if (((size == bufferSlice.length())
|
if (((size == bufferSlice.length())
|
||||||
&& (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
|
&& (bufferSlice.buffer()->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
|
||||||
m_context->invalidateBuffer(bufferSlice.buffer());
|
auto physicalSlice = bufferSlice.buffer()->allocPhysicalSlice();
|
||||||
std::memcpy(bufferSlice.mapPtr(0), pSrcData, size);
|
std::memcpy(physicalSlice.mapPtr(0), pSrcData, size);
|
||||||
|
|
||||||
|
EmitCs([
|
||||||
|
cDstBuffer = bufferSlice.buffer(),
|
||||||
|
cPhysicalSlice = std::move(physicalSlice)
|
||||||
|
] (DxvkContext* ctx) {
|
||||||
|
ctx->invalidateBuffer(cDstBuffer, cPhysicalSlice);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
m_context->updateBuffer(
|
EmitCs([
|
||||||
bufferSlice.buffer(),
|
cDataBuffer = Rc<DxvkDataBuffer>(new DxvkDataBuffer(pSrcData, size)),
|
||||||
bufferSlice.offset() + offset,
|
cBufferSlice = bufferSlice.subSlice(offset, size)
|
||||||
size, pSrcData);
|
] (DxvkContext* ctx) {
|
||||||
|
ctx->updateBuffer(
|
||||||
|
cBufferSlice.buffer(),
|
||||||
|
cBufferSlice.offset(),
|
||||||
|
cBufferSlice.length(),
|
||||||
|
cDataBuffer->data());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const D3D11TextureInfo* textureInfo
|
const D3D11TextureInfo* textureInfo
|
||||||
@ -604,10 +617,36 @@ namespace dxvk {
|
|||||||
subresource.mipLevel,
|
subresource.mipLevel,
|
||||||
subresource.arrayLayer, 1 };
|
subresource.arrayLayer, 1 };
|
||||||
|
|
||||||
m_context->updateImage(
|
auto formatInfo = imageFormatInfo(
|
||||||
textureInfo->image, layers,
|
textureInfo->image->info().format);
|
||||||
offset, extent, pSrcData,
|
|
||||||
|
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);
|
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)
|
if (pMappedResource == nullptr)
|
||||||
return S_OK;
|
return S_FALSE;
|
||||||
|
|
||||||
if (buffer->isInUse()) {
|
if (buffer->isInUse()) {
|
||||||
// Don't wait if the application tells us not to
|
// 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
|
// be preserved. The No Overwrite mode does not require any
|
||||||
// sort of synchronization, but should be used with care.
|
// sort of synchronization, but should be used with care.
|
||||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||||
m_context->invalidateBuffer(buffer);
|
m_context->invalidateBuffer(buffer, buffer->allocPhysicalSlice());
|
||||||
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||||
this->Flush();
|
this->Flush();
|
||||||
this->Synchronize();
|
this->Synchronize();
|
||||||
@ -142,30 +142,51 @@ namespace dxvk {
|
|||||||
levelExtent.depth / formatInfo->blockSize.depth };
|
levelExtent.depth / formatInfo->blockSize.depth };
|
||||||
|
|
||||||
// When using any map mode which requires the image contents
|
// 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) {
|
if (MapType != D3D11_MAP_WRITE_DISCARD) {
|
||||||
const VkImageSubresourceLayers subresourceLayers = {
|
const VkImageSubresourceLayers subresourceLayers = {
|
||||||
textureInfo->mappedSubresource.aspectMask,
|
textureInfo->mappedSubresource.aspectMask,
|
||||||
textureInfo->mappedSubresource.mipLevel,
|
textureInfo->mappedSubresource.mipLevel,
|
||||||
textureInfo->mappedSubresource.arrayLayer, 1 };
|
textureInfo->mappedSubresource.arrayLayer, 1 };
|
||||||
|
|
||||||
m_context->copyImageToBuffer(
|
EmitCs([
|
||||||
textureInfo->imageBuffer, 0, { 0u, 0u },
|
cImageBuffer = textureInfo->imageBuffer,
|
||||||
textureInfo->image, subresourceLayers,
|
cImage = textureInfo->image,
|
||||||
VkOffset3D { 0, 0, 0 }, levelExtent);
|
cSubresources = subresourceLayers,
|
||||||
|
cLevelExtent = levelExtent
|
||||||
|
] (DxvkContext* ctx) {
|
||||||
|
ctx->copyImageToBuffer(
|
||||||
|
cImageBuffer, 0, { 0u, 0u },
|
||||||
|
cImage, cSubresources,
|
||||||
|
VkOffset3D { 0, 0, 0 },
|
||||||
|
cLevelExtent);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textureInfo->imageBuffer->isInUse()) {
|
DxvkPhysicalBufferSlice physicalSlice;
|
||||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
|
||||||
m_context->invalidateBuffer(textureInfo->imageBuffer);
|
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||||
} else {
|
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->Flush();
|
||||||
this->Synchronize();
|
this->Synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
physicalSlice = textureInfo->imageBuffer->slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up map pointer. Data is tightly packed within the mapped buffer.
|
// 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->RowPitch = formatInfo->elementSize * blockCount.width;
|
||||||
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
|
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
@ -193,10 +214,16 @@ namespace dxvk {
|
|||||||
textureInfo->mappedSubresource.mipLevel,
|
textureInfo->mappedSubresource.mipLevel,
|
||||||
textureInfo->mappedSubresource.arrayLayer, 1 };
|
textureInfo->mappedSubresource.arrayLayer, 1 };
|
||||||
|
|
||||||
m_context->copyBufferToImage(
|
EmitCs([
|
||||||
textureInfo->image, subresourceLayers,
|
cSrcBuffer = textureInfo->imageBuffer,
|
||||||
VkOffset3D { 0, 0, 0 }, levelExtent,
|
cDstImage = textureInfo->image,
|
||||||
textureInfo->imageBuffer, 0, { 0u, 0u });
|
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();
|
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
|
* \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
|
// Allocate new backing resource
|
||||||
buffer->rename(buffer->allocPhysicalSlice());
|
buffer->rename(slice);
|
||||||
|
|
||||||
// We also need to update all bindings that the buffer
|
// We also need to update all bindings that the buffer
|
||||||
// may be bound to either directly or through views.
|
// may be bound to either directly or through views.
|
||||||
@ -884,53 +886,23 @@ namespace dxvk {
|
|||||||
const DxvkFormatInfo* formatInfo
|
const DxvkFormatInfo* formatInfo
|
||||||
= imageFormatInfo(image->info().format);
|
= imageFormatInfo(image->info().format);
|
||||||
|
|
||||||
VkExtent3D elementCount = imageExtent;
|
|
||||||
elementCount.depth *= subresources.layerCount;
|
|
||||||
|
|
||||||
// Align image extent to a full block. This is necessary in
|
// Align image extent to a full block. This is necessary in
|
||||||
// case the image size is not a multiple of the block size.
|
// case the image size is not a multiple of the block size.
|
||||||
elementCount.width += formatInfo->blockSize.width - 1;
|
VkExtent3D elementCount = util::computeBlockCount(
|
||||||
elementCount.height += formatInfo->blockSize.height - 1;
|
imageExtent, formatInfo->blockSize);
|
||||||
elementCount.depth += formatInfo->blockSize.depth - 1;
|
elementCount.depth *= subresources.layerCount;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Allocate staging buffer memory for the image data. The
|
// Allocate staging buffer memory for the image data. The
|
||||||
// pixels or blocks will be tightly packed within the buffer.
|
// 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 dstData = reinterpret_cast<char*>(slice.mapPtr);
|
||||||
auto srcData = reinterpret_cast<const char*>(data);
|
auto srcData = reinterpret_cast<const char*>(data);
|
||||||
|
|
||||||
// If the application provides tightly packed data as well,
|
util::packImageData(dstData, srcData,
|
||||||
// we can minimize the number of memcpy calls in order to
|
elementCount, formatInfo->elementSize,
|
||||||
// improve performance.
|
pitchPerRow, pitchPerLayer);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare the image layout. If the given extent covers
|
// Prepare the image layout. If the given extent covers
|
||||||
// the entire image, we may discard its previous contents.
|
// the entire image, we may discard its previous contents.
|
||||||
|
@ -352,7 +352,7 @@ namespace dxvk {
|
|||||||
/**
|
/**
|
||||||
* \brief Invalidates a buffer's contents
|
* \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
|
* backing resource. This allows the host to access
|
||||||
* the buffer while the GPU is still accessing the
|
* the buffer while the GPU is still accessing the
|
||||||
* original backing resource.
|
* original backing resource.
|
||||||
@ -360,9 +360,11 @@ namespace dxvk {
|
|||||||
* \warning If the buffer is used by another context,
|
* \warning If the buffer is used by another context,
|
||||||
* invalidating it will result in undefined behaviour.
|
* invalidating it will result in undefined behaviour.
|
||||||
* \param [in] buffer The buffer to invalidate
|
* \param [in] buffer The buffer to invalidate
|
||||||
|
* \param [in] slice New physical buffer slice
|
||||||
*/
|
*/
|
||||||
void invalidateBuffer(
|
void invalidateBuffer(
|
||||||
const Rc<DxvkBuffer>& buffer);
|
const Rc<DxvkBuffer>& buffer,
|
||||||
|
const DxvkPhysicalBufferSlice& slice);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Resolves a multisampled image resource
|
* \brief Resolves a multisampled image resource
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include "dxvk_util.h"
|
#include "dxvk_util.h"
|
||||||
|
|
||||||
namespace dxvk::util {
|
namespace dxvk::util {
|
||||||
@ -34,4 +36,36 @@ namespace dxvk::util {
|
|||||||
return mipCnt;
|
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);
|
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
|
* \brief Computes block count for compressed images
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user