* GPU: Remove swizzle undefined matching and rework depth aliasing
@gdkchan pointed out that UI textures in TOTK seemed to be setting their texture swizzle incorrectly (texture was RGB but was sampling A, swizzle for A was wrong), so I determined that SwizzleComponentMatches was the problem and set on eliminating it. This PR combines existing work to select the most recently modified texture (now used when selecting which aliased texture to use) with some additional changes to remove the swizzle check and support aliased view creation.
The original observation (#1538) was that we wanted to match depth textures for the purposes of aliasing with color textures, but they often had different swizzle from what was sampled (as it's generally the identity swizzle once rendered). At the time, I decided to allow swizzles to match if only the defined components matched, which fixed the issue in all known cases but could easily be broken by a game _expecting_ a given swizzle, such as a 1/0 value on a component.
This error case could also occur in textures that don't even depth alias, such as R11G11B10, as the rule was created to generally apply to all cases.
The solution is now to fail this exact match test, and allow the search for an R32 texture to create a swizzled view of a D32 texture (and other such cases). This allows the creation of a view that mismatches the requested format, which wasn't present before and was the reason for the swizzle matching approach.
The exact match and view creation rules now follow the same rules over what textures to select when there are multiple options (such as a "perfect" match and an "aliased" match at the same time). It now selects the most recently modified texture, which is done with a new sequence number in the GpuContext (because we don't have enough of these).
Reportedly fixes UI having weird coloured backgrounds in TOTK. This also fixes an issue in MK8D where returning from a race resulted in the character selection cubemaps being broken. May work around issues introduced by the "short texture cache" PR due to modification ordering, though they won't be truly fixed.
Should allow (#4365) to avoid copies in more cases. Need to test that.
I tested a bunch of games #1538 originally affected and they seem to be fine. This change affects all games so it would be good to get some wide testing on it.
* Address feedback 1, fix an issue
* Workaround: Do not allow copies for format alias.
These should be removed when D32<->R32 copy dependencies become legal
This fixes a potential issue where a shader lookup could match the address of a previous _different_ shader, but that shader is now partially unmapped. This would just crash with an invalid region exception.
To compare a shader in the address cache with one in memory, we get the memory at the location with the previous shader's size. However, it's possible it has been unmapped and then remapped with a smaller size. In this case, we should just get back the mapped portion of the shader, which will then fail the comparison immediately and get to compile/lookup for the new one.
This might fix a random crash in TOTK that was reported by Piplup. I don't know if it does, because I don't have the game yet.
* Vulkan: Batch vertex buffer updates
Some games can bind a large number of vertex buffers for draws. This PR allows for vertex buffers to be updated with one call rather than one per buffer.
This mostly affects the AMD Mesa driver, the testing platform was Steam Deck with Super Mario Odyssey. It was taking about 12% before, should be greatly reduced now.
A small optimization has been added to avoid looking up the same buffer multiple times, as a common pattern is for the same buffer to be bound many times in a row with different ranges.
* Only rebind vertex buffers if they have changed
* Address feedback
* GPU: Remove CPU region handle containers.
Another one for the "I don't know why I didn't do this earlier" pile.
This removes the "Cpu" prefixed region handle classes, which each mirror a region handle type from Ryujinx.Memory.
Originally, not all projects had a reference to Ryujinx.Memory, so these classes were introduced to bridge the gap. Someone else crossed that bridge since, so these classes don't have much of a purpose anymore.
This PR replaces all uses of CpuRegionHandle etc to their direct Ryujinx.Memory versions.
RegionHandle methods (specifically QueryModified) are about the hottest path there is in the entire emulator, so there is a nice boost from doing this.
* Add docs
* GPU: Allow granular buffer updates from the constant buffer updater
Sometimes, constant buffer updates can't be avoided, either due to a cb0 access that cannot be eliminated, or the game updating a buffer between draws to the detriment of everyone.
To avoid uploading the full 4096 bytes each time, this PR remembers the offset and size containing all constant buffer updates since the last sync. It will then upload that range after sync.
* Allow clearing the dirty range
* Always use precise
Might want to not do this if distance between the existing range and new one is too high.
* Use old force dirty mechanism when distance between regions is too great
* Update src/Ryujinx.Graphics.Gpu/Memory/Buffer.cs
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
* Fix inheritance of _dirtyStart and _dirtyEnd
---------
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Our Vulkan backend inserts image barriers when a texture is sampled after it is rendered. This is done via a "modification flag" which is set when a render target is unbound (presuming that a texture has finished drawing to it).
Imagine the following scenario:
- Game sets render target to texture A
- Game renders to texture A
- (render pass ends)
- Game binds texture A to a sampler
- Game sets render target to texture B
- Renders to texture B using texture A (barrier required)
Because of the previous behaviour, the check to add a barrier for sampling a texture actually happens before it is registered as modified, meaning no barrier was added at all. This isn't always the case, but it was definitely causing issues in Xenoblade 2.
This doesn't fix any more complicated issues where a texture is repeatedly sampled while it is currently being rendered.
Fixes visual glitches at lower resolutions in Xenoblade 2. May fix other cases.
* GPU: Keep sampled textures without any pool references alive
Occasionally games are very wasteful and clear/write to a texture without ever sampling it. As rendered textures in NVN games seem to all have overlapping memory ranges, the texture will eventually get overwritten.
Normally, this would trigger a removal from the auto delete cache, but a pool entry would keep the texture alive. However, with these textures that are never used, they will get deleted immediately and recreated on the next frame.
This change makes it so the ShortTextureCache can keep textures that have naver had a pool reference alive for a few frames, so they're not constantly being created and deleted.
This improves performance in Zelda BOTW a little.
* Cleanup
* WIP texture pre-flush
Improve performance of TextureView GetData to buffer
Fix copy/sync ordering
Fix minor bug
Make this actually work
WIP host mapping stuff
* Fix usage flags
* message
* Cleanup 1
* Fix rebase
* Fix
* Improve pre-flush rules
* Fix pre-flush
* A lot of cleanup
* Use the host memory bits
* Select the correct memory type
* Cleanup TextureGroupHandle
* Missing comment
* Remove debugging logs
* Revert BufferHandle _value access modifier
* One interrupt action at a time.
* Support D32S8 to D24S8 conversion, safeguards
* Interrupt cannot happen in sync handle's lock
Waitable needs to be checked twice now, but this should stop it from deadlocking.
* Remove unused using
* Address some feedback
* Address feedback
* Address more feedback
* Address more feedback
* Improve sync rules
Should allow for faster sync in some cases.
* GPU: Fix errors handling texture remapping
- Fixes an error where a pool entry and memory mapping changing at the same time could cause a texture to rebind its data from the wrong GPU VA (data swaps)
- Fixes an error where the texture pool could act on a mapping change before the mapping has actually been changed ("Unmapped" event happens before change, we need to signal it changed _after_ it completes)
TODO: remove textures from partially mapped list... if they aren't.
* Add Remap actions for handling post-mapping behaviours
* Remove unused code.
* Address feedback
* Nit
* Flush in the middle of long command buffers.
* Vulkan: add situational "Fast Flush" mode
The AutoFlushCounter class was added to periodically flush Vulkan command buffers throughout a frame, which reduces latency to the GPU as commands are submitted and processed much sooner. This was done by allowing command buffers to flush when framebuffer attachments changed.
However, some games have incredibly long render passes with a large number of draws, and really aggressive data access that forces GPU sync.
The Vulkan backend could potentially end up building a single command buffer for 4-5ms if a pass has enough draws, such as in BOTW. In the scenario where sync is waited on immediately after submission, this would have to wait for the completion of a much longer command buffer than usual.
The solution is to force command buffer submission periodically in a "fast flush" mode. This will end up splitting render passes, but it will only enable if sync is aggressive enough.
This should improve performance in GPU limited scenarios, or in games that aggressively wait on synchronization. In some games, it may only kick in when res scaling. It won't trigger in games like SMO where sync is not an issue.
Improves performance in Pokemon Scarlet/Violet (res scaled) and BOTW (in general).
* Add conversions in milliseconds next to flush timers.
* ARMeilleure: Move TPIDR_EL0 and TPIDRRO_EL0 to NativeContext
Some games access these system registers several tens of thousands of times in a second from many different threads. While this isn't really crippling, it is a lot of wasted time spent in a reverse pinvoke transition.
Example games are Pokemon Scarlet/Violet and BOTW. These games have a lot of different potential bottlenecks so it's unlikely you will see a consistent improvement, but it definitely disappears from the cpu profile.
* Remove unreachable code.
* Add ulong conversion for offsets
* Nit
This seems to have been removed by the Post-Processing PR, but it is required for the display in OBS to be the right way up and properly scaled.
I've tested this with AA and FSR on MK8D and it seems to behave properly. Testing is welcome.
* ARMeilleure: Respect Fz flag for all floating point operations.
This is a change in strategy for emulating the Fz FPCR flag. Before, it was set before instructions that "needed it" and reset after. However, this missed a few hot instructions like the multiplication instruction, and the entirety of A32.
The new strategy is to set the Fz flag only in the following circumstances:
- Set to match FPCR before translated functions/loop are executed.
- Reset when calling SoftFloat methods, set when returning.
- Reset when exiting execution.
This allows us to remove the code around the existing Fz aware instructions, and get the accuracy benefits on all floating point instructions executed while in translated code.
Single step executions now need to be called with a context wrapper - right now it just contains the Fz flag initialization, and won't actually do anything on ARM.
This fixes a bug in Breath of the Wild where some physics interactions could randomly crash the game due to subnormal values not flushing to zero.
This is draft right now because I need to answer the questions:
- Does dotnet avoid changing the value of Mxcsr?
- Is it a good idea to assume that? Or should the flag set/restore be done on every managed method call, not just softfloat?
- If we assume that, do we want a unit test to verify the behaviour?
I recommend testing a bunch of games, especially games affected when this was originally added, such as #1611.
* Remove unused method
* Use FMA for Fmadd, Fmsub, Fnmadd, Fnmsub, Fmla, Fmls
...when available.
Similar implementation to A32
* Use FMA for Frecps, Frsqrts
* Don't set DAZ.
* Add round mode to ARM FP mode
* Fix mistakes
* Add test for FP state when calling managed methods
* Add explanatory comment to test.
* Cleanup
* Add A64 FPCR flags
* Vrintx_S A32 fast path on A64 backend
* Address feedback 1, re-enable DAZ
* Fix FMA instructions By Elem
* Address feedback
* Vulkan: Insert barriers before clears
Newer NVIDIA GPUs seem to be able to start clearing render targets before the last rasterization task is completed, which can cause it to clear a texture while it is being sampled.
This change adds a barrier from read to write when doing a clear, assuming it has been sampled in the past. It could be possible for this to be needed for sample into draw by some GPU, but it's not right now afaik.
This should fix visual artifacts on newer NVIDIA GPUs and driver combos. Contrary to popular belief, Tetris® Effect: Connected is not affected. Testing welcome, hopefully should fix most cases of this and not cost too much performance.
* Visual Studio Moment
* Address feedback
* Address Feedback 2
* Initial implementation of migration between memory heaps
- Missing OOM handling
- Missing `_map` data safety when remapping
- Copy may not have completed yet (needs some kind of fence)
- Map may be unmapped before it is done being used. (needs scoped access)
- SSBO accesses are all "writes" - maybe pass info in another way.
- Missing keeping map type when resizing buffers (should this be done?)
* Ensure migrated data is in place before flushing.
* Fix issue where old waitable would be signalled.
- There is a real issue where existing Auto<> references need to be replaced.
* Swap bound Auto<> instances when swapping buffer backing
* Fix conversion buffers
* Don't try move buffers if the host has shared memory.
* Make GPU methods return PinnedSpan with scope
* Storage Hint
* Fix stupidity
* Fix rebase
* Tweak rules
Attempt to sidestep BOTW slowdown
* Remove line
* Migrate only when command buffers flush
* Change backing swap log to debug
* Address some feedback
* Disallow backing swap when the flush lock is held by the current thread
* Make PinnedSpan from ReadOnlySpan explicitly unsafe
* Fix some small issues
- Index buffer swap fixed
- Allocate DeviceLocal buffers using a separate block list to images.
* Remove alternative flags
* Address feedback
* GPU: Fast path for adding one texture view to a group
Texture group handles must store a list of their overlapping views, so they can be properly notified when a write is detected, and a few other things relating to texture readback. This is generally created when the group is established, with each handle looping over all views to find its overlaps. This whole process was also done when only a single view was added (and no handles were changed), however...
Sonic Frontiers had a huge cubemap array with 7350 faces (175 cubemaps * 6 faces * 7 levels), so iterating over both handles and existing views added up very fast. Since we are only adding a single view, we only need to _add_ that view to the existing overlaps, rather than recalculate them all.
This greatly improves performance during loading screens and a few seconds into gameplay on the "open zone" sections of Sonic Frontiers. May improve loading times or stutters on some other games.
Note that the current texture cache rules will cause these views to fall out of the cache, as there are more than the hard cap, so the cost will be repaid when reloading the open zone.
I also added some code to properly remove overlaps when texture views are removed, since it seems that was missing.
This can be improved further by only iterating handles that overlap the view (filter by range), but so can a few places in TextureGroup, so better to do all at once. The full generation of overlaps could probably be improved in a similar way.
I recommend testing a few games to make sure nothing breaks.
* Address feedback
* Update sparsely mapped texture ranges without recreating
Important TODO in TexturePool. Smaller TODO: should I look into making textures with views also do this? It needs to be able to detect if the views can be instantly deleted without issue if they're now remapped.
* Actually do partial updates
* Signal group dirty after mappings changed
* Fix various issues (should work now)
* Further optimisation
Should load a lot less data (16x) when partial updating 3d textures.
* Improve stability
* Allow granular uploads on large textures, improve rules
* Actually avoid updating slices that aren't modified.
* Address some feedback, minor optimisation
* Small tweak
* Refactor DereferenceRequest
More specific initialization methods.
* Improve code for resetting handles
* Explain data loading a bit more
* Add some safety for setting null from different threads.
All texture sets come from the one thread, but null sets can come from multiple. Only decrement ref count if we succeeded the null set first.
* Address feedback 1
* Make a bit safer
* GPU: Scale counter results before addition
Counter results were being scaled on ReportCounter, which meant that the _total_ value of the counter was being scaled. Not only could this result in very large numbers and weird overflows if the game doesn't clear the counter, but it also caused the result to change drastically.
This PR changes scaling to be done when the value is added to the counter on the backend. This should evaluate the scale at the same time as before, on report counter, but avoiding the issue with scaling the total.
Fixes scaling in Warioware, at least in the demo, where it seems to compare old/new counters and broke down when scaling was enabled.
* Fix issues when result is partially uploaded.
Drivers tend to write the low half first, then the high half. Retry if the high half is FFFFFFFF.
* Sockets: Properly convert error codes on MacOS
The error codes for MacOS are very different to how they are on windows or linux. An alternate mapping is used when the host operating system is MacOS.
This PR also defaults IsDhcpEnabled to true when interfaceProperties.DhcpServerAddresses is not available.
This change was already in `macos1`.
* Address feedback
I noticed that in Xenoblade 2, the game can end up spending a lot of time adding and removing tracking handles. One of the main causes of this is actually splitting existing handles, which does the following:
- Remove existing handle from list
- Update existing handle to end at split address, create new handle starting at split address
- Add updated handle (left) to list
- Add new handle (right) to list
This costs 1 deletion and 2 insertions. When there are more handles, this gets a lot more expensive, as insertions are done by copying all values to the right, and deletions by copying values to the left.
This PR simply allows it to look up the handle being split, and replace its entry with the new end address without insertion or deletion. This makes a split only cost one insertion and a binary search lookup (very cheap). This isn't all of the cost on Xenoblade 2, but it does significantly reduce it.
There might be something else to this - we could find a way to reduce the handle count for the game (merging on deletion? buffer deletion?), we could use a different structure for virtual regions, as the current one is optimal for buffer lookups which nearly always read, memory tracking has more of a balance between read/write. That's for a later date though, this was an easy improvment.
I was forcing some types of texture to partially update when investigating performance with games that stream in data, and noticed that partially loading texture data was really broken on both backends.
Fixes Vulkan texture set by getting the correct expected size for the texture. Fixes partial upload on both backends for both Texture 2D Array and Cubemap using the wrong offset and uploading to the first layer/level for a handle. 3D might also be affected.
This might fix textures randomly having incorrect data in games that render to it - jumbled in the case of OpenGL, and outdated/black in the case of Vulkan. This case typically happens in UE4 games.
* Log shader compile errors with Warning level
These are infrequent enough that I think it's worth dumping any errors into the log. They also keep causing graphical glitches, and the only indication that anything went wrong is a debug log that is never enabled.
* Add maximum length for shader log
The AutoFlushCounter would flush command buffers on any attachment change (write mask or bindings change) if there was a pending query. This is to get query results as soon as possible for draw skips, but it's assuming that a full occlusion query _pass_ happened, that we want to flush it's data before getting onto draws, rather than the queries being randomly interspersed throughout a pass that also draws.
Xenoblade 2 repeatedly switches between performing a samples passed query and outputting to a render target on each draw, and flips the write mask to do so. Flushing the command buffer every 2 draws isn't ideal, so it's best that we only do this if the pattern matches the large block style of occlusion query.
This change makes this flush only happen after a few consecutive query reports. "Consecutive" is interrupted by attachment changes or command buffer flush.
This doesn't really solve the issue where it resets more queries than it uses, it just stops the game doing it as often. I'm not sure of the best way to do that. The cost of resetting could probably be reduced by using query pools with more than one element and resetting in bulk.
* Reset queries on same command buffer
Vulkan seems to complain when the queries are reset on another command buffer. No idea why, the spec really could be written better in this regard. This fixes complaints, and hopefully any implementations that care extensively about them.
This change _guesses_ how many queries need to be reset and resets as many as possible at the same time to avoid splitting render passes. If it resets too many queries, we didn't waste too much time - if it runs out of resets it will batch reset 10 more.
The number of queries reset is the maximum number of queries in the last 3 frames. This has been worked into the AutoFlushCounter so that it only resets up to 32 if it is yet to force a command buffer submission in this attachment.
This is only done for samples passed queries right now, as they have by far the most resets.
* Address Feedback
* Allow setting texture data from 1x to fix some textures resetting randomly
Expected targets:
- Deltarune 1+2
- Crash Team Racing
- Those new pokemon games idk
* Allow scaling of MSAA textures, propagate scale on copy.
* Fix Rebase
Oops
* Automatic disable
* A bit more aggressive
* Without the debug log
* Actually decrement the score when writing.
The only guarantee of the occlusion query type in Vulkan is that it will be zero when no samples pass, and non-zero when any samples pass. Of course, most GPUs implement this by just placing the # of samples in the result and calling it a day. However, this lax restriction means that GPUs could just report a boolean (1/0) or report a value after one is recorded, but before all samples have been counted.
MoltenVK falls in the first category - by default it only reports 1/0 for occlusion queries. Thankfully, there is a feature and flag that you can use to force compatible drivers to provide a "precise" query result, that being the real # of samples passed.
Should fix ink collision in Splatoon 2/3 on MoltenVK.
* Add short duration texture cache
This texture cache takes textures that lose their last pool reference and keeps them alive until the next frame, or until an incompatible overlap removes it. This is done since under certain circumstances, a texture's reference can be wiped from a pool despite it still being in use - though typically the reference will return when rendering the next frame.
While this may slightly increase texture memory usage when quickly going through a bunch of temporary textures, it's still bounded due to the overlap removal rule.
This greatly increases performance in Hyrule Warriors: Age of Calamity. It may positively affect some UE4 games which dip framerate severely under certain circumstances.
* Small optimization
* Don't forget this.
* Add short cache dictionary
* Address feedback
* Address some feedback
* Add MVK basics.
* Use appropriate output attribute types
* 4kb vertex alignment, bunch of fixes
* Add reduced shader precision mode for mvk.
* Disable ASTC on MVK for now
* Only request robustnes2 when it is available.
* It's just the one feature actually
* Add triangle fan conversion
* Allow NullDescriptor on MVK for some reason.
* Force safe blit on MoltenVK
* Use ASTC only when formats are all available.
* Disable multilevel 3d texture views
* Filter duplicate render targets (on backend)
* Add Automatic MoltenVK Configuration
* Do not create color attachment views with formats that are not RT compatible
* Make sure that the host format matches the vertex shader input types for invalid/unknown guest formats
* FIx rebase for Vertex Attrib State
* Fix 4b alignment for vertex
* Use asynchronous queue submits for MVK
* Ensure color clear shader has correct output type
* Update MoltenVK config
* Always use MoltenVK workarounds on MacOS
* Make MVK supersede all vendors
* Fix rebase
* Various fixes on rebase
* Get portability flags from extension
* Fix some minor rebasing issues
* Style change
* Use LibraryImport for MVKConfiguration
* Rename MoltenVK vendor to Apple
Intel and AMD GPUs on moltenvk report with the those vendors - only apple silicon reports with vendor 0x106B.
* Fix features2 rebase conflict
* Rename fragment output type
* Add missing check for fragment output types
Might have caused the crash in MK8
* Only do fragment output specialization on MoltenVK
* Avoid copy when passing capabilities
* Self feedback
* Address feedback
Co-authored-by: gdk <gab.dark.100@gmail.com>
Co-authored-by: nastys <nastys@users.noreply.github.com>
* Vulkan: Don't flush commands when creating most sync
When the WaitForIdle method is called, we create sync as some internal GPU method may read back written buffer data. Some games randomly intersperse compute dispatch into their render passes, which result in this happening an unbounded number of times depending on how many times they run compute.
Creating sync in Vulkan is expensive, as we need to flush the current command buffer so that it can be waited on. We have a limited number of active command buffers due to how we track resource usage, so submitting too many command buffers will force us to wait for them to return to the pool.
This PR allows less "important" sync (things which are less likely to be waited on) to wait on a command buffer's result without submitting it, instead relying on AutoFlush or another, more important sync to flush it later on.
Because of the possibility of us waiting for a command buffer that hasn't submitted yet, any thread needs to be able to force the active command buffer to submit. The ability to do this has been added to the backend multithreading via an "Interrupt", though it is not supported without multithreading.
OpenGL drivers should already be doing something similar so they don't blow up when creating lots of sync, which is why this hasn't been a problem for these games over there.
Improves Vulkan performance on Xenoblade DE, Pokemon Scarlet/Violet, and Zelda BOTW (still another large issue here)
* Add strict argument
This is technically a separate concern from whether the sync is a host syncpoint.
* Remove _interrupted variable
* Actually wait for the invoke
This is required by AMD GPUs, and also may have caused some issues on other GPUs.
* Remove unused using.
* I don't know why it added these ones.
* Address Feedback
* Fix typo
* Add conversion for 16 bit RGBA formats (not supported in Rosetta)
* Rebase fix
Rebase fix
* Forgot to remove this
* Fix RGBA16 format conversion
* Add RGBA4 -> RGBA8 conversion
* Handle host stride alignment
* Address Feedback Part 1
* Can't count
* Don't zero out rgb when alpha is 0
* Separate RGBA4 and 5-bit component formats
Not sure of a better way to name them...
* Add A1B5G5R5 conversion
* Put this in the right place.
* Make format naming consistent for capabilities
* Change method names
I noticed a weirdly high cost for dictionary accesses from MarkLabel etc. Turns out that the hash code was always the same for labels, so the whole point of having a dictionary was missed and it was putting everything in the same bucket. I made it always hash the _data pointer as that's a good source of identifiable and "random" data.
We have a conversion from LDG on the compute shader to a special constant buffer binding that's used to exceed hardware limits on compute, but it was only running if the byte offset could be identified. The fallback that checks all of the bindings at runtime only checks the storage buffers.
This PR adds checking ube ranges to the LoadGlobal fallback. This extends the changes in #4011 to only check ube entries which are accessed by the shader.
Fixes particles affected by the wind in The Legend of Zelda: Breath of the Wild. May fix other weird issues with compute shaders in some games.
Try a bunch of games and drivers to make sure they don't blow up loading constants willynilly from searchable buffers.
* Initial implementation of metal surface across UIs
* Fix SDL2 on windows
* Update Ryujinx/Ryujinx.csproj
Co-authored-by: Mary-nyan <thog@protonmail.com>
* Address Feedback
Co-authored-by: Mary-nyan <thog@protonmail.com>
* GPU: Use lazy checks for specialization state
This PR adds a new class, the SpecializationStateUpdater, that allows elements of specialization state to be updated individually, and signal the state is checked when it changes between draws, instead of building and checking it on every draw. This also avoids building spec state when
Most state updates have been moved behind the shader state update, so that their specialization state updates make it in before shaders are fetched.
Downside: Fields in GpuChannelGraphicsState are no longer readonly. To counteract copies that might be caused this I pass it as `ref` when possible, though maybe `in` would be better? Not really sure about the quirks of `in` and the difference probably won't show on a benchmark.
The result is around 2 extra FPS on SMO in the usual spot. Not much right now, but it will remove costs when we're doing more expensive specialization checks, such as fragment output type specialization for macos. It may also help more on other games with more draws.
* Address Feedback
* Oops
* GPU: Swap bindings array instead of copying
Reduces work on UpdateShaderState. Now the cost is a few reference moves for arrays, rather than copying data.
Downside: bindings arrays are no longer readonly.
* Micro optimisation
* Add missing docs
* Address Feedback
* Track buffer migrations and flush source on incomplete copy
Makes sure that the modified range list is always from the latest iteration of the buffer, and flushes earlier iterations of a buffer if the data has not been migrated yet.
* Cleanup 1
* Reduce cost for redundant signal checks on Vulkan
* Only inherit the range list if there are pending ranges.
* Fix OpenGL
* Address Feedback
* Whoops
Polygon topology wasn't really supported and would only work on OpenGL on drivers that haven't removed it. As an alternative, this PR makes all cases of polygon topology use triangle fan. The topology type and transform feedback type have not been changed, as I don't think geo shader/tfb should be used with polygons.
The OpenGL spec states:
Only convex polygons are guaranteed to be drawn correctly by the GL.
For convex polygons, triangle fan is equivalent to polygon. I imagine this is probably how it works on device, as this get-out-of-jail-free card is too enticing to pass up.
This fixes the stat display in Pokemon S/V.
This replacement is meant to be done with the original identified byteOffset, not the one assigned later on by the below conditionals (that already has the constant offset added, for instance).
This fixes videos being pixelated in Xenoblade 3, and other regressions that might have happened since #3847.
* GAL: Send all buffer assignments at once rather than individually
The `(int first, BufferRange[] ranges)` method call has very significant performance implications when the bindings are spread out, which they generally always are in Vulkan. This change makes it so that these methods are only called a maximum of one time per draw.
Significantly improves GPU thread performance in Pokemon Scarlet/Violet.
* Address Feedback
Removed SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
* GPU: Access non-prefetch command buffers directly
Saves allocating new arrays for them constantly - they can be quite small so it can be very wasteful. About 0.4% of GPU thread in SMO, but was a bit higher in S/V when I checked.
Assumes that non-prefetch command buffers won't be randomly clobbered before they finish executing, though that's probably a safe bet.
* Small change while I'm here
* Address feedback
I did this on ncbuffer2 when we were using it for LDN 3, but I noticed that it can apply to the current buffer manager too, and it's an easy performance win.
The only buffer access that can come from another thread is the overlap search for buffers that have been unmapped. Everything else, including modifications, come from the main GPU thread. That means we only need to lock the range list when it's being modified, as that's the only time where we'll cause a race with the unmapped handler.
This has a significant performance improvements in situations where FIFO is high, like the other two PRs. Joined together they give a nice boost (73.6 master -> 79 -> 83 fps in SMO).
A quick fix to prevent reading the wrong value of Count when reregistering ranges for a new target buffer. Buffer flushes from another thread can modify the range list when the lock isn't active, which can change the count.
This prevents some crashes in Pokemon Scarlet/Violet. It's probably likely that buffer migration during flush is causing some other issues in this game, but this at least prevents the crashing.
* Vulkan: Don't create preload buffer outside a render pass
The preload command buffer is used to avoid render pass splits and barriers when updating buffer data. However, when a render pass is not active (for example, at the start of a pass, or during compute invocations) buffer uploads can be performed at any time, so the optimization isn't as useful.
This PR makes it so that the preload command buffer is only used for buffer updates outside of a render pass. It's still used for textures as I don't want to shake things up right now regarding how the preload buffer is obtained before some other changes, and texture updates are a lot rarer anyways.
Improves performance slightly in Pokemon Scarlet/Violet (43 -> 48), as it was switching to compute, writing a bunch of buffers inline, then dispatching, then flushing commands... It uses 1 command buffer instead of 2 every time it does this now. Maybe it would be nice to find a faster way to sync without creating so many command buffers in a short period of time.
* Address feedback
* Prune ForceDirty and CheckModified caches on unmap
Since we're now using this for modified checks on the HLE indirect draw method, I'm worried that leaving these to forever gather cache entries isn't the best idea for performance in the long term, and it could keep old buffer objects alive for longer than they should be.
This PR adds the ability to prune invalid entries before checking these caches, and queues it whenever gpu memory is unmapped. It also aligns modified checks to the page size, as I figured it would be possible for a huge number of overlapping over a game's runtime.
This prevents Super Mario Odyssey from having 10s of thousands of entries in the modified cache in Metro Kingdom, and them duplicating when entering and leaving a building (should be cleared, as they were unmapped).
* Address Feedback
* Allow _volatile to be set from MultiRegionHandle checks again
Tracking handles have a `_volatile` flag which indicates that the resource being tracked is modified every time it is used under a new sequence number. This is used to reduce the time spent reprotecting memory for tracking writes to commonly modified buffers, like constant buffers.
This optimisation works by detecting if a buffer is modified every time a check happens. If a buffer is checked but it is not dirty, then that data is likely not modified every sequence number, and should use memory protection for write tracking. If the opposite is the case all the time, it is faster to just assume it's dirty as we'd just be wasting time protecting the memory.
The new MultiRegionBitmap could not notify handles that they had been checked as part of the fast bitmap lookup, so bindings larger than 4096 bytes wouldn't trigger it at all. This meant that they would be subject to a ton of reprotection if they were modified often.
This does mean there are two separate sources for a _volatile set: VolatileOrDirty + _checkCount, and the bitmap check. These shouldn't interfere with each other, though.
This fixes performance regressions from #3775 in Pokemon Sword, and hopefully Yu-Gi-Oh! RUSH DUEL: Dawn of the Battle Royale. May affect other games.
* Fix stupid mistake
The type in the `texOp` in the textureSize instruction doesn't have the exact type on SPIR-V (for example, it is missing the Array flag). This PR gives it the proper type before giving it to the unscaling helper.
This fixes the ground textures being broken on Pokemon Scarlet/Violet when scaling. It wasn't finding the texture, so the descriptor index it provided was -1...
* Eliminate CB0 accesses
Still some work to do, decouple from hle?
* Forgot the important part somehow
* Fix and improve alignment test
* Address Feedback
* Remove some complexity when checking storage buffer alignment
* Update Ryujinx.Graphics.Shader/Translation/Optimizations/GlobalToStorage.cs
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Due to the `using` statement being scoped to the `CreateTextureView` method, `TextureStorage` would be disposed as soon as the view was returned.
This was largely fine as the TextureStorage resources were being kept alive by the views holding their own references to them, but it also meant that dispose is only called as soon as the texture is created.
Aliased Storages are TextureStorages created with the same allocation as another TextureStorage, if they have to be aliased as another format. We keep track of a TextureStorage's `_aliasedStorages` as they are created, and dispose them when the TextureStorage is disposed...
...except it is disposed immediately, before any aliased storages are even created. The aliased storages added after this will never be disposed.
This PR attempts to fix this by disposing TextureStorage when its view count reaches 0. The other use of texture storage - the D32S8 blit - still manually disposes the storage, but regular uses created via the GAL are now disposed by the view count.
I think this makes the most sense, as otherwise in the future this behaviour might be forgotton and more things could be added to the Dispose() method that don't work due to it not actually calling at the right time.
This should improve memory leaks in Super Mario Odyssey, most noticeable when resolution scaling. The memory usage of the game is still wildly unpredictable due to how it interacts with the texture cache, but now it shouldn't get considerably longer as you play... I hope. I've seen it typically recover back to the same level occasionally, though it can spike significantly.
Please test a bunch of games on multiple GPUs to make sure this doesn't break anything.
* Fix various issues caused by #3679
- The arguments for the 0th dummy vertex buffer were incorrect - it was given an offset of 16 rather than a size of 16.
- The wrong size was used when doing `autoBuffer.Get` on a converted vertex buffer.
- The possibility of a vertex buffer being disposed and then rebound can rebindings to find a different buffer where the current range is out of bounds. Avoid binding when out of range to prevent validation errors.
- The above also affects generation of converted buffers, which was a bit more fatal. Conversion functions now attempt to bound input offset/size.
* Fix offset for converted buffer
Luigi's Mansion 3 performs a non-index quads draw with 6 vertices. It's meant to ignore the last two, but the index pattern's primitive count calculation was rounding up.
No idea why the game does this but this should fix random triangles in the map.
* GPU: Pass SpanOrArray for Texture SetData to avoid copy
Texture data is often converted before upload, meaning that an array was allocated to perform the conversion into. However, the backend SetData methods were being passed a Span of that data, and the Multithreaded layer does `ToArray()` on it so that it can be stored for later! This method can't extract the original array, so it creates a copy.
This PR changes the type passed for textures to a new ref struct called SpanOrArray, which is backed by either a ReadOnlySpan or an array. The benefit here is that we can have a ToArray method that doesn't copy if it is originally backed by an array.
This will also avoid a copy when running the ASTC decoder.
On NieR this was taking 38% of texture upload time, which it does a _lot_ of when you move between areas, so there should be a 1.6x performance boost when strictly uploading textures. No doubt this will also improve texture streaming performance in UE4 games, and maybe a small reduction with video playback.
From the numbers, it's probably possible to improve the upload rate by a further 1.6x by performing layout conversion on GPU. I'm not sure if we could improve it further than that - multithreading conversion on CPU would probably result in memory bottleneck.
This doesn't extend to buffers, since we don't convert their data on the GPU emulator side.
* Remove implicit cast to array.
* Fix some issues with CacheByRange
- Cache now clears under more circumstances, the most important being the fast path write.
- Cache supports partial clear which should help when more buffers join.
- Fixed an issue with I8->I16 conversion where it wouldn't register the buffer for use on dispose.
Should hopefully fix issues with https://github.com/Ryujinx/Ryujinx-Games-List/issues/4010 and maybe others.
* Fix collection modified exception
* Fix accidental use of parameterless constructor
* Replay DynamicState when restoring from helper shader
* Zero blend state when disabled or write mask is 0
Any difference in the blend state when blend is disabled is meaningless, but Ryujinx would compare different disabled blends and compile them as separate pipelines. This change ensures that all pipelines where blend state is meaningless record it as such, which avoids compiling a bunch of pipelines that are essentially identical.
The NVIDIA driver is pretty forgiving when it comes to silly pipeline misses like this, but other drivers don't offer the same level of kindness.
This should reduce stuttering on those drivers, and might improve overall performance very slightly due to less pipeline variants being in the hash table.
* Fix blend possibly being wrong when an attachment is unmasked
* Add Index Buffer conversion for quads to Vulkan
Also adds a reusable repeating pattern index buffer to use for non-indexed
draws, and generalizes the conversion cache for buffers.
* Fix some issues
* End render pass before conversion
* Resume transform feedback after we ensure we're in a pass.
* Always generate UInt32 type indices for topology conversion
* No it's not.
* Remove unused code
* Rely on TopologyRemap to convert quads to tris.
* Remove double newline
* Ensure render pass ends before stride or I8 conversion
* Periodically Flush Commands for Vulkan
NVIDIA's OpenGL driver has a built-in mechanism to automatically flush commands to GPU when a lot have been queued. It's also pretty inconsistent, but we'll ignore that for now.
Our Vulkan implementation only submits a command buffer (flush equivalent) when it needs to. This is typically when another command buffer needs to be sequenced after it, presenting a frame, or an edge case where we flush around GPU queries to get results sooner.
This difference in flush behaviour causes a notable difference between Vulkan and OpenGL when we have to wait for commands. In the worst case, we will wait for a sync point that has just been created. In Vulkan, this sync point is created by flushing the command buffer, and storing a waitable fence that signals its completion. Our command buffer contains _every command that we queued since the last submit_, which could be an entire frame's worth of draws.
This has a huge effect on CPU <-> GPU latency. The more commands in a command buffer, the longer we have to wait for it to complete, which results in wasted time. Because we don't know when the guest will force us to wait, we always want the smallest possible latency.
By periodically flushing, we ensure that each command buffer takes a more consistent, smaller amount of time to execute, and that the back of the GPU queue isn't as far away when we need to wait for something to happen. This also might reduce time that the GPU is left inactive while commands are being built.
The main affected game is Pokemon Sword, which got significantly faster in overworld areas due to reduced waiting time when it flushes a shadow map from the main GPU thread.
Another affected game is BOTW, which gets faster depending on the area. This game flushes textures/buffers from its game thread, which is the bottleneck.
Flush latency and throughput may be improved on other games that are inexplicably slower than OpenGL. It's possible that certain games could have their performance _decreased_ slightly due to flushes not being free, but it is unlikely.
Also, flushing to get query results sooner has been tweaked to improve the number of full draw skips that can be done. (tested in SMO)
* Remove unused variable
* Fix possible issue with early query flush
* Scale SamplesPassed counter by RT scale on report
Adds a scale factor for samples passed counter report based on the render target scale at the time. This ensures that when a game reads this counter, it appears similar to the result at 1x.
This doesn't cover cases where the the render target scale changes during the queried draws, though that might be better to handle along with other scope related issues in a future rework of counters. Games generally don't count for occlusion queries over render target changes anyways.
Fixes an issue in the Splatoon games where the special charge would scale too quickly at high res, points at the end of the game would be broken (but still provide a correct winner), and playing at a low res would make it impossible to swim in ink.
May also affect LOD scaling in The Witcher 3.
* Update Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
* Vertex Buffer Alignment part 1
* Update CacheByRange
* Add Stride Change compute shader, fix storage buffers in helpers
* An AMD exclusive
* Reword
* Change rules - stride conversion when attrs misalign
* Fix stupid mistake
* Fix background pipeline compile
* Improve a few things.
* Fix some feedback
* Address Feedback
(the shader binary didn't change when i changed the source to use the subgroup size)
* Fix bug where rewritten buffer would be disposed instantly.
This was broken by the Vulkan changes - OpenGL was building host caches at boot on one thread, which is very notably slower than when it is multithreaded.
This was caused by trying to get the program binary immediately after compilation started, which blocks. Now it does it after compilation has completed.
* SPIR-V: Initialize undefined variables with a value
Changes undefined values on spir-v shaders (caused by phi nodes) to be initialized instead of truly undefined.
Fixes an issue with NVIDIA gpus seemingly not liking when a variable is _potentially_ undefined. Not sure about the details at the moment.
Fixes:
- Tilt shift blur effect in Link's Awakening (bottom of the screen)
- Potentially block flickering on newer NVIDIA gpus in Splatoon 2? Needs testing.
Testing is welcome.
* Update Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
* Initial commit with a lot of testing stuff.
* Partial Unmap Cleanup Part 1
* Fix some minor issues, hopefully windows tests.
* Disable partial unmap tests on macos for now
Weird issue.
* Goodbye magic number
* Add COMPlus_EnableAlternateStackCheck for tests
`COMPlus_EnableAlternateStackCheck` is needed for NullReferenceException handling to work on linux after registering the signal handler, due to how dotnet registers its own signal handler.
* Address some feedback
* Force retry when memory is mapped in memory tracking
This case existed before, but returning `false` no longer retries, so it would crash immediately after unprotecting the memory... Now, we return `true` to deliberately retry.
This case existed before (was just broken by this change) and I don't really want to look into fixing the issue right now. Technically, this means that on guest code partial unmaps will retry _due to this_ rather than hitting the handler. I don't expect this to cause any issues.
This should fix random crashes in Xenoblade Chronicles 2.
* Use IsRangeMapped
* Suppress MockMemoryManager.UnmapEvent warning
This event is not signalled by the mock memory manager.
* Remove 4kb mapping
Some games and the Mario Odyssey Multiplayer mod do this.
The SMO multiplayer mod also needs you to revert #3394 as it uses a blocking socket to receive (otherwise it hangs), and it doesn't seem to like being forced as non-blocking.
* Changes 1
* Changes 2
* Better ModifiedSequence handling
This should handle PreciseEvents properly, and simplifies a few things.
* Minor changes, remove debug log
* Handle stage.Info being null
Hopefully fixes Catherine crash
* Fix shader specialization fast texture lookup
* Fix some things.
* Address Feedback Part 1
* Make method static.
* Prefetch capabilities before spawning translation threads.
The Backend Multithreading only expects one thread to submit commands at a time. When compiling shaders, the translator may request the host GPU capabilities from the backend. It's possible for a bunch of translators to do this at the same time.
There's a caching mechanism in place so that the capabilities are only fetched once. By triggering this before spawning the thread, the async translation threads no longer try to queue onto the backend queue all at the same time.
The Capabilities do need to be checked from the GPU thread, due to OpenGL needing a context to check them, so it's not possible to call the underlying backend directly.
* Initialize the capabilities when setting the GPU thread + missing call in headless
* Remove private variables
This PR adds the alternative enum values for StencilOp. Similar to the other enums, I added these with the same names but with Gl added to the end. These are used by homebrew using Nouveau, though they might be used by games with the official Vulkan driver.
https://github.com/envytools/envytools/blob/39d90be897f41434d67277ebdf244d6bd419ecd9/rnndb/graph/nv_3ddefs.xml#L77
Fixes some broken graphics in Citra, such as missing shadows in Mario Kart 7. Likely fixes other homebrew.
If two or more threads encounter a region of memory where a read action has been registered, then they must _both_ wait on the data.
Clearing the action before it completed was causing the null check above to fail, so the action would only be run on the first thread, and the second would end up continuing without waiting. Depending on what the game does, this could be disasterous.
This fixes a regression introduced by #3302 with Pokemon Legends Arceus, and possibly Catherine. There are likely other affected games. What is fixed in that PR should still be fixed.
* Fix various issues with texture sync
A variable called _actionRegistered is used to keep track of whether a tracking action has been registered for a given texture group handle. This variable is set when the action is registered, and should be unset when it is consumed. This is used to skip registering the tracking action if it's already registered, saving some time for render targets that are modified very often.
There were two issues with this. The worst issue was that the tracking action handler exits early if the handle's modified flag is false... which means that it never reset _actionRegistered, as that was done within the Sync() method called later. The second issue was that this variable was set true after the sync action was registered, so it was technically possible for the action to run immediately, set the flag to false, then set it to true.
Both situations would lead to the action never being registered again, as the texture group handle would be sure the action is already registered. This breaks the texture for the remaining runtime, or until it is disposed.
It was also possible for a texture to register sync once, then on future frames the last modified sync number did not update. This may have caused some more minor issues.
Seems to fix the Xenoblade flashing bug. Obviously this needs a lot of testing, since it was random chance. I typically had the most luck getting it to happen by switching time of day on the event theatre screen for a while, then entering the equipment screen by pressing X on an event.
May also fix weird things like random chance air swimming in BOTW, maybe a few texture streaming bugs.
* Exchange rather than CompareExchange
OpenGL game overlays and hooks tend to make a lot of assumptions about how games present frames to the screen, since presentation in OpenGL kind of sucks and they would like to have info such as the size of the screen, or if the contents are SRGB rather than linear.
There are two ways of getting this. OBS hooks swap buffers to get a frame for video capture, but it actually checks the bound framebuffer at the time. I made sure that this matches the output framebuffer (the window) so that the output matches the size. RTSS checks the viewport size by default, but this was actually set to the last used viewport by the game, causing the OSD to fly all across the screen depending on how it was used (or res scale). The viewport is now manually set to match the output framebuffer size.
In the case of RTSS, it also loads its resources by destructively setting a pixel pack parameter without regard to what it was set to by the guest application. OpenGL state can be set for a long period of time and is not expected to be set before each call to a method, so randomly changing it isn't great practice. To fix this, I've added a line to set the pixel unpack alignment back to 4 after presentation, which should cover RTSS loading its incredibly ugly font.
- RTSS and overlays that use it should no longer cause certain textures to load incorrectly. (mario kart 8, pokemon legends arceus)
- OBS Game Capture should no longer crop the game output incorrectly, flicker randomly, or capture with incorrect gamma.
This doesn't fix issues with how RTSS reports our frame timings.
This should prevent filesystem services from blocking other services that don't have their own ServerBase. May improve filesystem related stutters in certain titles.
Improves button advanced cutscenes such as Miqol's Request in Xenoblade: DE when the game is on a network share (used to stutter when voice lines played).
Should probably be tested to make sure no mysterious bugs have been unearthed, and to see if any other filesystem related perf issues are improved.
Before, it was selecting nearest neighbour, which sounded terrible. This is likely temporary til the upsampling algorithm used by the switch is reversed.
Fixes bad audio in Skyward Sword HD.
* Add timestamp to 16-byte semaphore releases.
BOTW was reading a ulong 8 bytes after a semaphore return. Turns out this is the timestamp it was trying to do performance calculation with, so I've made it write when necessary.
This mode was also added to the DMA semaphore I added recently, as it is required by a few games. (i think quake?)
The timestamp code has been moved to GPU context. Check other games with an unusually low framerate cap or dynamic resolution to see if they have improved.
* Cast dma semaphore payload to ulong to fill the space
* Write timestamp first
Might be just worrying too much, but we don't want the applcation reading timestamp if it sees the payload before timestamp is written.
This fixes an issue where the render scale array would not be updated when technically the scales on the flat array were the same, but the start index for the vertex scales was different.
This fixes a rare bug where reporting a counter for a region containing 0 draws could deadlock the GPU. If this write overlaps with a tracking action, then the GPU could end up waiting on something that it's meant to do in the future, so it would just get stuck.
Before, this reported immediately and wrote the result to guest memory (tracked) from the backend thread.
The backend thread cannot be allowed to trigger read actions that wait on the GPU, as it will end up waiting on itself, and never advancing.
In the case of backend multithreading's `SyncMap`, it would try to wait for a backend sync object that does not yet exist, as the sync object would exist according to the GPU and tracking, but it has not yet been created by the backend (and never will be, since it's stuck).
The fix is to queue the 0 draw event just like any other, its _bufferMap value is just forced to 0.
This affects games that use Conditional Rendering: SMO, Splatoon 2, MK8. Was generally indicated by a red message in log saying that the query result timed out after 5000 tries, but not always the cause.
This fixes some regressions caused by #2971 which caused rendered 3D texture data to be lost for most slices. Fixes issues with Xenoblade 2's colour grading, probably a ton of other games.
This also removes the check from TextureCache, making it the tiniest bit smaller (any win is a win here).
* Initial test for texture sync
* WIP new texture flushing setup
* Improve rules for incompatible overlaps
Fixes a lot of issues with Unreal Engine games. Still a few minor issues (some caused by dma fast path?) Needs docs and cleanup.
* Cleanup, improvements
Improve rules for fast DMA
* Small tweak to group together flushes of overlapping handles.
* Fixes, flush overlapping texture data for ASTC and BC4/5 compressed textures.
Fixes the new Life is Strange game.
* Flush overlaps before init data, fix 3d texture size/overlap stuff
* Fix 3D Textures, faster single layer flush
Note: nosy people can no longer merge this with Vulkan. (unless they are nosy enough to implement the new backend methods)
* Remove unused method
* Minor cleanup
* More cleanup
* Use the More Fun and Hopefully No Driver Bugs method for getting compressed tex too
This one's for metro
* Address feedback, ASTC+ETC to FormatClass
* Change offset to use Span slice rather than IntPtr Add
* Fix this too
* Add support for render scale to vertex stage.
Occasionally games read off textureSize on the vertex stage to inform the fragment shader what size a texture is without querying in there. Scales were not present in the vertex shader to correct the sizes, so games were providing the raw upscaled texture size to the fragment shader, which was incorrect.
One downside is that the fragment and vertex support buffer description must be identical, so the full size scales array must be defined when used. I don't think this will have an impact though. Another is that the fragment texture count must be updated when vertex shader textures are used. I'd like to correct this so that the update is folded into the update for the scales.
Also cleans up a bunch of things, like it making no sense to call CommitRenderScale for each stage.
Fixes render scale causing a weird offset bloom in Super Mario Party and Clubhouse Games. Clubhouse Games still has a pixelated look in a number of its games due to something else it does in the shader.
* Split out support buffer update, lazy updates.
* Commit support buffer before compute dispatch
* Remove unnecessary qualifier.
* Address Feedback
Rather than calculating this for every sampler, this PR calculates if a texture can force anisotropy when its info is set, and exposes the value via a public boolean.
This should help texture/sampler heavy games when anisotropic filtering is not Auto, like UE4 ones (or so i hear?). There is another cost where samplers are created twice when anisotropic filtering is enabled, but I'm not sure how relevant this one is.
* Limit Custom Anisotropic Filtering to only fully mipmapped textures
There's a major flaw with the anisotropic filtering setting that causes @GamerzHell9137 to report graphical bugs that otherwise wouldn't be there, because he just won't set it to Auto. This should fix those issues, hopefully.
These bugs are generally because anisotropic filtering is enabled on something that it shouldn't be, such as a post process filter or some data texture. This PR maintains two host samplers when custom AF is enabled, and only uses the forced AF one when the texture is 2d and fully mipmapped (goes down to 1x1). This is because game textures are the ideal target for this filtering, and they are typically fully mipmapped, unlike things like screen render targets which usually have 1 or just a few levels.
This also only enables AF on mipmapped samplers where the filtering is bilinear or trilinear. This should be self explanatory.
This PR also allows the changing of Anisotropic Filtering at runtime, and you can immediately see the changes. All samplers are flushed from the cache if the setting changes, causing them to be recreated with the new custom AF value. This brings it in line with our resolution scale. 😌
* Expected minimum mip count for large textures rather than all, address feedback
* Use Target rather than Info.Target
* Retrigger build?
* Fix rebase
* Another workaround for NVIDIA driver 496.13 shader bug
This might work better than the other one. Give this a test to see if it fixes/doesn't fix issues with the other one.
The problem seems to be when any variable assignment happens with a negation. `temp_1 = -temp_0;` seems to trigger weird behaviour, but `temp_1 = 0.0 - temp_0;` does not. This also might to extend towards integer types?
* Update cache version
* Add disclaimer comment
* Wording