diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index d5cab3593..b7ba95df9 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -254,29 +254,9 @@ namespace dxvk { 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_FALSE; - 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; - - if (MapType == D3D11_MAP_WRITE_DISCARD) { - m_context->invalidateBuffer(textureInfo->imageBuffer); - } else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) { - this->Flush(); - this->Synchronize(); - } - } - // Query format and subresource in order to compute // the row pitch and layer pitch properly. const DxvkImageCreateInfo& imageInfo = textureInfo->image->info(); @@ -294,6 +274,29 @@ namespace dxvk { levelExtent.height / formatInfo->blockSize.height, levelExtent.depth / formatInfo->blockSize.depth }; + // When using any map mode which requires the image contents + // to be preserved, copy image 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); + } + + if (textureInfo->imageBuffer->isInUse()) { + if (MapType == D3D11_MAP_WRITE_DISCARD) { + m_context->invalidateBuffer(textureInfo->imageBuffer); + } else { + this->Flush(); + this->Synchronize(); + } + } + // Set up map pointer. Data is tightly packed within the mapped buffer. pMappedResource->pData = textureInfo->imageBuffer->mapPtr(0); pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width; diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 7a940bae9..69b3f622b 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -213,6 +213,18 @@ namespace dxvk { } + void cmdCopyImageToBuffer( + VkImage srcImage, + VkImageLayout srcImageLayout, + VkBuffer dstBuffer, + uint32_t regionCount, + const VkBufferImageCopy* pRegions) { + m_vkd->vkCmdCopyImageToBuffer(m_buffer, + srcImage, srcImageLayout, dstBuffer, + regionCount, pRegions); + } + + void cmdDispatch( uint32_t x, uint32_t y, diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 0534408f2..496936ff8 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -354,6 +354,13 @@ namespace dxvk { dstImage->info().layout, dstImage->info().stages, dstImage->info().access); + + m_barriers.accessBuffer(srcSlice, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + srcBuffer->info().stages, + srcBuffer->info().access); + m_barriers.recordCommands(m_cmd); m_cmd->trackResource(dstImage); @@ -442,6 +449,70 @@ namespace dxvk { } + void DxvkContext::copyImageToBuffer( + const Rc& dstBuffer, + VkDeviceSize dstOffset, + VkExtent2D dstExtent, + const Rc& srcImage, + VkImageSubresourceLayers srcSubresource, + VkOffset3D srcOffset, + VkExtent3D srcExtent) { + this->renderPassEnd(); + + auto dstSlice = dstBuffer->subSlice(dstOffset, 0); + + const VkImageSubresourceRange srcSubresourceRange = { + srcSubresource.aspectMask, + srcSubresource.mipLevel, 1, + srcSubresource.baseArrayLayer, + srcSubresource.layerCount }; + + m_barriers.accessImage( + srcImage, srcSubresourceRange, + srcImage->info().layout, + srcImage->info().stages, + srcImage->info().access, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT); + m_barriers.recordCommands(m_cmd); + + VkBufferImageCopy copyRegion; + copyRegion.bufferOffset = dstSlice.offset(); + copyRegion.bufferRowLength = dstExtent.width; + copyRegion.bufferImageHeight = dstExtent.height; + copyRegion.imageSubresource = srcSubresource; + copyRegion.imageOffset = srcOffset; + copyRegion.imageExtent = srcExtent; + + m_cmd->cmdCopyImageToBuffer( + srcImage->handle(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstSlice.handle(), + 1, ©Region); + + m_barriers.accessImage( + srcImage, srcSubresourceRange, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_READ_BIT, + srcImage->info().layout, + srcImage->info().stages, + srcImage->info().access); + + m_barriers.accessBuffer(dstSlice, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_ACCESS_TRANSFER_WRITE_BIT, + dstBuffer->info().stages, + dstBuffer->info().access); + + m_barriers.recordCommands(m_cmd); + + m_cmd->trackResource(srcImage); + m_cmd->trackResource(dstSlice.resource()); + } + + void DxvkContext::dispatch( uint32_t x, uint32_t y, diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 000399a6f..bfcba61b6 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -224,7 +224,27 @@ namespace dxvk { VkImageSubresourceLayers srcSubresource, VkOffset3D srcOffset, VkExtent3D extent); - + + /** + * \brief Copies data from an image into a buffer + * + * \param [in] dstBuffer Destination buffer + * \param [in] dstOffset Destination offset, in bytes + * \param [in] dstExtent Destination data extent + * \param [in] srcImage Source image + * \param [in] srcSubresource Source subresource + * \param [in] srcOffset Source area offset + * \param [in] srcExtent Source area size + */ + void copyImageToBuffer( + const Rc& dstBuffer, + VkDeviceSize dstOffset, + VkExtent2D dstExtent, + const Rc& srcImage, + VkImageSubresourceLayers srcSubresource, + VkOffset3D srcOffset, + VkExtent3D srcExtent); + /** * \brief Starts compute jobs *