mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[d3d11] Re-implemented image mapping
Image mapping now returns the map pointer of a separate buffer, rather than the the image itself. This fixes issues with applications that ignore the RowPitch and/or DepthPitch fields of the MappedSubresource struct.
This commit is contained in:
parent
93a5cf093c
commit
e7bf76f5ef
@ -208,7 +208,7 @@ namespace dxvk {
|
||||
|
||||
if (buffer->mapPtr(0) == nullptr) {
|
||||
Logger::err("D3D11: Cannot map a device-local buffer");
|
||||
return E_FAIL;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (pMappedResource == nullptr)
|
||||
@ -236,39 +236,61 @@ namespace dxvk {
|
||||
pMappedResource->DepthPitch = buffer->info().size;
|
||||
return S_OK;
|
||||
} else {
|
||||
const D3D11TextureInfo* textureInfo
|
||||
// Mapping an image is sadly not as simple as mapping a buffer
|
||||
// because applications tend to ignore row and layer strides.
|
||||
// We use a buffer instead and then perform a copy.
|
||||
D3D11TextureInfo* textureInfo
|
||||
= GetCommonTextureInfo(pResource);
|
||||
|
||||
if (textureInfo->image->mapPtr(0) == nullptr) {
|
||||
if (textureInfo->imageBuffer == nullptr) {
|
||||
Logger::err("D3D11DeviceContext: Cannot map a device-local image");
|
||||
return E_FAIL;
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
// FIXME copy current image contents into the
|
||||
// buffer unless D3D11_MAP_DISCARD is used.
|
||||
if (MapType == D3D11_MAP_READ || MapType == D3D11_MAP_READ_WRITE) {
|
||||
Logger::err("D3D11DeviceContext: Read-only and Read-Write mapping of images currently not supported");
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (pMappedResource == nullptr)
|
||||
return S_OK;
|
||||
return S_FALSE;
|
||||
|
||||
if (textureInfo->image->isInUse()) {
|
||||
if (textureInfo->imageBuffer->isInUse()) {
|
||||
// Don't wait if the application tells us not to
|
||||
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT)
|
||||
return DXGI_ERROR_WAS_STILL_DRAWING;
|
||||
|
||||
this->Flush();
|
||||
this->Synchronize();
|
||||
if (MapType == D3D11_MAP_WRITE_DISCARD) {
|
||||
m_context->invalidateBuffer(textureInfo->imageBuffer);
|
||||
} else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
|
||||
this->Flush();
|
||||
this->Synchronize();
|
||||
}
|
||||
}
|
||||
|
||||
const DxvkImageCreateInfo imageInfo = textureInfo->image->info();
|
||||
// Query format and subresource in order to compute
|
||||
// the row pitch and layer pitch properly.
|
||||
const DxvkImageCreateInfo& imageInfo = textureInfo->image->info();
|
||||
const DxvkFormatInfo* formatInfo = imageFormatInfo(imageInfo.format);
|
||||
|
||||
const VkImageSubresource imageSubresource =
|
||||
textureInfo->mappedSubresource =
|
||||
GetSubresourceFromIndex(VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
imageInfo.mipLevels, Subresource);
|
||||
|
||||
const VkSubresourceLayout layout =
|
||||
textureInfo->image->querySubresourceLayout(imageSubresource);
|
||||
const VkExtent3D levelExtent = textureInfo->image
|
||||
->mipLevelExtent(textureInfo->mappedSubresource.mipLevel);
|
||||
|
||||
// TODO handle undefined stuff
|
||||
pMappedResource->pData = textureInfo->image->mapPtr(layout.offset);
|
||||
pMappedResource->RowPitch = layout.rowPitch;
|
||||
pMappedResource->DepthPitch = layout.depthPitch;
|
||||
const VkExtent3D blockCount = {
|
||||
levelExtent.width / formatInfo->blockSize.width,
|
||||
levelExtent.height / formatInfo->blockSize.height,
|
||||
levelExtent.depth / formatInfo->blockSize.depth };
|
||||
|
||||
// Set up map pointer. Data is tightly packed within the mapped buffer.
|
||||
pMappedResource->pData = textureInfo->imageBuffer->mapPtr(0);
|
||||
pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width;
|
||||
pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
@ -277,7 +299,28 @@ namespace dxvk {
|
||||
void STDMETHODCALLTYPE D3D11DeviceContext::Unmap(
|
||||
ID3D11Resource* pResource,
|
||||
UINT Subresource) {
|
||||
// Nothing to do here, resources are persistently mapped
|
||||
D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
||||
pResource->GetType(&resourceDim);
|
||||
|
||||
if (resourceDim != D3D11_RESOURCE_DIMENSION_BUFFER) {
|
||||
// Now that data has been written into the buffer,
|
||||
// we need to copy its contents into the image
|
||||
const D3D11TextureInfo* textureInfo
|
||||
= GetCommonTextureInfo(pResource);
|
||||
|
||||
const VkExtent3D levelExtent = textureInfo->image
|
||||
->mipLevelExtent(textureInfo->mappedSubresource.mipLevel);
|
||||
|
||||
const VkImageSubresourceLayers subresourceLayers = {
|
||||
textureInfo->mappedSubresource.aspectMask,
|
||||
textureInfo->mappedSubresource.mipLevel,
|
||||
textureInfo->mappedSubresource.arrayLayer, 1 };
|
||||
|
||||
m_context->copyBufferToImage(
|
||||
textureInfo->image, subresourceLayers,
|
||||
VkOffset3D { 0, 0, 0 }, levelExtent,
|
||||
textureInfo->imageBuffer, 0, { 0u, 0u });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,6 +56,42 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Creates a buffer to map an image object
|
||||
*
|
||||
* When mapping an image, some applications make the incorrect
|
||||
* assumption that image data is tightly packed, which may lead
|
||||
* to corrupted textures in memory. To prevent this, we create
|
||||
* a tightly packed buffer and use it when mapping the image.
|
||||
*/
|
||||
Rc<DxvkBuffer> CreateImageBuffer(
|
||||
const Rc<DxvkDevice>& device,
|
||||
VkFormat format,
|
||||
VkExtent3D extent) {
|
||||
const DxvkFormatInfo* formatInfo = imageFormatInfo(format);
|
||||
|
||||
const VkExtent3D blockCount = {
|
||||
extent.width / formatInfo->blockSize.width,
|
||||
extent.height / formatInfo->blockSize.height,
|
||||
extent.depth / formatInfo->blockSize.depth };
|
||||
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = formatInfo->elementSize
|
||||
* blockCount.width
|
||||
* blockCount.height
|
||||
* blockCount.depth;
|
||||
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
return device->createBuffer(info,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Fills in image info stage and access flags
|
||||
*
|
||||
@ -101,7 +137,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
if (CPUAccessFlags != 0) {
|
||||
pImageInfo->tiling = VK_IMAGE_TILING_LINEAR;
|
||||
pImageInfo->stages |= VK_PIPELINE_STAGE_HOST_BIT;
|
||||
|
||||
if (CPUAccessFlags & D3D11_CPU_ACCESS_WRITE)
|
||||
@ -159,8 +194,10 @@ namespace dxvk {
|
||||
// Create the image and, if necessary, the image buffer
|
||||
m_texInfo.formatMode = formatMode;
|
||||
m_texInfo.image = pDevice->GetDXVKDevice()->createImage(
|
||||
info, GetMemoryFlagsForUsage(pDesc->Usage));
|
||||
m_texInfo.imageBuffer = D3D11ImageBuffer { nullptr, 0, 0 };
|
||||
info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_texInfo.imageBuffer = pDesc->CPUAccessFlags != 0
|
||||
? CreateImageBuffer(pDevice->GetDXVKDevice(), info.format, info.extent)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
@ -249,8 +286,10 @@ namespace dxvk {
|
||||
// Create the image and, if necessary, the image buffer
|
||||
m_texInfo.formatMode = formatMode;
|
||||
m_texInfo.image = pDevice->GetDXVKDevice()->createImage(
|
||||
info, GetMemoryFlagsForUsage(pDesc->Usage));
|
||||
m_texInfo.imageBuffer = D3D11ImageBuffer { nullptr, 0, 0 };
|
||||
info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_texInfo.imageBuffer = pDesc->CPUAccessFlags != 0
|
||||
? CreateImageBuffer(pDevice->GetDXVKDevice(), info.format, info.extent)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -336,8 +375,10 @@ namespace dxvk {
|
||||
// Create the image and, if necessary, the image buffer
|
||||
m_texInfo.formatMode = formatMode;
|
||||
m_texInfo.image = pDevice->GetDXVKDevice()->createImage(
|
||||
info, GetMemoryFlagsForUsage(pDesc->Usage));
|
||||
m_texInfo.imageBuffer = D3D11ImageBuffer { nullptr, 0, 0 };
|
||||
info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
m_texInfo.imageBuffer = pDesc->CPUAccessFlags != 0
|
||||
? CreateImageBuffer(pDevice->GetDXVKDevice(), info.format, info.extent)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -384,7 +425,7 @@ namespace dxvk {
|
||||
|
||||
|
||||
|
||||
const D3D11TextureInfo* GetCommonTextureInfo(ID3D11Resource* pResource) {
|
||||
D3D11TextureInfo* GetCommonTextureInfo(ID3D11Resource* pResource) {
|
||||
D3D11_RESOURCE_DIMENSION dimension = D3D11_RESOURCE_DIMENSION_UNKNOWN;
|
||||
pResource->GetType(&dimension);
|
||||
|
||||
|
@ -9,18 +9,6 @@ namespace dxvk {
|
||||
|
||||
class D3D11Device;
|
||||
|
||||
/**
|
||||
* \brief Image buffer info
|
||||
*
|
||||
* Stores the buffer used for mapping
|
||||
* an image and the row/layer strides.
|
||||
*/
|
||||
struct D3D11ImageBuffer {
|
||||
Rc<DxvkBuffer> buffer;
|
||||
VkDeviceSize bytesPerRow;
|
||||
VkDeviceSize bytesPerLayer;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Common texture info
|
||||
*
|
||||
@ -29,8 +17,11 @@ namespace dxvk {
|
||||
*/
|
||||
struct D3D11TextureInfo {
|
||||
DxgiFormatMode formatMode;
|
||||
D3D11ImageBuffer imageBuffer;
|
||||
Rc<DxvkBuffer> imageBuffer;
|
||||
Rc<DxvkImage> image;
|
||||
|
||||
VkImageSubresource mappedSubresource = {
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
|
||||
};
|
||||
|
||||
|
||||
@ -64,7 +55,7 @@ namespace dxvk {
|
||||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_TEXTURE1D_DESC *pDesc) final;
|
||||
|
||||
const D3D11TextureInfo* GetTextureInfo() const {
|
||||
D3D11TextureInfo* GetTextureInfo() {
|
||||
return &m_texInfo;
|
||||
}
|
||||
|
||||
@ -106,7 +97,7 @@ namespace dxvk {
|
||||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_TEXTURE2D_DESC *pDesc) final;
|
||||
|
||||
const D3D11TextureInfo* GetTextureInfo() const {
|
||||
D3D11TextureInfo* GetTextureInfo() {
|
||||
return &m_texInfo;
|
||||
}
|
||||
|
||||
@ -148,7 +139,7 @@ namespace dxvk {
|
||||
void STDMETHODCALLTYPE GetDesc(
|
||||
D3D11_TEXTURE3D_DESC *pDesc) final;
|
||||
|
||||
const D3D11TextureInfo* GetTextureInfo() const {
|
||||
D3D11TextureInfo* GetTextureInfo() {
|
||||
return &m_texInfo;
|
||||
}
|
||||
|
||||
@ -168,7 +159,7 @@ namespace dxvk {
|
||||
* \param [out] pTextureInfo Pointer to the texture info struct.
|
||||
* \returns E_INVALIDARG if the resource is not a texture
|
||||
*/
|
||||
const D3D11TextureInfo* GetCommonTextureInfo(
|
||||
D3D11TextureInfo* GetCommonTextureInfo(
|
||||
ID3D11Resource* pResource);
|
||||
|
||||
/**
|
||||
|
@ -217,6 +217,18 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::cmdCopyBufferToImage(
|
||||
VkBuffer srcBuffer,
|
||||
VkImage dstImage,
|
||||
VkImageLayout dstImageLayout,
|
||||
uint32_t regionCount,
|
||||
const VkBufferImageCopy* pRegions) {
|
||||
m_vkd->vkCmdCopyBufferToImage(m_buffer,
|
||||
srcBuffer, dstImage, dstImageLayout,
|
||||
regionCount, pRegions);
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::cmdCopyImage(
|
||||
VkImage srcImage,
|
||||
VkImageLayout srcImageLayout,
|
||||
|
@ -133,6 +133,13 @@ namespace dxvk {
|
||||
uint32_t regionCount,
|
||||
const VkBufferCopy* pRegions);
|
||||
|
||||
void cmdCopyBufferToImage(
|
||||
VkBuffer srcBuffer,
|
||||
VkImage dstImage,
|
||||
VkImageLayout dstImageLayout,
|
||||
uint32_t regionCount,
|
||||
const VkBufferImageCopy* pRegions);
|
||||
|
||||
void cmdCopyImage(
|
||||
VkImage srcImage,
|
||||
VkImageLayout srcImageLayout,
|
||||
|
@ -286,6 +286,63 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::copyBufferToImage(
|
||||
const Rc<DxvkImage>& dstImage,
|
||||
VkImageSubresourceLayers dstSubresource,
|
||||
VkOffset3D dstOffset,
|
||||
VkExtent3D dstExtent,
|
||||
const Rc<DxvkBuffer>& srcBuffer,
|
||||
VkDeviceSize srcOffset,
|
||||
VkExtent2D srcExtent) {
|
||||
this->renderPassEnd();
|
||||
|
||||
const VkImageSubresourceRange dstSubresourceRange = {
|
||||
dstSubresource.aspectMask,
|
||||
dstSubresource.mipLevel, 1,
|
||||
dstSubresource.baseArrayLayer,
|
||||
dstSubresource.layerCount };
|
||||
|
||||
m_barriers.accessImage(
|
||||
dstImage, dstSubresourceRange,
|
||||
dstImage->info().extent == dstExtent
|
||||
? VK_IMAGE_LAYOUT_UNDEFINED
|
||||
: dstImage->info().layout,
|
||||
dstImage->info().stages,
|
||||
dstImage->info().access,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
m_barriers.recordCommands(m_cmd);
|
||||
|
||||
VkBufferImageCopy copyRegion;
|
||||
copyRegion.bufferOffset = srcOffset;
|
||||
copyRegion.bufferRowLength = srcExtent.width;
|
||||
copyRegion.bufferImageHeight = srcExtent.height;
|
||||
copyRegion.imageSubresource = dstSubresource;
|
||||
copyRegion.imageOffset = dstOffset;
|
||||
copyRegion.imageExtent = dstExtent;
|
||||
|
||||
m_cmd->cmdCopyBufferToImage(
|
||||
srcBuffer->handle(),
|
||||
dstImage->handle(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1, ©Region);
|
||||
|
||||
m_barriers.accessImage(
|
||||
dstImage, dstSubresourceRange,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
dstImage->info().layout,
|
||||
dstImage->info().stages,
|
||||
dstImage->info().access);
|
||||
m_barriers.recordCommands(m_cmd);
|
||||
|
||||
m_cmd->trackResource(dstImage);
|
||||
m_cmd->trackResource(srcBuffer->resource());
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::copyImage(
|
||||
const Rc<DxvkImage>& dstImage,
|
||||
VkImageSubresourceLayers dstSubresource,
|
||||
@ -296,25 +353,23 @@ namespace dxvk {
|
||||
VkExtent3D extent) {
|
||||
this->renderPassEnd();
|
||||
|
||||
VkImageSubresourceRange dstSubresourceRange;
|
||||
dstSubresourceRange.aspectMask = dstSubresource.aspectMask;
|
||||
dstSubresourceRange.baseMipLevel = dstSubresource.mipLevel;
|
||||
dstSubresourceRange.levelCount = 1;
|
||||
dstSubresourceRange.baseArrayLayer = dstSubresource.baseArrayLayer;
|
||||
dstSubresourceRange.layerCount = dstSubresource.layerCount;
|
||||
const VkImageSubresourceRange dstSubresourceRange = {
|
||||
dstSubresource.aspectMask,
|
||||
dstSubresource.mipLevel, 1,
|
||||
dstSubresource.baseArrayLayer,
|
||||
dstSubresource.layerCount };
|
||||
|
||||
VkImageSubresourceRange srcSubresourceRange;
|
||||
srcSubresourceRange.aspectMask = srcSubresource.aspectMask;
|
||||
srcSubresourceRange.baseMipLevel = srcSubresource.mipLevel;
|
||||
srcSubresourceRange.levelCount = 1;
|
||||
srcSubresourceRange.baseArrayLayer = srcSubresource.baseArrayLayer;
|
||||
srcSubresourceRange.layerCount = srcSubresource.layerCount;
|
||||
const VkImageSubresourceRange srcSubresourceRange = {
|
||||
srcSubresource.aspectMask,
|
||||
srcSubresource.mipLevel, 1,
|
||||
srcSubresource.baseArrayLayer,
|
||||
srcSubresource.layerCount };
|
||||
|
||||
// TODO if the entire destination resource
|
||||
// gets overwritten, discard the contents.
|
||||
m_barriers.accessImage(
|
||||
dstImage, dstSubresourceRange,
|
||||
dstImage->info().layout,
|
||||
dstImage->info().extent == extent
|
||||
? VK_IMAGE_LAYOUT_UNDEFINED
|
||||
: dstImage->info().layout,
|
||||
dstImage->info().stages,
|
||||
dstImage->info().access,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
|
@ -185,6 +185,26 @@ namespace dxvk {
|
||||
VkDeviceSize srcOffset,
|
||||
VkDeviceSize numBytes);
|
||||
|
||||
/**
|
||||
* \brief Copies data from a buffer to an image
|
||||
*
|
||||
* \param [in] dstImage Destination image
|
||||
* \param [in] dstSubresource Destination subresource
|
||||
* \param [in] dstOffset Destination area offset
|
||||
* \param [in] dstExtent Destination area size
|
||||
* \param [in] srcBuffer Source buffer
|
||||
* \param [in] srcOffset Source offset, in bytes
|
||||
* \param [in] srcExtent Source data extent
|
||||
*/
|
||||
void copyBufferToImage(
|
||||
const Rc<DxvkImage>& dstImage,
|
||||
VkImageSubresourceLayers dstSubresource,
|
||||
VkOffset3D dstOffset,
|
||||
VkExtent3D dstExtent,
|
||||
const Rc<DxvkBuffer>& srcBuffer,
|
||||
VkDeviceSize srcOffset,
|
||||
VkExtent2D srcExtent);
|
||||
|
||||
/**
|
||||
* \brief Copies data from one image to another
|
||||
*
|
||||
@ -204,7 +224,7 @@ namespace dxvk {
|
||||
VkImageSubresourceLayers srcSubresource,
|
||||
VkOffset3D srcOffset,
|
||||
VkExtent3D extent);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Starts compute jobs
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user