diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index fe42fc79ba..bb30cba3db 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -399,18 +399,29 @@ D3D12GSRender::D3D12GSRender() { gfxHandler = [this](u32 addr) { - LOG_ERROR(RSX, "CATCH SEGFAULT %x", addr); - for (auto tmp : texaddrs) + bool handled = false; + auto It = m_protectedTextures.begin(), E = m_protectedTextures.end(); + for (; It != E;) { - if (addr - tmp.first < tmp.second) + auto currentIt = It; + ++It; + auto protectedTexture = *currentIt; + u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture); + if (addr - protectedRangeStart < protectedRangeSize) { - LOG_ERROR(RSX, "Modified %x range, starting again", tmp.first); - vm::page_protect(tmp.first, tmp.second, 0, vm::page_writable, 0); - return true; + std::lock_guard lock(mut); + u32 texadrr = std::get<0>(protectedTexture); + LOG_WARNING(RSX, "Modified %x, starting again", texadrr); + 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 false; + return handled; }; loadD3D12FunctionPointers(); if (Ini.GSDebugOutputEnable.GetValue()) @@ -1041,7 +1052,6 @@ void D3D12GSRender::Flip() m_commandQueueGraphic->Signal(storage.m_frameFinishedFence, 1); // Flush - m_texturesCache.clear(); m_texturesRTTs.clear(); std::vector > cleaningFunction = @@ -1052,7 +1062,11 @@ void D3D12GSRender::Flip() m_textureData.getCleaningFunction() }; - m_GC.pushWork([&, cleaningFunction]() + std::lock_guard lock(mut); + std::vector textoclean = m_Textoclean; + m_Textoclean.clear(); + + m_GC.pushWork([&, cleaningFunction, textoclean]() { WaitForSingleObject(storage.m_frameFinishedHandle, INFINITE); CloseHandle(storage.m_frameFinishedHandle); @@ -1061,6 +1075,9 @@ void D3D12GSRender::Flip() for (unsigned i = 0; i < 4; i++) cleaningFunction[i](); storage.Reset(); + + for (auto tmp : textoclean) + tmp->Release(); }); while (getCurrentResourceStorage().m_frameFinishedHandle) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 2fa3efa42b..5eb4058930 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -202,7 +202,14 @@ struct GarbageCollectionThread class D3D12GSRender : public GSRender { private: - std::vector > texaddrs; // Address, size + /** + * 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; GarbageCollectionThread m_GC; // Copy of RTT to be used as texture std::unordered_map m_texturesRTTs; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index 3f51529d77..876f0faa86 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -337,8 +337,7 @@ ID3D12Resource *uploadSingleTexture( const RSXTexture &texture, ID3D12Device *device, ID3D12GraphicsCommandList *commandList, - DataHeap &textureBuffersHeap, - DataHeap &textureHeap) + DataHeap &textureBuffersHeap) { ID3D12Resource *vramTexture; size_t w = texture.GetWidth(), h = texture.GetHeight(); @@ -552,19 +551,17 @@ ID3D12Resource *uploadSingleTexture( D3D12_RESOURCE_DESC texturedesc = getTexture2DResourceDesc(w, h, dxgiFormat, texture.GetMipmap()); textureSize = device->GetResourceAllocationInfo(0, 1, &texturedesc).SizeInBytes; - assert(textureHeap.canAlloc(textureSize)); - size_t heapOffset2 = textureHeap.alloc(textureSize); + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; - check(device->CreatePlacedResource( - textureHeap.m_heap, - heapOffset2, + check(device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, &texturedesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&vramTexture) )); - textureHeap.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset2, textureSize, vramTexture)); - size_t miplevel = 0; for (const MipmapLevelInfo mli : mipInfos) @@ -597,6 +594,7 @@ ID3D12Resource *uploadSingleTexture( size_t D3D12GSRender::UploadTextures() { + std::lock_guard lock(mut); size_t usedTexture = 0; for (u32 i = 0; i < m_textures_count; ++i) @@ -630,17 +628,17 @@ size_t D3D12GSRender::UploadTextures() ID3D12GraphicsCommandList *commandList; check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_textureUploadCommandAllocator, nullptr, IID_PPV_ARGS(&commandList))); - vramTexture = uploadSingleTexture(m_textures[i], m_device, commandList, m_textureUploadData, m_textureData); + vramTexture = uploadSingleTexture(m_textures[i], m_device, commandList, m_textureUploadData); commandList->Close(); m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList); getCurrentResourceStorage().m_inflightCommandList.push_back(commandList); m_texturesCache[texaddr] = vramTexture; - size_t s = powerOf2Align(w * h * 4, 4096); - LOG_ERROR(RSX, "PROTECTING %x of size %d", powerOf2Align(texaddr, 4096), s); - texaddrs.push_back(std::make_pair(texaddr & ~0xfff, s)); - vm::page_protect(texaddr & ~0xfff, s, 0, 0, vm::page_writable); + u32 s = align(w * h * 4, 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); } D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};