mirror of https://github.com/RPCS3/rpcs3.git
d3d12: Factorise texture cache management.
This commit is contained in:
parent
cd71125277
commit
3d643fbc0b
|
@ -93,8 +93,7 @@ void D3D12GSRender::ResourceStorage::WaitAndClean()
|
|||
|
||||
Reset();
|
||||
|
||||
for (auto tmp : m_dirtyTextures)
|
||||
tmp->Release();
|
||||
m_dirtyTextures.clear();
|
||||
|
||||
m_RAMFramebuffer = nullptr;
|
||||
}
|
||||
|
@ -119,30 +118,11 @@ void D3D12GSRender::Shader::Release()
|
|||
|
||||
extern std::function<bool(u32 addr)> gfxHandler;
|
||||
|
||||
bool D3D12GSRender::invalidateTexture(u32 addr)
|
||||
bool D3D12GSRender::invalidateAddress(u32 addr)
|
||||
{
|
||||
bool handled = false;
|
||||
auto It = m_protectedTextures.begin(), E = m_protectedTextures.end();
|
||||
for (; It != E;)
|
||||
{
|
||||
auto currentIt = It;
|
||||
++It;
|
||||
auto protectedTexture = *currentIt;
|
||||
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
||||
if (addr - protectedRangeStart < protectedRangeSize)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
u32 texadrr = std::get<0>(protectedTexture);
|
||||
ID3D12Resource *texToErase = m_texturesCache[texadrr];
|
||||
m_texturesCache.erase(texadrr);
|
||||
m_texToClean.push_back(texToErase);
|
||||
|
||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||
m_protectedTextures.erase(currentIt);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
bool result = false;
|
||||
result |= m_textureCache.invalidateAddress(addr);
|
||||
return result;
|
||||
}
|
||||
|
||||
D3D12DLLManagement::D3D12DLLManagement()
|
||||
|
@ -159,7 +139,7 @@ D3D12GSRender::D3D12GSRender()
|
|||
: GSRender(), m_D3D12Lib(), m_PSO(nullptr)
|
||||
{
|
||||
gfxHandler = [this](u32 addr) {
|
||||
bool result = invalidateTexture(addr);
|
||||
bool result = invalidateAddress(addr);
|
||||
if (result)
|
||||
LOG_WARNING(RSX, "Reporting Cell writing to %x", addr);
|
||||
return result;
|
||||
|
@ -305,12 +285,7 @@ D3D12GSRender::~D3D12GSRender()
|
|||
CloseHandle(handle);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
for (auto &protectedTexture : m_protectedTextures)
|
||||
{
|
||||
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||
}
|
||||
m_textureCache.unprotedAll();
|
||||
}
|
||||
|
||||
gfxHandler = [this](u32) { return false; };
|
||||
|
@ -326,10 +301,6 @@ D3D12GSRender::~D3D12GSRender()
|
|||
m_perFrameStorage[0].Release();
|
||||
m_perFrameStorage[1].Release();
|
||||
m_rtts.Release();
|
||||
for (auto &tmp : m_texToClean)
|
||||
tmp->Release();
|
||||
for (auto &tmp : m_texturesCache)
|
||||
tmp.second->Release();
|
||||
m_outputScalingPass.Release();
|
||||
|
||||
ReleaseD2DStructures();
|
||||
|
@ -851,9 +822,8 @@ void D3D12GSRender::Flip()
|
|||
storage.m_frameFinishedFence->SetEventOnCompletion(storage.m_fenceValue, storage.m_frameFinishedHandle);
|
||||
storage.m_fenceValue++;
|
||||
|
||||
storage.m_dirtyTextures = m_texToClean;
|
||||
storage.m_dirtyTextures = m_textureCache.getCurrentDisposableTexture();
|
||||
storage.m_inUse = true;
|
||||
m_texToClean.clear();
|
||||
|
||||
// Get the put pos - 1. This way after cleaning we can set the get ptr to
|
||||
// this value, allowing heap to proceed even if we cleant before allocating
|
||||
|
@ -1072,7 +1042,7 @@ void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value)
|
|||
getCurrentResourceStorage().m_commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(writeDest.Get(), { 0, { DXGI_FORMAT_R8_UNORM, m_surface_clip_w, m_surface_clip_h, 1, (UINT)depthRowPitch } }), 0, 0, 0,
|
||||
&CD3DX12_TEXTURE_COPY_LOCATION(depthConverted.Get(), 0), nullptr);
|
||||
|
||||
invalidateTexture(GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000));
|
||||
invalidateAddress(GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000));
|
||||
}
|
||||
|
||||
ID3D12Resource *rtt0, *rtt1, *rtt2, *rtt3;
|
||||
|
@ -1110,10 +1080,10 @@ void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value)
|
|||
break;
|
||||
}
|
||||
|
||||
if (m_context_dma_color_a) invalidateTexture(GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000));
|
||||
if (m_context_dma_color_b) invalidateTexture(GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000));
|
||||
if (m_context_dma_color_c) invalidateTexture(GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000));
|
||||
if (m_context_dma_color_d) invalidateTexture(GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000));
|
||||
if (m_context_dma_color_a) invalidateAddress(GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000));
|
||||
if (m_context_dma_color_b) invalidateAddress(GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000));
|
||||
if (m_context_dma_color_c) invalidateAddress(GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000));
|
||||
if (m_context_dma_color_d) invalidateAddress(GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000));
|
||||
}
|
||||
if (needTransfer)
|
||||
{
|
||||
|
|
|
@ -190,6 +190,87 @@ struct DataHeap
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages cache of data (texture/vertex/index)
|
||||
*/
|
||||
struct DataCache
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Mutex protecting m_dataCache access
|
||||
* Memory protection fault catch can be generated by any thread and
|
||||
* modifies it.
|
||||
*/
|
||||
std::mutex mut;
|
||||
|
||||
std::unordered_map<u64, 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)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
m_dataCache[key] = data;
|
||||
/// align start to 4096 byte
|
||||
u32 protected_range_start = align(start, 4096);
|
||||
u32 protected_range_size = (u32)align(size, 4096);
|
||||
m_protectedRange.push_back(std::make_tuple(key, protected_range_start, protected_range_size));
|
||||
vm::page_protect(protected_range_start, protected_range_size, 0, 0, vm::page_writable);
|
||||
}
|
||||
|
||||
/// remove all data containing addr from cache, unprotect them. Returns false if no data is modified.
|
||||
bool invalidateAddress(u32 addr)
|
||||
{
|
||||
bool handled = false;
|
||||
auto It = m_protectedRange.begin(), E = m_protectedRange.end();
|
||||
for (; It != E;)
|
||||
{
|
||||
auto currentIt = It;
|
||||
++It;
|
||||
auto protectedTexture = *currentIt;
|
||||
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
||||
if (addr >= protectedRangeStart && addr <= protectedRangeSize + protectedRangeStart)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
u64 texadrr = std::get<0>(protectedTexture);
|
||||
m_dataToDispose.push_back(m_dataCache[texadrr]);
|
||||
m_dataCache.erase(texadrr);
|
||||
|
||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||
m_protectedRange.erase(currentIt);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
ID3D12Resource *findDataIfAvailable(u64 key)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
std::unordered_map<u64, ComPtr<ID3D12Resource> >::const_iterator It = m_dataCache.find(key);
|
||||
if (It == m_dataCache.end())
|
||||
return nullptr;
|
||||
return It->second.Get();
|
||||
}
|
||||
|
||||
void unprotedAll()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
for (auto &protectedTexture : m_protectedRange)
|
||||
{
|
||||
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<ComPtr<ID3D12Resource> > getCurrentDisposableTexture()
|
||||
{
|
||||
std::list<ComPtr<ID3D12Resource> > result;
|
||||
result.swap(m_dataToDispose);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure used to load/unload D3D12 lib.
|
||||
*/
|
||||
|
@ -213,22 +294,14 @@ private:
|
|||
ComPtr<ID3D12DescriptorHeap> m_backbufferAsRendertarget[2];
|
||||
// m_rootSignatures[N] is RS with N texture/sample
|
||||
ComPtr<ID3D12RootSignature> m_rootSignatures[17];
|
||||
/**
|
||||
* Mutex protecting m_texturesCache and m_Textoclean access
|
||||
* Memory protection fault catch can be generated by any thread and
|
||||
* modifies these two members.
|
||||
*/
|
||||
std::mutex mut;
|
||||
std::list <std::tuple<u32, u32, u32> > m_protectedTextures; // Texaddress, start of protected range, size of protected range
|
||||
std::vector<ID3D12Resource *> m_texToClean;
|
||||
bool invalidateTexture(u32 addr);
|
||||
|
||||
// TODO: Use a tree structure to parse more efficiently
|
||||
DataCache m_textureCache;
|
||||
bool invalidateAddress(u32 addr);
|
||||
|
||||
// Copy of RTT to be used as texture
|
||||
std::unordered_map<u32, ID3D12Resource* > m_texturesRTTs;
|
||||
|
||||
std::unordered_map<u32, ID3D12Resource*> m_texturesCache;
|
||||
// std::vector<PostDrawObj> m_post_draw_objs;
|
||||
|
||||
PipelineStateObjectCache m_cachePSO;
|
||||
std::pair<ID3D12PipelineState *, size_t> *m_PSO;
|
||||
|
||||
|
@ -311,7 +384,7 @@ private:
|
|||
|
||||
|
||||
/// Texture that were invalidated
|
||||
std::vector<ID3D12Resource *> m_dirtyTextures;
|
||||
std::list<ComPtr<ID3D12Resource> > m_dirtyTextures;
|
||||
|
||||
size_t m_getPosConstantsHeap;
|
||||
size_t m_getPosVertexIndexHeap;
|
||||
|
|
|
@ -126,13 +126,13 @@ D3D12_SAMPLER_DESC getSamplerDesc(const RSXTexture &texture)
|
|||
* using a temporary texture buffer.
|
||||
*/
|
||||
static
|
||||
ID3D12Resource *uploadSingleTexture(
|
||||
ComPtr<ID3D12Resource> uploadSingleTexture(
|
||||
const RSXTexture &texture,
|
||||
ID3D12Device *device,
|
||||
ID3D12GraphicsCommandList *commandList,
|
||||
DataHeap<ID3D12Resource, 65536> &textureBuffersHeap)
|
||||
{
|
||||
ID3D12Resource *vramTexture;
|
||||
ComPtr<ID3D12Resource> vramTexture;
|
||||
size_t w = texture.GetWidth(), h = texture.GetHeight();
|
||||
|
||||
int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||
|
@ -157,18 +157,18 @@ ID3D12Resource *uploadSingleTexture(
|
|||
&texturedesc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&vramTexture)
|
||||
IID_PPV_ARGS(vramTexture.GetAddressOf())
|
||||
));
|
||||
|
||||
size_t miplevel = 0;
|
||||
for (const MipmapLevelInfo mli : mipInfos)
|
||||
{
|
||||
commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(vramTexture, (UINT)miplevel), 0, 0, 0,
|
||||
commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(vramTexture.Get(), (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(vramTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vramTexture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
return vramTexture;
|
||||
}
|
||||
|
||||
|
@ -246,7 +246,6 @@ size_t getTextureSize(const RSXTexture &texture)
|
|||
|
||||
size_t D3D12GSRender::UploadTextures(ID3D12GraphicsCommandList *cmdlist)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mut);
|
||||
size_t usedTexture = 0;
|
||||
|
||||
for (u32 i = 0; i < m_textures_count; ++i)
|
||||
|
@ -263,26 +262,22 @@ size_t D3D12GSRender::UploadTextures(ID3D12GraphicsCommandList *cmdlist)
|
|||
|
||||
ID3D12Resource *vramTexture;
|
||||
std::unordered_map<u32, ID3D12Resource* >::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr);
|
||||
std::unordered_map<u32, ID3D12Resource* >::const_iterator ItCache = m_texturesCache.find(texaddr);
|
||||
ID3D12Resource *cachedTex = m_textureCache.findDataIfAvailable(texaddr);
|
||||
bool isRenderTarget = false;
|
||||
if (ItRTT != m_rtts.m_renderTargets.end())
|
||||
{
|
||||
vramTexture = ItRTT->second;
|
||||
isRenderTarget = true;
|
||||
}
|
||||
else if (ItCache != m_texturesCache.end())
|
||||
else if (cachedTex != nullptr)
|
||||
{
|
||||
vramTexture = ItCache->second;
|
||||
vramTexture = cachedTex;
|
||||
}
|
||||
else
|
||||
{
|
||||
vramTexture = uploadSingleTexture(m_textures[i], m_device.Get(), cmdlist, m_textureUploadData);
|
||||
m_texturesCache[texaddr] = vramTexture;
|
||||
|
||||
u32 s = (u32)align(getTextureSize(m_textures[i]), 4096);
|
||||
LOG_WARNING(RSX, "PROTECTING %x of size %d", align(texaddr, 4096), s);
|
||||
m_protectedTextures.push_back(std::make_tuple(texaddr, align(texaddr, 4096), s));
|
||||
vm::page_protect(align(texaddr, 4096), s, 0, 0, vm::page_writable);
|
||||
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);
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
|
|
Loading…
Reference in New Issue