Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Texture Cache cleanup/refactoring & fixes #5115

Merged
merged 5 commits into from
Sep 24, 2018
Merged

Conversation

ruipin
Copy link
Contributor

@ruipin ruipin commented Sep 11, 2018

This PR is the result of over 7 weeks of significant effort to debug, cleanup and optimize the RSX Texture Cache.

(Note that the texture cache is mostly a "backend" part of the emulator, so don't expect these changes to have a large impact on the number of bugs)

There are a significant amount of changes, which means this PR is high-risk. I have tried to verify this as best as possible (having introduced the AUDIT macro for this exact purpose), however I am a single person and cannot test every single game. Things will break and performance could suffer.

Although in my tests this PR shows a small performance improvement depending on the game, this might just be a coincidence. Please report any significant peformance differences (both improvements and losses), as well as any regressions you find.

As a final note, I'd like to thank @kd-11 for his invaluable help in the last couple of months.


Now for the (long) changelist:

General changes:

  • Adds a try/catch around the RSX violation handler so that crashes/verify failures inside it do not silently crash RPCS3
  • Adds the ASSERT and AUDIT macros as wrappers around verify. AUDIT can be enabled selectively by defining _DEBUG or _AUDIT before including types.h.
  • Changes ASSUME in clang to use __builtin_assume because it ignores side-effects
    Justification:

RSX/Texture Cache changes:

  • (debug) Add a significant number of AUDIT assertions, as well as texture cache sanity checks gated behind TEXTURE_CACHE_DEBUG
  • (cleanup) Refactor all uses of std::pair<u32,u32> for address ranges into a dedicated utils::address_range struct
  • (optimization) Restructure get_intersecting_set and unprotect_set to avoid chaining into neighboring or unsynchronized sections unless necessary. Re-enable full-range protection by default even without SRM.
  • (optimization) Batch memory_protect calls when invalidating sections
  • (cleanup) Refactor uses of std::vector<section_storage_type*> in the invalidation algorithm into a dedicated address_range_vector struct
  • (optimization) Support exclusion of RO sections. If a NA section gets unprotected, and a RO section overlaps it (but is not in the set of textures to unprotect), the section will now be reprotected RO
  • (bugfix) Implement automatic ranged_storage reference counting through callbacks, getting rid of the very common texture_cache.h:301 verification failures forever
  • (bugfix) Reset all cached section members when reset() is called and a section is going to be reused for something else
  • (bugfix) Implement automatic m_flush_always_cache tracking through callbacks to avoid forgetting to remove sections (e.g. when they get reset/replaced)
  • (cleanup) Refactor ranged storage from std::unordered_map into a dedicated class ranged_storage
  • (optimization) Pre-allocate all ranged storage blocks at startup to have O(1) access and avoid expensive (de-)allocations during runtime. These structs are small anyway.
  • (optimization) Maintain a list of unowned overlapping sections inside each ranged storage block to make iterating through all sections in a specified range cheaper (no longer necessary to iterate through all section blocks)
  • (optimization) Ranged storage blocks now store their blocks using a "list of constant-size arrays" (class ranged_storage_block_list) instead of using std::vector. This prevents constant reallocations when the vector grows in size, while avoiding the slow (uncacheable) iterations common to a list of objects. After some testing I have chosen 32 sections per list element, as this seemed to show no performance loss compared to std::vector.
  • (cleanup/optimization) Implement range_iterator for ranged storage. Given an address range, it will iterate automatically through all overlapping sections, using an optimized algorithm taking advantage the new "unowned overlapping sections" list mentioned above.
  • (cleanup) Move all texture cache support code (such as ranged_storage, cached_texture_section, etc) from RSX/Common/texture_cache.h to RSX/Common/texture_cache_utils.h.

Other than the above changes, I underwent a general review of the texture cache code, which resulted in various small bug fixes and tweaks I did not mention above (too many to list), some of which have already been merged in past PRs.


A second batch of changes fixes known regressions, and implements the following changes:

  • (facepalm) Fix a mistake of mine that was tanking performance: Do not loop through every single (most likely empty) ranged storage block when purging empty sections from memory. Instead, keep track of the set of blocks-in-use.
  • (bugfix) section.discard() now resets confirmed_range appropriately
  • (cleanup/optimization) Section storage now does automatic refcounting and resource tracking (except for framebuffer textures, which are kept around longer). Might help fix VRAM leaks.
  • (debug) Implement a texture cache protection checker. This checker (enabled by defining TEXTURE_CACHE_DEBUG) will keep track of the current protection of each page, as well as a refcount of the sections that require it to be protected. This allows us to quickly check whether something went wrong with the invalidation process, speeding up debug and development
  • (bugfix) Correctly unprotect sections that cross a mapped block boundary
  • (bugfix) Fix RSX/Cell race condition where a game unmapping and/or re-mapping various sections in a row could cause VirtualProtect errors or other similar failures due to RSX section invalidation
  • (optimization) Track cache misses using address_range instead of just the base address, in order to avoid as many collisions
  • (optimization) Small tweaks to m_flush_always_cache
  • (OCD) Align the statistics in the debug overlay to make them easier to parse

These changes are confirmed to bring the Transformer games to the menu, whereas before they would get stuck after the intro logos.

@Kravickas
Copy link
Contributor

Kravickas commented Sep 12, 2018

NHL 15 - Access violations and infinite loading to ingame
NHL15v1.gz
NHL15v2.gz

@stride21
Copy link

Battlefield: Bad Company crashes on start up
RPCS3.log.gz

@Hasster1
Copy link

No problems with InFamous or Serious Sam 3.
This pr - is just perfect.
Now rpcs3 compiles shaders REALLY fast.
And there is on 90% less glitches and lags with async shader compiler.
It's like i'm playing game without shader compiling!

@greentop
Copy link

GCC build error on Ubuntu 18.04.

[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLCommonDecompiler.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLFragmentProgram.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLGSRender.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLHelpers.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLRenderTargets.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLTexture.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLVertexBuffers.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLVertexProgram.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/OpenGL.cpp.o
In file included from /home/green/rpcs3/rpcs3/Emu/RSX/GL/../Common/texture_cache.h:5:0,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLTextureCache.h:19,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLGSRender.h:5,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLGSRender.cpp:4:
/home/green/rpcs3/rpcs3/Emu/RSX/GL/../Common/texture_cache_utils.h:471:3: error: non-constant condition for static assertion
   static_assert((num_blocks > 0) && ((u64)(num_blocks)* block_size == 0x1'0000'0000ull), "Invalid block_size/num_blocks");
   ^~~~~~~~~~~~~
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GSRender.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/Null/NullGSRender.cpp.o
/home/green/rpcs3/rpcs3/Emu/RSX/GL/GLGSRender.cpp: In member function ‘virtual void GLGSRender::end()’:
/home/green/rpcs3/rpcs3/Emu/RSX/GL/GLGSRender.cpp:560:54: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
     offsets[dst_index++] = (const GLvoid*)(first << 2);
                                                      ^
In file included from /home/green/rpcs3/rpcs3/Emu/RSX/GL/../Common/texture_cache.h:5:0,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLTextureCache.h:19,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLGSRender.h:5,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp:3:
/home/green/rpcs3/rpcs3/Emu/RSX/GL/../Common/texture_cache_utils.h:471:3: error: non-constant condition for static assertion
   static_assert((num_blocks > 0) && ((u64)(num_blocks)* block_size == 0x1'0000'0000ull), "Invalid block_size/num_blocks");
   ^~~~~~~~~~~~~
In file included from /home/green/rpcs3/rpcs3/Emu/RSX/GL/../Common/texture_cache.h:5:0,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLTextureCache.h:19,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLGSRender.h:5,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/GL/GLVertexBuffers.cpp:2:
/home/green/rpcs3/rpcs3/Emu/RSX/GL/../Common/texture_cache_utils.h:471:3: error: non-constant condition for static assertion
   static_assert((num_blocks > 0) && ((u64)(num_blocks)* block_size == 0x1'0000'0000ull), "Invalid block_size/num_blocks");
   ^~~~~~~~~~~~~
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/Overlays/overlay_perf_metrics.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/Overlays/overlays.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/RSXTexture.cpp.o
[ 91%] Building CXX object rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/RSXThread.cpp.o
rpcs3/CMakeFiles/rpcs3.dir/build.make:5326: recipe for target 'rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLRenderTargets.cpp.o' failed
make[2]: *** [rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLRenderTargets.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
rpcs3/CMakeFiles/rpcs3.dir/build.make:5276: recipe for target 'rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLGSRender.cpp.o' failed
make[2]: *** [rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLGSRender.cpp.o] Error 1
rpcs3/CMakeFiles/rpcs3.dir/build.make:5376: recipe for target 'rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLVertexBuffers.cpp.o' failed
make[2]: *** [rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/GL/GLVertexBuffers.cpp.o] Error 1
In file included from /home/green/rpcs3/rpcs3/Emu/RSX/Common/texture_cache.h:5:0,
                 from /home/green/rpcs3/rpcs3/Emu/RSX/RSXThread.cpp:10:
/home/green/rpcs3/rpcs3/Emu/RSX/Common/texture_cache_utils.h:471:3: error: non-constant condition for static assertion
   static_assert((num_blocks > 0) && ((u64)(num_blocks)* block_size == 0x1'0000'0000ull), "Invalid block_size/num_blocks");
   ^~~~~~~~~~~~~
rpcs3/CMakeFiles/rpcs3.dir/build.make:5576: recipe for target 'rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/RSXThread.cpp.o' failed
make[2]: *** [rpcs3/CMakeFiles/rpcs3.dir/Emu/RSX/RSXThread.cpp.o] Error 1
CMakeFiles/Makefile2:1430: recipe for target 'rpcs3/CMakeFiles/rpcs3.dir/all' failed
make[1]: *** [rpcs3/CMakeFiles/rpcs3.dir/all] Error 2
Makefile:151: recipe for target 'all' failed
make: *** [all] Error 2

@@ -56,6 +70,16 @@

#define STR_CASE(...) case __VA_ARGS__: return #__VA_ARGS__


#define ASSERT(x) do { if(!(bool)(x)) fmt::raw_error("Assertion failed: " STRINGIZE(x) HERE); } while(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use C style casts. if (!(x)) is much more correct.

@@ -21,20 +21,34 @@
#define IS_BE_MACHINE 0

#ifdef _MSC_VER
#define ASSUME(cond) __assume(cond)

#define ASSUME(cond) __assume(cond) // MSVC __assume ignores side-effects
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old problem, but most macro should use ... and VA_ARGS instead of a single named arg.

public:
static constexpr u32 block_size = 0x100'0000;
static_assert(block_size % 4096u == 0, "block_size must be a multiple of the page size");
static constexpr u32 num_blocks = (u32)(0x1'0000'0000ull / block_size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C style cast damages.

static constexpr u32 num_blocks = u32{0x1'0000'0000ull / block_size};

@ruipin
Copy link
Contributor Author

ruipin commented Sep 12, 2018

@Hasster1

Now rpcs3 compiles shaders REALLY fast.
And there is on 90% less glitches and lags with async shader compiler.
It's like i'm playing game without shader compiling!

This PR does not touch the shader compilation, so you might be confusing those improvements with the fact that the shader cache exists and was collected the first time you ran the game on master.

@greentop

GCC build error on Ubuntu 18.04.

What gcc version are you using, for reference? Although I believe @Nekotekina has already pointed out my mistake

@Nekotekina
Thanks for the review comments, will fix them later today.

@ Everyone Else
I'll take a look at the regressions you have pointed out today after work. Thanks for the reports!

@MSuih
Copy link
Member

MSuih commented Sep 12, 2018

Nvidia drivers also have their own cache which tries to speed up shader operations. It can sometimes activate or deactivate itself randomly, speeding up or slowing down shader-related operations.

@vietnam13231
Copy link

Hyperdimension Neptunia performance drops by ~60% in comparison to master. Beside that I don't see any difference (P5, Project Diva f2nd, Infamous, Ethernal Sonata, Drakengard 3).

HyperNep-RPCS3.log.gz

@greentop
Copy link

@ruipin - Ubuntu 18.04 with repository packages:

  • gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0
  • g++ (Ubuntu 7.3.0-16ubuntu3) 7.3.0

@Hasster1
Copy link

Oh, i guess i just readed the title wrong, and i wasn't checking last merged pr's.
Sorry(

@ruipin ruipin changed the title [WIP] [Testing needed] Texture Cache cleanup/refactoring & fixes [WIP] [Wait for fixes] Texture Cache cleanup/refactoring & fixes Sep 13, 2018
@ruipin
Copy link
Contributor Author

ruipin commented Sep 13, 2018

Since there are known bugs right now, no more testing is needed until further notice. Thanks to everyone who reported regressions. I will let you know once this is ready for further testing.

@Kravickas
I have managed to reproduce the issue and am in the process of debugging it. Thanks for the report 👍

@stride21
I see this crash on the latest master. It seems to have been caused by #5110

@raveskirza
I was not able to reproduce the issue you see, sadly. What settings were you using?

@stride21
Copy link

@ruipin Your right, I don't know how I missed that master my mistake.

@kd-11 kd-11 mentioned this pull request Sep 14, 2018
@ruipin ruipin changed the title [WIP] [Wait for fixes] Texture Cache cleanup/refactoring & fixes [WIP] [Testing needed] Texture Cache cleanup/refactoring & fixes Sep 18, 2018
@ruipin
Copy link
Contributor Author

ruipin commented Sep 18, 2018

All reported regressions should be fixed, plus a significant number of extra changes (I have added an updated list to the PR description above).

Please (re-)test. As always, expect things to go wrong.

(32 commits, 4930 lines changed, +3,522 −1,408 what did I get myself into 😱)

@elhaya
Copy link

elhaya commented Sep 18, 2018

getting this with pretty much every game: {rsx::thread} class std::runtime_error thrown: VirtualProtect failed

@stride21
Copy link

stride21 commented Sep 18, 2018

Killzone 3 crashes just before going ingame, throws " {rsx::thread} class std::runtime_error thrown: Assertion failed: region.matches_dimensions(width, height, 1, 1)"
RPCS3.log.gz

@greentop
Copy link

The gcc 7.3.0 build is confirmed fixed on Ubuntu 18.04. BLUS31535, BLUS30727, BLUS31597, BLUS30701, All running - No texture issues observed - Roughly ~27 FPS on BLUS30701 (Hyperdimension Neptunia) compared to Master's ~28 FPS in the Evil Cave (First Dungeon) / All other games running at 30 FPS.

RPCS3.log.gz

@vietnam13231
Copy link

No problems on my side, no regressions compared to current master. What's more, I observed significant performance improvement (5~10FPS depending on game and locations in game).

@ruipin
Copy link
Contributor Author

ruipin commented Sep 18, 2018

@elhaya Thanks for the report, but I do not see that error with "pretty much every game" otherwise I wouldn't have requested people to retest. I'm not omniscient, so please list at least one or two games you have tried where you got that error, explain when/how you got that error, and if possible submit a log so I can actually understand what is causing it and fix it.

@stride21 That is indeed an assertion I was afraid might fail. Will take a look, thanks for the report!

@vietnam13231 That is good to hear, although I am honestly quite surprised at a 5-10FPS improvement. Out of curiosity, can you give one or two examples of games/locations where you see such a drastic change? I'd like to take a look myself. Thanks.

@elhaya
Copy link

elhaya commented Sep 18, 2018

@ruipin attched is a log of gow3. also tested with rdr.
what's strange though is that if i play another game first, say god of war hd and only then gow 3 - the error goes away.. hmm also tried extracting to a fresh dir and got the same result
RPCS3.log

@MSuih
Copy link
Member

MSuih commented Sep 18, 2018

THPS HD: The whole emulator locks up when trying to load any level. Log doesn't seem to contain anything useful. Master loads levels without any issues.

Red Dead Redemption: Throws Assertion failed: region.get_context() == texture_upload_context::framebuffer_storage after intro movies. RPCS3.log.gz

@ruipin
Copy link
Contributor Author

ruipin commented Sep 18, 2018

@MSuih
THPS HD: Can you try this build once it finishes https://ci.appveyor.com/project/ruipin/rpcs3/build/0.0.5-7385 and see whether you see an actual error instead of a hang? (I enabled the checker and assertions)

As for RDR, thanks for the report.

@MSuih
Copy link
Member

MSuih commented Sep 18, 2018

In that assertion build THPS HD still freezes when loading levels but it doesn't lock up rest of the emulator anymore. I didn't see anything different in log, no errors are being printed to it.

@stride21
Copy link

stride21 commented Sep 23, 2018

I'll keep retesting master to see if I can reproduce the black flash but your PR does fix graphic issues with the game so it might not even be a regression.

@RainbowCookie32
Copy link
Contributor

RainbowCookie32 commented Sep 23, 2018

This PR fixes the blue tint that'd appear in some situations in P5 NPEB02436 introduced by #5146
I'd love to attach some comparison screenshots but they happen fast usually and are hard to catch

@ruipin ruipin force-pushed the texture-cache-pr branch 2 times, most recently from 0d581f0 to ba0b5ae Compare September 23, 2018 22:59
@ruipin
Copy link
Contributor Author

ruipin commented Sep 24, 2018

I have done some last changes to fix some style issues pointed out by @kd-11. I believe this PR is ready to be reviewed/merged whenever.

Meanwhile, I took a quick look at the TLOU segfault with WCB on. After some discussions with kd-11, I also took the chance to add the single-line fix for this issue. This should allow games that segfaulted with WCB enabled to now go in-game.

Debugging this segfault raised some issues/inneficiencies with the way rsx::weak_ptr objects are created and copied around which could severely reduce performance, but these aren't simple to fix and this PR has already gotten big enough, so they will be done at some point as a separate PR.

@RainbowCookie32
Copy link
Contributor

3806 lines of code added. This is a big boi

@ScorchEmber256
Copy link

Little Big Planet 2 crashes on vulkan with
"F {rsx::thread} class std::runtime_error thrown: Verification failed:
(in file c:\projects\rpcs3\rpcs3\emu\rsx\vk\vkgsrender.cpp:3023)"
and on opengl with
"F {rsx::thread} class std::runtime_error thrown: Verification failed (e=0xb7):
(in file c:\projects\rpcs3\rpcs3\emu\rsx\gl\glgsrender.cpp:1483)"

@ruipin
Copy link
Contributor Author

ruipin commented Sep 24, 2018

@ScorchEmber256 does that not happen on master? I did not touch the surface cache (which is where these verifications are failing)

@ScorchEmber256
Copy link

nevermind, yes it is happening on master

@stride21
Copy link

stride21 commented Sep 24, 2018

I've been testing Motorstorm on this PR and it crashes when trying to go ingame and it does not throw an error when it does. I've tested it on master too and it gets ingame but gets a Verification failed error shortly after getting ingame. Edit: Should I just wait for this and #5163 to be merge to see if the issue is fixed?
RPCS3log.zip

- ASSUME now uses __builtin_assume in clang
- ASSERT defined as a wrapper around verify
- AUDIT aliases ASSERT when _DEBUG or _AUDIT are set, otherwise empty
This allows for further flexibility on the RSX side, allowing us to fix
some bugs and crashes in later commits.
@ruipin
Copy link
Contributor Author

ruipin commented Sep 24, 2018

@stride21 Since master also doesn't work, this does not seem like a regression. Have you tried the latest build with the WCB fix?

@kd-11
Copy link
Contributor

kd-11 commented Sep 24, 2018

I'm going to merge this as-is since there are no major reported regressions. Open a regression tracker if you find any more issues.

@kd-11 kd-11 merged commit 35139eb into RPCS3:master Sep 24, 2018
@hockland
Copy link

As this PR is a potential fix for #5105 which I opened, I'll definitely be testing out this one. Will report back. Or should I just post in the #5105 ?

@Asinin3
Copy link
Contributor

Asinin3 commented Sep 24, 2018

Best to post in the issue since one is already made. Then just tag this pr if it fixes it. And, there's no real reason to notify people you're about to test something, we like to keep GitHub comments clean. (But I understand you were just asking where to post).

@stride21
Copy link

@ruipin I've done a lot of retesting and the verification failed error isn't happening in previous builds any more. I'm not sure what caused it but I'm actually able to complete races now even though the game can still randomly crash. With your build it black screens and crashes when trying to go ingame and it doesn't throw an error when it does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet