From 3d643fbc0bbb80f17ed14cfcdfdba5f6d4fd5e83 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 19 Sep 2015 19:17:23 +0200 Subject: [PATCH 1/5] d3d12: Factorise texture cache management. --- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 56 ++++----------- rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 99 +++++++++++++++++++++++---- rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp | 27 +++----- 3 files changed, 110 insertions(+), 72 deletions(-) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index f8b10e4971..12d382e556 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -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 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 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 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) { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index f0a11c1d14..a515813b9b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -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 > m_dataCache; // Storage + std::list > m_protectedRange; // address, start of protected range, size of protected range + std::list > m_dataToDispose; +public: + void storeAndProtectData(u64 key, u32 start, size_t size, ComPtr data) + { + std::lock_guard 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 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 lock(mut); + std::unordered_map >::const_iterator It = m_dataCache.find(key); + if (It == m_dataCache.end()) + return nullptr; + return It->second.Get(); + } + + void unprotedAll() + { + std::lock_guard 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 > getCurrentDisposableTexture() + { + std::list > result; + result.swap(m_dataToDispose); + return result; + } +}; + /** * Structure used to load/unload D3D12 lib. */ @@ -213,22 +294,14 @@ private: ComPtr m_backbufferAsRendertarget[2]; // m_rootSignatures[N] is RS with N texture/sample ComPtr 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 > m_protectedTextures; // Texaddress, start of protected range, size of protected range - std::vector 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 m_texturesRTTs; - std::unordered_map m_texturesCache; - // std::vector m_post_draw_objs; - PipelineStateObjectCache m_cachePSO; std::pair *m_PSO; @@ -311,7 +384,7 @@ private: /// Texture that were invalidated - std::vector m_dirtyTextures; + std::list > m_dirtyTextures; size_t m_getPosConstantsHeap; size_t m_getPosVertexIndexHeap; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index 5c4f6e14c6..fc37b25557 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -126,13 +126,13 @@ D3D12_SAMPLER_DESC getSamplerDesc(const RSXTexture &texture) * using a temporary texture buffer. */ static -ID3D12Resource *uploadSingleTexture( +ComPtr uploadSingleTexture( const RSXTexture &texture, ID3D12Device *device, ID3D12GraphicsCommandList *commandList, DataHeap &textureBuffersHeap) { - ID3D12Resource *vramTexture; + ComPtr 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 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::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr); - std::unordered_map::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 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 = {}; From 8d986e77d168e9aa3f1ff2094fe13f28f230a778 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 30 Sep 2015 23:50:28 +0200 Subject: [PATCH 2/5] d3d12: Reuse texture resources --- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 1 - rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 55 +++++++++++++++++++++------ rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp | 55 +++++++++++++++++++++++++-- 3 files changed, 94 insertions(+), 17 deletions(-) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 12d382e556..a7ad6b7cee 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -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 diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index a515813b9b..76d2f0ffd3 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -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 > m_dataCache; // Storage + std::unordered_map> > m_dataCache; // Storage std::list > m_protectedRange; // address, start of protected range, size of protected range - std::list > m_dataToDispose; public: - void storeAndProtectData(u64 key, u32 start, size_t size, ComPtr data) + void storeAndProtectData(u64 key, u32 start, size_t size, int format, size_t w, size_t h, size_t m, ComPtr data) { std::lock_guard 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 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 > *findDataIfAvailable(u64 key) { std::lock_guard lock(mut); - std::unordered_map >::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 > getCurrentDisposableTexture() + /** + * Remove data stored at key, and returns a ComPtr owning it. + * The caller is responsible for releasing the ComPtr. + */ + ComPtr removeFromCache(u64 key) { - std::list > result; - result.swap(m_dataToDispose); + auto result = m_dataCache[key].second; + m_dataCache.erase(key); return result; } }; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index fc37b25557..6f71a2a41f 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -172,6 +172,46 @@ ComPtr uploadSingleTexture( return vramTexture; } + + +/** +* +*/ +static +void updateExistingTexture( + const RSXTexture &texture, + ID3D12GraphicsCommandList *commandList, + DataHeap &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 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::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr); - ID3D12Resource *cachedTex = m_textureCache.findDataIfAvailable(texaddr); + std::pair > *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 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 = {}; From a5ecbd0b2b92d831069eb916fb573782a434606c Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sun, 4 Oct 2015 00:14:30 +0200 Subject: [PATCH 3/5] d3d12: Do not regenerate RTTs if they didn't change between draw call. --- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 5 +++++ rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 7 +++++++ rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp | 14 ++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index a7ad6b7cee..0b838b6efa 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -138,6 +138,11 @@ D3D12DLLManagement::~D3D12DLLManagement() D3D12GSRender::D3D12GSRender() : GSRender(), m_D3D12Lib(), m_PSO(nullptr) { + m_previous_address_a = 0; + m_previous_address_b = 0; + m_previous_address_c = 0; + m_previous_address_d = 0; + m_previous_address_z = 0; gfxHandler = [this](u32 addr) { bool result = invalidateAddress(addr); if (result) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 76d2f0ffd3..889af8890c 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -463,6 +463,13 @@ private: ID3D12Resource *m_dummyTexture; size_t m_lastWidth, m_lastHeight, m_lastDepth; + + // Store previous fbo addresses to detect RTT config changes. + u32 m_previous_address_a; + u32 m_previous_address_b; + u32 m_previous_address_c; + u32 m_previous_address_d; + u32 m_previous_address_z; public: GSFrameBase2 *m_frame; u32 m_draw_frames; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index a50d8b6caa..f9f8dc3f6c 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -14,6 +14,20 @@ void D3D12GSRender::PrepareRenderTargets(ID3D12GraphicsCommandList *copycmdlist) { + // Exit early if there is no rtt changes + if ((m_previous_address_a == m_surface_offset_a) && + (m_previous_address_b == m_surface_offset_b) && + (m_previous_address_c == m_surface_offset_c) && + (m_previous_address_d == m_surface_offset_d) && + (m_previous_address_z == m_surface_offset_z)) + return; + + m_previous_address_a = m_surface_offset_a; + m_previous_address_b = m_surface_offset_b; + m_previous_address_c = m_surface_offset_c; + m_previous_address_d = m_surface_offset_d; + m_previous_address_z = m_surface_offset_z; + // FBO location has changed, previous data might be copied u32 address_a = m_set_context_dma_color_a ? GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000) : 0; u32 address_b = m_set_context_dma_color_b ? GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000) : 0; From 2f211e4e5a0a2b1ebcf5838c49c63ee95ea27e34 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sun, 4 Oct 2015 17:35:15 +0200 Subject: [PATCH 4/5] d3d12: Move adapter's description to settings. --- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 20 +++----------------- rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 1 - rpcs3/Gui/D3DGSFrame.cpp | 7 +------ rpcs3/Gui/D3DGSFrame.h | 2 -- rpcs3/Gui/SettingsDialog.cpp | 26 +++++++++++++++++++++----- 5 files changed, 25 insertions(+), 31 deletions(-) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 0b838b6efa..8b6bc6b54d 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -159,20 +159,9 @@ D3D12GSRender::D3D12GSRender() Microsoft::WRL::ComPtr dxgiFactory; ThrowIfFailed(CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory))); // Create adapter - IDXGIAdapter* adaptater = nullptr; - switch (Ini.GSD3DAdaptater.GetValue()) - { - case 0: // WARP - ThrowIfFailed(dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&adaptater))); - break; - case 1: // Default - dxgiFactory->EnumAdapters(0, &adaptater); - break; - default: // Adaptater 0, 1, ... - dxgiFactory->EnumAdapters(Ini.GSD3DAdaptater.GetValue() - 2,&adaptater); - break; - } - ThrowIfFailed(wrapD3D12CreateDevice(adaptater, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))); + ComPtr adaptater = nullptr; + ThrowIfFailed(dxgiFactory->EnumAdapters(Ini.GSD3DAdaptater.GetValue(), adaptater.GetAddressOf())); + ThrowIfFailed(wrapD3D12CreateDevice(adaptater.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))); // Queues D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}, graphicQueueDesc = {}; @@ -186,9 +175,6 @@ D3D12GSRender::D3D12GSRender() g_descriptorStrideSamplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); m_frame = GetGSFrame(); - DXGI_ADAPTER_DESC adaptaterDesc; - adaptater->GetDesc(&adaptaterDesc); - m_frame->SetAdaptaterName(adaptaterDesc.Description); // Create swap chain and put them in a descriptor heap as rendertarget DXGI_SWAP_CHAIN_DESC swapChain = {}; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 889af8890c..a571b2fadc 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -57,7 +57,6 @@ public: virtual void DeleteContext(void* ctx) = 0; virtual void Flip(void* ctx) = 0; virtual HWND getHandle() const = 0; - virtual void SetAdaptaterName(const wchar_t *) = 0; }; typedef GSFrameBase2*(*GetGSFrameCb2)(); diff --git a/rpcs3/Gui/D3DGSFrame.cpp b/rpcs3/Gui/D3DGSFrame.cpp index 808251f130..f4327da252 100644 --- a/rpcs3/Gui/D3DGSFrame.cpp +++ b/rpcs3/Gui/D3DGSFrame.cpp @@ -20,11 +20,6 @@ D3DGSFrame::~D3DGSFrame() { } -void D3DGSFrame::SetAdaptaterName(const wchar_t *name) -{ - AdaptaterName = name; -} - void D3DGSFrame::Close() { GSFrame::Close(); @@ -69,7 +64,7 @@ void D3DGSFrame::Flip(void* context) // canvas->SwapBuffers(); m_frames++; - const std::string sub_title = Emu.GetTitle() + (Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | ") + AdaptaterName.ToStdString() + " | "; + const std::string sub_title = Emu.GetTitle() + (Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | ") + " | "; if (fps_t.GetElapsedTimeInSec() >= 0.5) { diff --git a/rpcs3/Gui/D3DGSFrame.h b/rpcs3/Gui/D3DGSFrame.h index fecd729d22..47de197d0a 100644 --- a/rpcs3/Gui/D3DGSFrame.h +++ b/rpcs3/Gui/D3DGSFrame.h @@ -9,7 +9,6 @@ struct D3DGSFrame : public GSFrame, public GSFrameBase2 { wxWindow* canvas; u32 m_frames; - wxString AdaptaterName; D3DGSFrame(); ~D3DGSFrame(); @@ -29,7 +28,6 @@ struct D3DGSFrame : public GSFrame, public GSFrameBase2 virtual void SetViewport(int x, int y, u32 w, u32 h) override; virtual HWND getHandle() const override; - virtual void SetAdaptaterName(const wchar_t *) override; private: virtual void OnSize(wxSizeEvent& event); diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index b9a1fadf62..f9762d9698 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -7,6 +7,13 @@ #include "Utilities/Log.h" #include +#if defined(DX12_SUPPORT) +#undef GetHwnd +#include +#include +#include +#endif + SettingsDialog::SettingsDialog(wxWindow *parent) : wxDialog(parent, wxID_ANY, "Settings", wxDefaultPosition) { @@ -159,11 +166,20 @@ SettingsDialog::SettingsDialog(wxWindow *parent) cbox_gs_render->Append("DirectX 12"); #endif - cbox_gs_d3d_adaptater->Append("WARP"); - cbox_gs_d3d_adaptater->Append("Default"); - cbox_gs_d3d_adaptater->Append("Renderer 0"); - cbox_gs_d3d_adaptater->Append("Renderer 1"); - cbox_gs_d3d_adaptater->Append("Renderer 2"); +#if defined(DX12_SUPPORT) + unsigned id = 0; + Microsoft::WRL::ComPtr dxgiFactory; + CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory)); + Microsoft::WRL::ComPtr adapter; + + while (dxgiFactory->EnumAdapters(id, adapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND) + { + DXGI_ADAPTER_DESC adapterDesc; + adapter->GetDesc(&adapterDesc); + cbox_gs_d3d_adaptater->Append(adapterDesc.Description); + id++; + } +#endif #if !defined(DX12_SUPPORT) cbox_gs_d3d_adaptater->Enable(false); From d511153836ae2b17044edf8ea457aacbbc52d3f9 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Mon, 5 Oct 2015 01:54:19 +0200 Subject: [PATCH 5/5] Common: Fix element count computation if addr is null (RSXVertexData) --- rpcs3/Emu/RSX/Common/BufferUtils.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index 757add8e20..934b109264 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -20,11 +20,15 @@ std::vector FormatVertexData(const RSXVertexData *m_vertex_d const RSXVertexData &vertexData = m_vertex_data[i]; if (!vertexData.IsEnabled()) continue; - size_t elementCount = vertex_data_size[i] / (vertexData.size * vertexData.GetTypeSize()); + size_t elementCount = ((vertexData.addr) ? vertex_data_size[i] : m_vertex_data[i].data.size()) / (vertexData.size * vertexData.GetTypeSize()); + // If there is a single element, stride is 0, use the size of element instead size_t stride = vertexData.stride; size_t elementSize = vertexData.GetTypeSize(); - std::pair range = std::make_pair(vertexData.addr + base_offset, vertexData.addr + base_offset + elementSize * vertexData.size + (elementCount - 1) * stride - 1); + size_t start = vertexData.addr + base_offset; + size_t end = start + elementSize * vertexData.size + (elementCount - 1) * stride - 1; + std::pair range = std::make_pair(start, end); + assert(start < end); bool isMerged = false; for (VertexBufferFormat &vbf : Result)