diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp index 3a70c45df..cd073da01 100644 --- a/src/d3d11/d3d11_context_imm.cpp +++ b/src/d3d11/d3d11_context_imm.cpp @@ -100,126 +100,14 @@ namespace dxvk { pResource->GetType(&resourceDim); if (resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { - D3D11Buffer* resource = static_cast(pResource); - Rc buffer = resource->GetBufferSlice().buffer(); - - if (!(buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { - Logger::err("D3D11: Cannot map a device-local buffer"); - return E_INVALIDARG; - } - - if (pMappedResource == nullptr) - return S_FALSE; - - if (MapType == D3D11_MAP_WRITE_DISCARD) { - // Allocate a new backing slice for the buffer and set - // it as the 'new' mapped slice. This assumes that the - // only way to invalidate a buffer is by mapping it. - auto physicalSlice = buffer->allocPhysicalSlice(); - physicalSlice.resource()->acquire(); - - resource->GetBufferInfo()->mappedSlice = physicalSlice; - - EmitCs([ - cBuffer = buffer, - cPhysicalSlice = physicalSlice - ] (DxvkContext* ctx) { - ctx->invalidateBuffer(cBuffer, cPhysicalSlice); - cPhysicalSlice.resource()->release(); - }); - } else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) { - if (!WaitForResource(buffer->resource(), MapFlags)) - return DXGI_ERROR_WAS_STILL_DRAWING; - } - - // Use map pointer from previous map operation. This - // way we don't have to synchronize with the CS thread - // if the map mode is D3D11_MAP_WRITE_NO_OVERWRITE. - const DxvkPhysicalBufferSlice physicalSlice - = resource->GetBufferInfo()->mappedSlice; - - pMappedResource->pData = physicalSlice.mapPtr(0); - pMappedResource->RowPitch = physicalSlice.length(); - pMappedResource->DepthPitch = physicalSlice.length(); - return S_OK; + return MapBuffer( + static_cast(pResource), + MapType, MapFlags, pMappedResource); } else { - D3D11CommonTexture* textureInfo = GetCommonTexture(pResource); - - const Rc mappedImage = textureInfo->GetImage(); - const Rc mappedBuffer = textureInfo->GetMappedBuffer(); - - if (mappedBuffer == nullptr) { - Logger::err("D3D11: Cannot map a device-local image"); - return E_INVALIDARG; - } - - if (pMappedResource == nullptr) - return S_FALSE; - - VkImageSubresource subresource = - textureInfo->GetSubresourceFromIndex( - VK_IMAGE_ASPECT_COLOR_BIT, Subresource); - - textureInfo->SetMappedSubresource(subresource); - - // Query format info in order to compute - // the row pitch and layer pitch properly. - const DxvkFormatInfo* formatInfo = imageFormatInfo(mappedImage->info().format); - - const VkExtent3D levelExtent = mappedImage->mipLevelExtent(subresource.mipLevel); - const VkExtent3D blockCount = util::computeBlockCount( - levelExtent, formatInfo->blockSize); - - DxvkPhysicalBufferSlice physicalSlice; - - // When using any map mode which requires the image contents - // to be preserved, copy the image's contents into the buffer. - if (MapType == D3D11_MAP_WRITE_DISCARD) { - physicalSlice = mappedBuffer->allocPhysicalSlice(); - physicalSlice.resource()->acquire(); - - EmitCs([ - cImageBuffer = mappedBuffer, - cPhysicalSlice = physicalSlice - ] (DxvkContext* ctx) { - ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice); - cPhysicalSlice.resource()->release(); - }); - } else { - // We may have to copy the current image contents into the - // mapped buffer if the GPU has write access to the image. - const bool copyExistingData = textureInfo->Desc()->Usage == D3D11_USAGE_STAGING; - - if (copyExistingData) { - const VkImageSubresourceLayers subresourceLayers = { - subresource.aspectMask, - subresource.mipLevel, - subresource.arrayLayer, 1 }; - - EmitCs([ - cImageBuffer = mappedBuffer, - cImage = mappedImage, - cSubresources = subresourceLayers, - cLevelExtent = levelExtent - ] (DxvkContext* ctx) { - ctx->copyImageToBuffer( - cImageBuffer, 0, VkExtent2D { 0u, 0u }, - cImage, cSubresources, VkOffset3D { 0, 0, 0 }, - cLevelExtent); - }); - } - - if (!WaitForResource(mappedBuffer->resource(), MapFlags)) - return DXGI_ERROR_WAS_STILL_DRAWING; - - physicalSlice = mappedBuffer->slice(); - } - - // Set up map pointer. Data is tightly packed within the mapped buffer. - pMappedResource->pData = physicalSlice.mapPtr(0); - pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width; - pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height; - return S_OK; + return MapImage( + GetCommonTexture(pResource), + Subresource, MapType, MapFlags, + pMappedResource); } } @@ -230,15 +118,154 @@ namespace dxvk { D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; pResource->GetType(&resourceDim); - if (resourceDim != D3D11_RESOURCE_DIMENSION_BUFFER) { + if (resourceDim != D3D11_RESOURCE_DIMENSION_BUFFER) + UnmapImage(GetCommonTexture(pResource), Subresource); + } + + + HRESULT D3D11ImmediateContext::MapBuffer( + D3D11Buffer* pResource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + Rc buffer = pResource->GetBufferSlice().buffer(); + + if (!(buffer->memFlags() & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + Logger::err("D3D11: Cannot map a device-local buffer"); + return E_INVALIDARG; + } + + if (pMappedResource == nullptr) + return S_FALSE; + + if (MapType == D3D11_MAP_WRITE_DISCARD) { + // Allocate a new backing slice for the buffer and set + // it as the 'new' mapped slice. This assumes that the + // only way to invalidate a buffer is by mapping it. + auto physicalSlice = buffer->allocPhysicalSlice(); + physicalSlice.resource()->acquire(); + + pResource->GetBufferInfo()->mappedSlice = physicalSlice; + + EmitCs([ + cBuffer = buffer, + cPhysicalSlice = physicalSlice + ] (DxvkContext* ctx) { + ctx->invalidateBuffer(cBuffer, cPhysicalSlice); + cPhysicalSlice.resource()->release(); + }); + } else if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) { + if (!WaitForResource(buffer->resource(), MapFlags)) + return DXGI_ERROR_WAS_STILL_DRAWING; + } + + // Use map pointer from previous map operation. This + // way we don't have to synchronize with the CS thread + // if the map mode is D3D11_MAP_WRITE_NO_OVERWRITE. + const DxvkPhysicalBufferSlice physicalSlice + = pResource->GetBufferInfo()->mappedSlice; + + pMappedResource->pData = physicalSlice.mapPtr(0); + pMappedResource->RowPitch = physicalSlice.length(); + pMappedResource->DepthPitch = physicalSlice.length(); + return S_OK; + } + + + HRESULT D3D11ImmediateContext::MapImage( + D3D11CommonTexture* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource) { + const Rc mappedImage = pResource->GetImage(); + const Rc mappedBuffer = pResource->GetMappedBuffer(); + + if (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_NONE) { + Logger::err("D3D11: Cannot map a device-local image"); + return E_INVALIDARG; + } + + if (pMappedResource == nullptr) + return S_FALSE; + + VkImageSubresource subresource = + pResource->GetSubresourceFromIndex( + VK_IMAGE_ASPECT_COLOR_BIT, Subresource); + + pResource->SetMappedSubresource(subresource); + + // Query format info in order to compute + // the row pitch and layer pitch properly. + const DxvkFormatInfo* formatInfo = imageFormatInfo(mappedImage->info().format); + + const VkExtent3D levelExtent = mappedImage->mipLevelExtent(subresource.mipLevel); + const VkExtent3D blockCount = util::computeBlockCount( + levelExtent, formatInfo->blockSize); + + DxvkPhysicalBufferSlice physicalSlice; + + // When using any map mode which requires the image contents + // to be preserved, copy the image's contents into the buffer. + if (MapType == D3D11_MAP_WRITE_DISCARD) { + physicalSlice = mappedBuffer->allocPhysicalSlice(); + physicalSlice.resource()->acquire(); + + EmitCs([ + cImageBuffer = mappedBuffer, + cPhysicalSlice = physicalSlice + ] (DxvkContext* ctx) { + ctx->invalidateBuffer(cImageBuffer, cPhysicalSlice); + cPhysicalSlice.resource()->release(); + }); + } else { + // We may have to copy the current image contents into the + // mapped buffer if the GPU has write access to the image. + const bool copyExistingData = pResource->Desc()->Usage == D3D11_USAGE_STAGING; + + if (copyExistingData) { + const VkImageSubresourceLayers subresourceLayers = { + subresource.aspectMask, + subresource.mipLevel, + subresource.arrayLayer, 1 }; + + EmitCs([ + cImageBuffer = mappedBuffer, + cImage = mappedImage, + cSubresources = subresourceLayers, + cLevelExtent = levelExtent + ] (DxvkContext* ctx) { + ctx->copyImageToBuffer( + cImageBuffer, 0, VkExtent2D { 0u, 0u }, + cImage, cSubresources, VkOffset3D { 0, 0, 0 }, + cLevelExtent); + }); + } + + if (!WaitForResource(mappedBuffer->resource(), MapFlags)) + return DXGI_ERROR_WAS_STILL_DRAWING; + + physicalSlice = mappedBuffer->slice(); + } + + // Set up map pointer. Data is tightly packed within the mapped buffer. + pMappedResource->pData = physicalSlice.mapPtr(0); + pMappedResource->RowPitch = formatInfo->elementSize * blockCount.width; + pMappedResource->DepthPitch = formatInfo->elementSize * blockCount.width * blockCount.height; + return S_OK; + } + + + void D3D11ImmediateContext::UnmapImage( + D3D11CommonTexture* pResource, + UINT Subresource) { + if (pResource->GetMapMode() == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER) { // Now that data has been written into the buffer, // we need to copy its contents into the image - D3D11CommonTexture* textureInfo = GetCommonTexture(pResource); + const Rc mappedImage = pResource->GetImage(); + const Rc mappedBuffer = pResource->GetMappedBuffer(); - const Rc mappedImage = textureInfo->GetImage(); - const Rc mappedBuffer = textureInfo->GetMappedBuffer(); - - VkImageSubresource subresource = textureInfo->GetMappedSubresource(); + VkImageSubresource subresource = pResource->GetMappedSubresource(); VkExtent3D levelExtent = mappedImage ->mipLevelExtent(subresource.mipLevel); diff --git a/src/d3d11/d3d11_context_imm.h b/src/d3d11/d3d11_context_imm.h index f727ff974..d2f192f47 100644 --- a/src/d3d11/d3d11_context_imm.h +++ b/src/d3d11/d3d11_context_imm.h @@ -4,6 +4,9 @@ namespace dxvk { + class D3D11Buffer; + class D3D11CommonTexture; + class D3D11ImmediateContext : public D3D11DeviceContext { public: @@ -48,6 +51,23 @@ namespace dxvk { DxvkCsThread m_csThread; + HRESULT MapBuffer( + D3D11Buffer* pResource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource); + + HRESULT MapImage( + D3D11CommonTexture* pResource, + UINT Subresource, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedResource); + + void UnmapImage( + D3D11CommonTexture* pResource, + UINT Subresource); + void SynchronizeDevice(); bool WaitForResource( diff --git a/src/d3d11/d3d11_texture.cpp b/src/d3d11/d3d11_texture.cpp index cd0b2dbef..1096c6829 100644 --- a/src/d3d11/d3d11_texture.cpp +++ b/src/d3d11/d3d11_texture.cpp @@ -7,7 +7,7 @@ namespace dxvk { D3D11Device* pDevice, const D3D11_COMMON_TEXTURE_DESC* pDesc, D3D11_RESOURCE_DIMENSION Dimension) - : m_device(pDevice), m_desc(*pDesc) { + : m_device(pDevice), m_desc(*pDesc), m_mapMode(DetermineMapMode()) { DxgiFormatInfo formatInfo = m_device->LookupFormat(m_desc.Format, GetFormatMode()); DxvkImageCreateInfo imageInfo; @@ -56,8 +56,15 @@ namespace dxvk { | VK_ACCESS_SHADER_WRITE_BIT; } - if (m_desc.CPUAccessFlags != 0) { + if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) + imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + if (FAILED(GetSampleCount(m_desc.SampleDesc.Count, &imageInfo.sampleCount))) + throw DxvkError(str::format("D3D11: Invalid sample count: ", m_desc.SampleDesc.Count)); + + if (m_mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) { imageInfo.stages |= VK_PIPELINE_STAGE_HOST_BIT; + imageInfo.tiling = VK_IMAGE_TILING_LINEAR; if (m_desc.CPUAccessFlags & D3D11_CPU_ACCESS_WRITE) imageInfo.access |= VK_ACCESS_HOST_WRITE_BIT; @@ -66,15 +73,9 @@ namespace dxvk { imageInfo.access |= VK_ACCESS_HOST_READ_BIT; } - if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) - imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL) imageInfo.layout = OptimizeLayout(imageInfo.usage); - if (FAILED(GetSampleCount(m_desc.SampleDesc.Count, &imageInfo.sampleCount))) - throw DxvkError(str::format("D3D11: Invalid sample count: ", m_desc.SampleDesc.Count)); - m_image = m_device->GetDXVKDevice()->createImage( imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); @@ -127,6 +128,15 @@ namespace dxvk { } + D3D11_COMMON_TEXTURE_MAP_MODE D3D11CommonTexture::DetermineMapMode() const { + // TODO re-implement direct mapping. We'll have to check + // whether that is supported on a per-image basis though. + return m_desc.CPUAccessFlags == 0 + ? D3D11_COMMON_TEXTURE_MAP_MODE_NONE + : D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; + } + + Rc D3D11CommonTexture::CreateMappedBuffer() const { const DxvkFormatInfo* formatInfo = imageFormatInfo( m_device->LookupFormat(m_desc.Format, GetFormatMode()).format); diff --git a/src/d3d11/d3d11_texture.h b/src/d3d11/d3d11_texture.h index e8cc6d3c0..8dd7563b6 100644 --- a/src/d3d11/d3d11_texture.h +++ b/src/d3d11/d3d11_texture.h @@ -9,6 +9,19 @@ namespace dxvk { class D3D11Device; + /** + * \brief Image memory mapping mode + * + * Determines how exactly \c Map will + * behave when mapping an image. + */ + enum D3D11_COMMON_TEXTURE_MAP_MODE { + D3D11_COMMON_TEXTURE_MAP_MODE_NONE, ///< Not mapped + D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER, ///< Mapped through buffer + D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT, ///< Directly mapped to host mem + }; + + /** * \brief Common texture description * @@ -59,6 +72,14 @@ namespace dxvk { return &m_desc; } + /** + * \brief Map mode + * \returns Map mode + */ + D3D11_COMMON_TEXTURE_MAP_MODE GetMapMode() const { + return m_mapMode; + } + /** * \brief The DXVK image * \returns The DXVK image @@ -141,17 +162,20 @@ namespace dxvk { private: - Com m_device; - D3D11_COMMON_TEXTURE_DESC m_desc; + Com m_device; + D3D11_COMMON_TEXTURE_DESC m_desc; + D3D11_COMMON_TEXTURE_MAP_MODE m_mapMode; - Rc m_image; - Rc m_buffer; + Rc m_image; + Rc m_buffer; VkImageSubresource m_mappedSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 }; Rc CreateMappedBuffer() const; + D3D11_COMMON_TEXTURE_MAP_MODE DetermineMapMode() const; + static VkImageType GetImageTypeFromResourceDim( D3D11_RESOURCE_DIMENSION Dimension);