1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-03-15 16:29:16 +01:00

[d3d9] Use memory mapped files for textures

This commit is contained in:
Robin Kertels 2022-03-16 02:28:22 +01:00 committed by Joshie
parent d598fd3156
commit 6ca6554452
5 changed files with 146 additions and 72 deletions

View File

@ -40,7 +40,8 @@ namespace dxvk {
m_shadow = DetermineShadowState();
m_supportsFetch4 = DetermineFetch4Compatibility();
if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED) {
const bool createImage = m_desc.Pool != D3DPOOL_SYSTEMMEM && m_desc.Pool != D3DPOOL_SCRATCH && m_desc.Format != D3D9Format::NULL_FORMAT;
if (createImage) {
bool plainSurface = m_type == D3DRTYPE_SURFACE &&
!(m_desc.Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL));
@ -73,7 +74,9 @@ namespace dxvk {
}
}
if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM)
if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE)
AllocData();
else if (m_mapMode != D3D9_COMMON_TEXTURE_MAP_MODE_NONE && m_desc.Pool != D3DPOOL_DEFAULT)
CreateBuffers();
m_exposedMipLevels = m_desc.MipLevels;
@ -165,11 +168,16 @@ namespace dxvk {
return D3D_OK;
}
void* D3D9CommonTexture::GetData(UINT Subresource) {
if (unlikely(m_mappedSlices[Subresource].mapPtr != nullptr || m_mapMode != D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE))
return m_mappedSlices[Subresource].mapPtr;
bool D3D9CommonTexture::CreateBufferSubresource(UINT Subresource) {
if (m_buffers[Subresource] != nullptr)
return false;
D3D9Memory& memory = m_data[Subresource];
memory.Map();
return memory.Ptr();
}
void D3D9CommonTexture::CreateBufferSubresource(UINT Subresource) {
DxvkBufferCreateInfo info;
info.size = GetMipSize(Subresource);
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
@ -190,8 +198,6 @@ namespace dxvk {
m_buffers[Subresource] = m_device->GetDXVKDevice()->createBuffer(info, memType);
m_mappedSlices[Subresource] = m_buffers[Subresource]->getSliceHandle();
return true;
}
@ -477,6 +483,20 @@ namespace dxvk {
return VK_IMAGE_LAYOUT_GENERAL;
}
D3D9_COMMON_TEXTURE_MAP_MODE D3D9CommonTexture::DetermineMapMode() const {
if (m_desc.Format == D3D9Format::NULL_FORMAT)
return D3D9_COMMON_TEXTURE_MAP_MODE_NONE;
#ifdef D3D9_ALLOW_UNMAPPING
if (m_desc.Pool != D3DPOOL_DEFAULT)
return D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE;
#endif
if (m_desc.Pool == D3DPOOL_SYSTEMMEM || m_desc.Pool == D3DPOOL_SCRATCH)
return D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM;
return D3D9_COMMON_TEXTURE_MAP_MODE_BACKED;
}
void D3D9CommonTexture::ExportImageInfo() {
/* From MSDN:
@ -606,5 +626,30 @@ namespace dxvk {
m_sampleView.Srgb = CreateView(AllLayers, Lod, VK_IMAGE_USAGE_SAMPLED_BIT, true);
}
void D3D9CommonTexture::AllocData() {
// D3D9Initializer will handle clearing the data
const uint32_t count = CountSubresources();
for (uint32_t i = 0; i < count; i++) {
m_data[i] = m_device->GetAllocator()->Alloc(GetMipSize(i));
}
}
const Rc<DxvkBuffer>& D3D9CommonTexture::GetBuffer(UINT Subresource, bool Initialize) {
if (unlikely(m_buffers[Subresource] == nullptr)) {
CreateBufferSubresource(Subresource);
if (Initialize) {
if (m_data[Subresource]) {
m_data[Subresource].Map();
memcpy(m_mappedSlices[Subresource].mapPtr, m_data[Subresource].Ptr(), GetMipSize(Subresource));
} else {
memset(m_mappedSlices[Subresource].mapPtr, 0, GetMipSize(Subresource));
}
}
m_data[Subresource] = {};
}
return m_buffers[Subresource];
}
}

View File

@ -3,6 +3,7 @@
#include "d3d9_format.h"
#include "d3d9_util.h"
#include "d3d9_caps.h"
#include "d3d9_mem.h"
#include "../dxvk/dxvk_device.h"
@ -22,6 +23,7 @@ namespace dxvk {
D3D9_COMMON_TEXTURE_MAP_MODE_NONE, ///< No mapping available
D3D9_COMMON_TEXTURE_MAP_MODE_BACKED, ///< Mapped image through buffer
D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM, ///< Only a buffer - no image
D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE, ///< Non-Vulkan memory that can be unmapped
};
/**
@ -141,9 +143,17 @@ namespace dxvk {
return m_resolveImage;
}
const Rc<DxvkBuffer>& GetBuffer(UINT Subresource) {
return m_buffers[Subresource];
}
/**
* \brief Returns a pointer to the internal data used for LockRect/LockBox
*
* This works regardless of the map mode used by this texture
* and will map the memory if necessary.
* \param [in] Subresource Subresource index
* @return Pointer to locking data
*/
void* GetData(UINT Subresource);
const Rc<DxvkBuffer>& GetBuffer(UINT Subresource, bool Initialize);
DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) {
@ -215,24 +225,16 @@ namespace dxvk {
return Face * m_desc.MipLevels + MipLevel;
}
/**
* \brief Creates buffers
* Creates mapping and staging buffers for all subresources
* allocates new buffers if necessary
*/
void CreateBuffers() {
const uint32_t count = CountSubresources();
for (uint32_t i = 0; i < count; i++)
CreateBufferSubresource(i);
void UnmapData(UINT Subresource) {
m_data[Subresource].Unmap();
}
/**
* \brief Creates a buffer
* Creates mapping and staging buffers for a given subresource
* allocates new buffers if necessary
* \returns Whether an allocation happened
*/
bool CreateBufferSubresource(UINT Subresource);
void UnmapData() {
const uint32_t subresources = CountSubresources();
for (uint32_t i = 0; i < subresources; i++) {
m_data[i].Unmap();
}
}
/**
* \brief Destroys a buffer
@ -456,6 +458,12 @@ namespace dxvk {
: 0ull;
}
/**
* \brief Mip level
* \returns Size of packed mip level in bytes
*/
VkDeviceSize GetMipSize(UINT Subresource) const;
private:
D3D9DeviceEx* m_device;
@ -468,7 +476,9 @@ namespace dxvk {
D3D9SubresourceArray<
Rc<DxvkBuffer>> m_buffers;
D3D9SubresourceArray<
DxvkBufferSliceHandle> m_mappedSlices;
DxvkBufferSliceHandle> m_mappedSlices = { };
D3D9SubresourceArray<
D3D9Memory> m_data = { };
D3D9SubresourceArray<
uint64_t> m_seqs = { };
@ -503,12 +513,6 @@ namespace dxvk {
std::array<D3DBOX, 6> m_dirtyBoxes;
/**
* \brief Mip level
* \returns Size of packed mip level in bytes
*/
VkDeviceSize GetMipSize(UINT Subresource) const;
Rc<DxvkImage> CreatePrimaryImage(D3DRESOURCETYPE ResourceType, bool TryOffscreenRT, HANDLE* pSharedHandle) const;
Rc<DxvkImage> CreateResolveImage() const;
@ -525,15 +529,7 @@ namespace dxvk {
VkFormat Format,
VkImageTiling Tiling) const;
D3D9_COMMON_TEXTURE_MAP_MODE DetermineMapMode() const {
if (m_desc.Format == D3D9Format::NULL_FORMAT)
return D3D9_COMMON_TEXTURE_MAP_MODE_NONE;
if (m_desc.Pool == D3DPOOL_SYSTEMMEM || m_desc.Pool == D3DPOOL_SCRATCH)
return D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM;
return D3D9_COMMON_TEXTURE_MAP_MODE_BACKED;
}
D3D9_COMMON_TEXTURE_MAP_MODE DetermineMapMode() const;
VkImageLayout OptimizeLayout(
VkImageUsageFlags Usage) const;
@ -544,6 +540,28 @@ namespace dxvk {
D3DRESOURCETYPE Dimension,
UINT Layer);
/**
* \brief Creates a buffer
* Creates mapping and staging buffers for a given subresource
* allocates new buffers if necessary
* \returns Whether an allocation happened
*/
void CreateBufferSubresource(UINT Subresource);
/**
* \brief Creates buffers
* Creates mapping and staging buffers for all subresources
* allocates new buffers if necessary
*/
void CreateBuffers() {
// D3D9Initializer will handle clearing the buffers
const uint32_t count = CountSubresources();
for (uint32_t i = 0; i < count; i++)
CreateBufferSubresource(i);
}
void AllocData();
static constexpr UINT AllLayers = UINT32_MAX;
};

View File

@ -876,7 +876,10 @@ namespace dxvk {
if (dstTexInfo->Desc()->Pool == D3DPOOL_DEFAULT)
return this->StretchRect(pRenderTarget, nullptr, pDestSurface, nullptr, D3DTEXF_NONE);
Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(src->GetMipLevel());
Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource(), dstTexExtent.width > srcTexExtent.width || dstTexExtent.height > srcTexExtent.height);
Rc<DxvkImage> srcImage = srcTexInfo->GetImage();
const DxvkFormatInfo* srcFormatInfo = lookupFormatInfo(srcImage->info().format);
@ -887,9 +890,8 @@ namespace dxvk {
srcSubresource.mipLevel,
srcSubresource.arrayLayer, 1 };
VkExtent3D srcExtent = srcTexInfo->GetExtentMip(src->GetMipLevel());
VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(srcExtent, srcFormatInfo->blockSize);
VkExtent3D texLevelExtentBlockCount = util::computeBlockCount(srcTexExtent, srcFormatInfo->blockSize);
VkDeviceSize pitch = align(texLevelExtentBlockCount.width * uint32_t(srcFormatInfo->elementSize), 4);
uint32_t pitchBlocks = uint32_t(pitch / srcFormatInfo->elementSize);
VkExtent2D dstExtent = VkExtent2D{ pitchBlocks,
@ -899,7 +901,7 @@ namespace dxvk {
cBuffer = dstBuffer,
cImage = srcImage,
cSubresources = srcSubresourceLayers,
cLevelExtent = srcExtent,
cLevelExtent = srcTexExtent,
cDstExtent = dstExtent
] (DxvkContext* ctx) {
ctx->copyImageToBuffer(cBuffer, 0, 4, 0,
@ -4128,10 +4130,6 @@ namespace dxvk {
auto& desc = *(pResource->Desc());
bool alloced = pResource->CreateBufferSubresource(Subresource);
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource);
auto& formatMapping = pResource->GetFormatMapping();
const DxvkFormatInfo* formatInfo = formatMapping.IsValid()
@ -4182,12 +4180,14 @@ namespace dxvk {
bool needsReadback = pResource->NeedsReachback(Subresource) || renderable;
pResource->SetNeedsReadback(Subresource, false);
DxvkBufferSliceHandle physSlice;
void* mapPtr;
if ((Flags & D3DLOCK_DISCARD) && needsReadback) {
// We do not have to preserve the contents of the
// buffer if the entire image gets discarded.
physSlice = pResource->DiscardMapSlice(Subresource);
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource, false);
DxvkBufferSliceHandle physSlice = pResource->DiscardMapSlice(Subresource);
mapPtr = physSlice.mapPtr;
EmitCs([
cImageBuffer = std::move(mappedBuffer),
@ -4196,10 +4196,15 @@ namespace dxvk {
ctx->invalidateBuffer(cImageBuffer, cBufferSlice);
});
} else {
physSlice = pResource->GetMappedSlice(Subresource);
if (unlikely(pResource->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED)) {
// Create mapping buffer if it doesn't exist yet. (POOL_DEFAULT)
pResource->GetBuffer(Subresource, !needsReadback);
}
mapPtr = pResource->GetData(Subresource);
if (needsReadback) {
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource);
const Rc<DxvkBuffer> mappedBuffer = pResource->GetBuffer(Subresource, false);
if (unlikely(needsReadback) && pResource->GetImage() != nullptr) {
Rc<DxvkImage> resourceImage = pResource->GetImage();
@ -4274,8 +4279,6 @@ namespace dxvk {
if (!WaitForResource(mappedBuffer, pResource->GetMappingBufferSequenceNumber(Subresource), Flags))
return D3DERR_WASSTILLDRAWING;
} else if (alloced) {
std::memset(physSlice.mapPtr, 0, physSlice.length);
}
}
@ -4332,8 +4335,7 @@ namespace dxvk {
(!atiHack) ? formatInfo : nullptr,
pBox);
uint8_t* data = reinterpret_cast<uint8_t*>(physSlice.mapPtr);
uint8_t* data = reinterpret_cast<uint8_t*>(mapPtr);
data += offset;
pLockedBox->pBits = data;
return D3D_OK;
@ -4419,7 +4421,6 @@ namespace dxvk {
// Now that data has been written into the buffer,
// we need to copy its contents into the image
const DxvkBufferSliceHandle srcSlice = pSrcTexture->GetMappedSlice(SrcSubresource);
auto formatInfo = lookupFormatInfo(image->info().format);
auto srcSubresource = pSrcTexture->GetSubresourceFromIndex(
@ -4462,9 +4463,10 @@ namespace dxvk {
+ srcOffsetBlockCount.y * pitch
+ srcOffsetBlockCount.x * formatInfo->elementSize;
const void* mapPtr = pSrcTexture->GetData(SrcSubresource);
VkDeviceSize dirtySize = extentBlockCount.width * extentBlockCount.height * extentBlockCount.depth * formatInfo->elementSize;
D3D9BufferSlice slice = AllocStagingBuffer(dirtySize);
const void* srcData = reinterpret_cast<const uint8_t*>(srcSlice.mapPtr) + copySrcOffset;
const void* srcData = reinterpret_cast<const uint8_t*>(mapPtr) + copySrcOffset;
util::packImageData(
slice.mapPtr, srcData, extentBlockCount, formatInfo->elementSize,
pitch, pitch * srcTexLevelExtentBlockCount.height);
@ -4487,6 +4489,7 @@ namespace dxvk {
}
else {
const DxvkFormatInfo* formatInfo = lookupFormatInfo(pDestTexture->GetFormatMapping().FormatColor);
const void* mapPtr = pSrcTexture->GetData(SrcSubresource);
// Add more blocks for the other planes that we might have.
// TODO: PLEASE CLEAN ME
@ -4504,11 +4507,11 @@ namespace dxvk {
}
// the converter can not handle the 4 aligned pitch so we always repack into a staging buffer
D3D9BufferSlice slice = AllocStagingBuffer(srcSlice.length);
D3D9BufferSlice slice = AllocStagingBuffer(pSrcTexture->GetMipSize(SrcSubresource));
VkDeviceSize pitch = align(srcTexLevelExtentBlockCount.width * formatInfo->elementSize, 4);
util::packImageData(
slice.mapPtr, srcSlice.mapPtr, srcTexLevelExtentBlockCount, formatInfo->elementSize,
slice.mapPtr, mapPtr, srcTexLevelExtentBlockCount, formatInfo->elementSize,
pitch, std::min(convertFormat.PlaneCount, 2u) * pitch * srcTexLevelExtentBlockCount.height);
Flush();
@ -5214,7 +5217,7 @@ namespace dxvk {
void D3D9DeviceEx::UploadManagedTexture(D3D9CommonTexture* pResource) {
for (uint32_t subresource = 0; subresource < pResource->CountSubresources(); subresource++) {
if (!pResource->NeedsUpload(subresource) || pResource->GetBuffer(subresource) == nullptr)
if (!pResource->NeedsUpload(subresource))
continue;
this->FlushImage(pResource, subresource);

View File

@ -44,9 +44,11 @@ namespace dxvk {
if (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_NONE)
return;
(pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED)
? InitDeviceLocalTexture(pTexture)
: InitHostVisibleTexture(pTexture, pInitialData);
if (pTexture->GetImage() != nullptr)
InitDeviceLocalTexture(pTexture);
if (pTexture->Desc()->Pool != D3DPOOL_DEFAULT)
InitHostVisibleTexture(pTexture, pInitialData);
}
@ -115,7 +117,8 @@ namespace dxvk {
for (uint32_t a = 0; a < desc->ArraySize; a++) {
for (uint32_t m = 0; m < desc->MipLevels; m++) {
uint32_t subresource = pTexture->CalcSubresource(a, m);
DxvkBufferSliceHandle mapSlice = pTexture->GetBuffer(subresource)->getSliceHandle();
void* mapPtr = pTexture->GetData(subresource);
uint32_t length = pTexture->GetMipSize(subresource);
if (pInitialData != nullptr) {
VkExtent3D mipExtent = pTexture->GetExtentMip(m);
@ -125,7 +128,7 @@ namespace dxvk {
uint32_t alignedPitch = align(pitch, 4);
util::packImageData(
mapSlice.mapPtr,
mapPtr,
pInitialData,
pitch,
pitch * blockCount.height,
@ -138,11 +141,13 @@ namespace dxvk {
VK_IMAGE_ASPECT_COLOR_BIT);
} else {
std::memset(
mapSlice.mapPtr, 0,
mapSlice.length);
mapPtr, 0,
length);
}
}
}
if (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_UNMAPPABLE)
pTexture->UnmapData();
}

View File

@ -341,7 +341,10 @@ namespace dxvk {
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
return D3DERR_INVALIDCALL;
Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(0);
Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource(), dstTexExtent.width > srcTexExtent.width || dstTexExtent.height > srcTexExtent.height);
Rc<DxvkImage> srcImage = srcTexInfo->GetImage();
if (srcImage->info().sampleCount != VK_SAMPLE_COUNT_1_BIT) {