mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 14:31:24 +12:00
d3d12: Reuse texture resources
This commit is contained in:
parent
3d643fbc0b
commit
8d986e77d1
3 changed files with 94 additions and 17 deletions
|
@ -822,7 +822,6 @@ void D3D12GSRender::Flip()
|
|||
storage.m_frameFinishedFence->SetEventOnCompletion(storage.m_fenceValue, storage.m_frameFinishedHandle);
|
||||
storage.m_fenceValue++;
|
||||
|
||||
storage.m_dirtyTextures = m_textureCache.getCurrentDisposableTexture();
|
||||
storage.m_inUse = true;
|
||||
|
||||
// Get the put pos - 1. This way after cleaning we can set the get ptr to
|
||||
|
|
|
@ -190,6 +190,26 @@ struct DataHeap
|
|||
}
|
||||
};
|
||||
|
||||
struct TextureEntry
|
||||
{
|
||||
int m_format;
|
||||
size_t m_width;
|
||||
size_t m_height;
|
||||
size_t m_mipmap;
|
||||
bool m_isDirty;
|
||||
|
||||
TextureEntry() : m_format(0), m_width(0), m_height(0), m_isDirty(true)
|
||||
{}
|
||||
|
||||
TextureEntry(int f, size_t w, size_t h, size_t m) : m_format(f), m_width(w), m_height(h), m_isDirty(false)
|
||||
{}
|
||||
|
||||
bool operator==(const TextureEntry &other)
|
||||
{
|
||||
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages cache of data (texture/vertex/index)
|
||||
*/
|
||||
|
@ -203,14 +223,22 @@ private:
|
|||
*/
|
||||
std::mutex mut;
|
||||
|
||||
std::unordered_map<u64, ComPtr<ID3D12Resource> > m_dataCache; // Storage
|
||||
std::unordered_map<u64, std::pair<TextureEntry, ComPtr<ID3D12Resource>> > m_dataCache; // Storage
|
||||
std::list <std::tuple<u64, u32, u32> > m_protectedRange; // address, start of protected range, size of protected range
|
||||
std::list<ComPtr<ID3D12Resource> > m_dataToDispose;
|
||||
public:
|
||||
void storeAndProtectData(u64 key, u32 start, size_t size, ComPtr<ID3D12Resource> data)
|
||||
void storeAndProtectData(u64 key, u32 start, size_t size, int format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
m_dataCache[key] = data;
|
||||
m_dataCache[key] = std::make_pair(TextureEntry(format, w, h, m), data);
|
||||
protectData(key, start, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make memory from start to start + size write protected.
|
||||
* Associate key to this range so that when a write is detected, data at key is marked dirty.
|
||||
*/
|
||||
void protectData(u64 key, u32 start, size_t size)
|
||||
{
|
||||
/// align start to 4096 byte
|
||||
u32 protected_range_start = align(start, 4096);
|
||||
u32 protected_range_size = (u32)align(size, 4096);
|
||||
|
@ -233,8 +261,7 @@ public:
|
|||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
u64 texadrr = std::get<0>(protectedTexture);
|
||||
m_dataToDispose.push_back(m_dataCache[texadrr]);
|
||||
m_dataCache.erase(texadrr);
|
||||
m_dataCache[texadrr].first.m_isDirty = true;
|
||||
|
||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||
m_protectedRange.erase(currentIt);
|
||||
|
@ -244,13 +271,13 @@ public:
|
|||
return handled;
|
||||
}
|
||||
|
||||
ID3D12Resource *findDataIfAvailable(u64 key)
|
||||
std::pair<TextureEntry, ComPtr<ID3D12Resource> > *findDataIfAvailable(u64 key)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
std::unordered_map<u64, ComPtr<ID3D12Resource> >::const_iterator It = m_dataCache.find(key);
|
||||
auto It = m_dataCache.find(key);
|
||||
if (It == m_dataCache.end())
|
||||
return nullptr;
|
||||
return It->second.Get();
|
||||
return &It->second;
|
||||
}
|
||||
|
||||
void unprotedAll()
|
||||
|
@ -263,10 +290,14 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
std::list<ComPtr<ID3D12Resource> > getCurrentDisposableTexture()
|
||||
/**
|
||||
* Remove data stored at key, and returns a ComPtr owning it.
|
||||
* The caller is responsible for releasing the ComPtr.
|
||||
*/
|
||||
ComPtr<ID3D12Resource> removeFromCache(u64 key)
|
||||
{
|
||||
std::list<ComPtr<ID3D12Resource> > result;
|
||||
result.swap(m_dataToDispose);
|
||||
auto result = m_dataCache[key].second;
|
||||
m_dataCache.erase(key);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -172,6 +172,46 @@ ComPtr<ID3D12Resource> uploadSingleTexture(
|
|||
return vramTexture;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static
|
||||
void updateExistingTexture(
|
||||
const RSXTexture &texture,
|
||||
ID3D12GraphicsCommandList *commandList,
|
||||
DataHeap<ID3D12Resource, 65536> &textureBuffersHeap,
|
||||
ID3D12Resource *existingTexture)
|
||||
{
|
||||
size_t w = texture.GetWidth(), h = texture.GetHeight();
|
||||
|
||||
int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
DXGI_FORMAT dxgiFormat = getTextureDXGIFormat(format);
|
||||
|
||||
size_t textureSize = getPlacedTextureStorageSpace(texture, 256);
|
||||
assert(textureBuffersHeap.canAlloc(textureSize));
|
||||
size_t heapOffset = textureBuffersHeap.alloc(textureSize);
|
||||
|
||||
void *buffer;
|
||||
ThrowIfFailed(textureBuffersHeap.m_heap->Map(0, &CD3DX12_RANGE(heapOffset, heapOffset + textureSize), &buffer));
|
||||
void *textureData = (char*)buffer + heapOffset;
|
||||
std::vector<MipmapLevelInfo> mipInfos = uploadPlacedTexture(texture, 256, textureData);
|
||||
textureBuffersHeap.m_heap->Unmap(0, &CD3DX12_RANGE(heapOffset, heapOffset + textureSize));
|
||||
|
||||
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existingTexture, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST));
|
||||
size_t miplevel = 0;
|
||||
for (const MipmapLevelInfo mli : mipInfos)
|
||||
{
|
||||
commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existingTexture, (UINT)miplevel), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(textureBuffersHeap.m_heap, { heapOffset + mli.offset,{ dxgiFormat, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||
miplevel++;
|
||||
}
|
||||
|
||||
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existingTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get number of bytes occupied by texture in RSX mem
|
||||
*/
|
||||
|
@ -262,22 +302,29 @@ size_t D3D12GSRender::UploadTextures(ID3D12GraphicsCommandList *cmdlist)
|
|||
|
||||
ID3D12Resource *vramTexture;
|
||||
std::unordered_map<u32, ID3D12Resource* >::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr);
|
||||
ID3D12Resource *cachedTex = m_textureCache.findDataIfAvailable(texaddr);
|
||||
std::pair<TextureEntry, ComPtr<ID3D12Resource> > *cachedTex = m_textureCache.findDataIfAvailable(texaddr);
|
||||
bool isRenderTarget = false;
|
||||
if (ItRTT != m_rtts.m_renderTargets.end())
|
||||
{
|
||||
vramTexture = ItRTT->second;
|
||||
isRenderTarget = true;
|
||||
}
|
||||
else if (cachedTex != nullptr)
|
||||
else if (cachedTex != nullptr && (cachedTex->first == TextureEntry(format, w, h, m_textures[i].GetMipmap())))
|
||||
{
|
||||
vramTexture = cachedTex;
|
||||
if (cachedTex->first.m_isDirty)
|
||||
{
|
||||
updateExistingTexture(m_textures[i], cmdlist, m_textureUploadData, cachedTex->second.Get());
|
||||
m_textureCache.protectData(texaddr, texaddr, getTextureSize(m_textures[i]));
|
||||
}
|
||||
vramTexture = cachedTex->second.Get();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cachedTex != nullptr)
|
||||
getCurrentResourceStorage().m_dirtyTextures.push_back(m_textureCache.removeFromCache(texaddr));
|
||||
ComPtr<ID3D12Resource> tex = uploadSingleTexture(m_textures[i], m_device.Get(), cmdlist, m_textureUploadData);
|
||||
vramTexture = tex.Get();
|
||||
m_textureCache.storeAndProtectData(texaddr, texaddr, getTextureSize(m_textures[i]), tex);
|
||||
m_textureCache.storeAndProtectData(texaddr, texaddr, getTextureSize(m_textures[i]), format, w, h, m_textures[i].GetMipmap(), tex);
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue