diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index f1201608..dc6698ef 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -2,6 +2,7 @@ #include "d3d11_context.h" #include "d3d11_device.h" +#include "d3d11_texture.h" #include "../dxbc/dxbc_util.h" @@ -228,8 +229,44 @@ namespace dxvk { pMappedResource->DepthPitch = buffer->info().size; return S_OK; } else { - Logger::err("D3D11: Mapping of image resources currently not supported"); - return E_NOTIMPL; + D3D11TextureInfo textureInfo; + + if (FAILED(GetCommonTextureInfo(pResource, &textureInfo))) { + Logger::err("D3D11DeviceContext: Cannot map a device-local image"); + return E_FAIL; + } + + if (textureInfo.image->mapPtr(0) == nullptr) { + Logger::err("D3D11DeviceContext: Cannot map a device-local image"); + return E_FAIL; + } + + if (pMappedResource == nullptr) + return S_OK; + + if (textureInfo.image->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(); + } + + const DxvkImageCreateInfo imageInfo = textureInfo.image->info(); + + const VkImageSubresource imageSubresource = + GetSubresourceFromIndex(VK_IMAGE_ASPECT_COLOR_BIT, + imageInfo.mipLevels, Subresource); + + const VkSubresourceLayout layout = + textureInfo.image->querySubresourceLayout(imageSubresource); + + // TODO handle undefined stuff + pMappedResource->pData = textureInfo.image->mapPtr(layout.offset); + pMappedResource->RowPitch = layout.rowPitch; + pMappedResource->DepthPitch = layout.depthPitch; + return S_OK; } } @@ -446,7 +483,7 @@ namespace dxvk { } if (offset + size > bufferSlice.length()) { - Logger::err("D3D11: UpdateSubresource: Buffer size out of bounds"); + Logger::err("D3D11DeviceContext: Buffer update range out of bounds"); return; } @@ -457,9 +494,46 @@ namespace dxvk { size, pSrcData); } } else { - Logger::err("D3D11DeviceContext::UpdateSubresource: Images not yet supported"); + D3D11TextureInfo textureInfo; + + if (FAILED(GetCommonTextureInfo(pDstResource, &textureInfo))) { + Logger::err("D3D11DeviceContext: Failed to retrieve DXVK image"); + return; + } + + VkOffset3D offset = { 0, 0, 0 }; + VkExtent3D extent = textureInfo.image->info().extent; + + if (pDstBox != nullptr) { + if (pDstBox->left >= pDstBox->right + || pDstBox->top >= pDstBox->bottom + || pDstBox->front >= pDstBox->back) + return; // no-op, but legal + + offset.x = pDstBox->left; + offset.y = pDstBox->top; + offset.z = pDstBox->front; + + extent.width = pDstBox->right - pDstBox->left; + extent.height = pDstBox->bottom - pDstBox->top; + extent.depth = pDstBox->back - pDstBox->front; + } + + const VkImageSubresource imageSubresource = + GetSubresourceFromIndex(VK_IMAGE_ASPECT_COLOR_BIT, + textureInfo.image->info().mipLevels, DstSubresource); + + VkImageSubresourceLayers layers; + layers.aspectMask = imageSubresource.aspectMask; + layers.mipLevel = imageSubresource.mipLevel; + layers.baseArrayLayer = imageSubresource.arrayLayer; + layers.layerCount = 1; + + m_context->updateImage( + textureInfo.image, layers, + offset, extent, pSrcData, + SrcRowPitch, SrcDepthPitch); } - } diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index b6b6534e..49456fec 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -363,4 +363,16 @@ namespace dxvk { } } + + VkImageSubresource GetSubresourceFromIndex( + VkImageAspectFlags Aspect, + UINT MipLevels, + UINT Subresource) { + VkImageSubresource result; + result.aspectMask = Aspect; + result.mipLevel = Subresource % MipLevels; + result.arrayLayer = Subresource / MipLevels; + return result; + } + } diff --git a/src/d3d11/d3d11_texture.h b/src/d3d11/d3d11_texture.h index 377e40a3..bc0ab2eb 100644 --- a/src/d3d11/d3d11_texture.h +++ b/src/d3d11/d3d11_texture.h @@ -173,4 +173,9 @@ namespace dxvk { ID3D11Resource* pResource, D3D11TextureInfo* pTextureInfo); + VkImageSubresource GetSubresourceFromIndex( + VkImageAspectFlags Aspect, + UINT MipLevels, + UINT Subresource); + } diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 734d439d..d54d8bd7 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -48,8 +48,6 @@ namespace dxvk { /** * \brief Physical buffer resource - * - * */ class DxvkBufferResource : public DxvkResource { diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h index 84961dec..ab4b3a28 100644 --- a/src/dxvk/dxvk_image.h +++ b/src/dxvk/dxvk_image.h @@ -155,6 +155,36 @@ namespace dxvk { return size; } + /** + * \brief Queries memory layout of a subresource + * + * Can be used to retrieve the exact pointer to a + * subresource of a mapped image with linear tiling. + * \param [in] subresource The image subresource + * \returns Memory layout of that subresource + */ + VkSubresourceLayout querySubresourceLayout( + const VkImageSubresource& subresource) const { + VkSubresourceLayout result; + m_vkd->vkGetImageSubresourceLayout( + m_vkd->device(), m_image, + &subresource, &result); + return result; + } + + /** + * \brief Map pointer + * + * If the image has been created on a host-visible + * memory type, its memory is mapped and can be + * accessed by the host. + * \param [in] offset Byte offset into mapped region + * \returns Pointer to mapped memory region + */ + void* mapPtr(VkDeviceSize offset) const { + return m_memory.mapPtr(offset); + } + private: Rc m_vkd;