Currently, when immediately compile shaders is not enabled, the
ubershaders will be placed before any specialized shaders in the compile
queue in hybrid ubershaders mode. This means that Dolphin could
potentially use the ubershaders for a longer time than it would have if
we blocked startup until all shaders were compiled, leading to a drop in
performance.
- In D3D, shaders could be compiled on the main thread, blocking
startup.
- Reduced the latency between a pipeline being requested and used in all
backends in hybrid ubershader mode, when no shader stages were present.
- Fixed a case where async compilation could cause the same UID to be
appended multiple times to the UID cache.
- Fix incorrect number of threads being used when immediately compile
shaders was enabled.
Lowest hanging fruit I could find with a profiler.
Not sure this stuff actually needs to be done, but assuming it is, why
not do it quickly? 10x faster, goes from 1% CPU to 0.09%.
This enables shaders to be compiled while the game is starting, instead
of blocking startup. If a shader is needed before it is compiled,
emulation will block.
As these are stored in a map, operator< will become a hot function when
doing lookups, which happen every frame. std::tie generated a rather
large function here with quite a few branches.
tl;dr: This PR speedups dolphin on mobiles with the Mali GPU and ES 3.2
drivers by a factor of 10 by using the method with the biggest overhead.
Please keep care not to buy this shit!
The ARM driver team seems to care very well about their customers. But
bad luck, users and open source developers are *not* their customers. So
even device-independent feature requests are just ignored for *years*:
https://community.arm.com/graphics/f/discussions/4645/gl_ext_buffer_storage-support
The bad point, they neither implement any of the other common ways to
stream dynamic content in unextented GL:
- They just ignore the GL_MAP_UNSYNCHRONIZED_BIT flag
- They don't support on-device buffer updates and just stall with
glBufferSubData
It seems like no benchmark is using any dynamic content - and like no
customer cares about anything but benchmarks, or users...
We have a flag to disable the glBufferSubData way, this PR adds the flag
to also disable the unsychronized mapping way. The second one is
available since their ES 3.2 update, but slow as hell.
So how to continue? The last remaining technical way to stream dynamic
content at all is to alloc a new buffer per draw call with glBufferData.
This is very gross, but still a factor 10 speedup compared to stalling
the GPU. Small tests shows that you can expect another 3-5 times speedup
with EXT_buffer_data, so Mali would be on pair with Adreno here. So if
you have bought such a device unfortunately, please try to make noise on
your vendor forums/support and ask for this extension. If you are going
to buy a new mobile, I'd recormend to avoid *any* mobile with a Mali GPU
in it.
We now differentiate between a resize event and surface change/destroyed
event, reducing the overhead for resizes in the Vulkan backend. It is
also now now safe to change the surface multiple times if the video thread
is lagging behind.
The option is named DisableCopyToVRAM under the Hacks section in
GFX.ini. It is intentionally not exposed to the GUI, as users should not
need to use it under normal circumstances. The main use is debugging
issues in the EFB-to-RAM shaders.
The console appears to behave against standard IEEE754 specification
here, in particular around how NaNs are handled. NaNs appear to have no
effect on the result, and are treated the same as positive or negative
infinity, based on the sign bit.
However, when the result would be NaN (inf - inf, or (-inf) - (-inf)),
this results in a completely fogged color, or unfogged color
respectively. We handle this by returning a constant zero for the A
varaible, and positive or negative infinity for C depending on the sign
bits of the A and C registers. This ensures that no NaN value is passed
to the GPU in the first place, and that the result of the fog
calculation cannot be NaN.
Otherwise we might get UB if the value we cast is larger than the
max value of the underlying type that the compiled picked for the enum.
I haven't done any extensive check through Dolphin to find cases
of this, I'm just fixing the cases I already know of.
Tested on a linux Intel Skylake integrated graphics with
blend_func_extended force-disabled, as it's the only platform I have
that doesn't crash with ubershaders and supports fb_fetch
It seems it doesn't like modifying inout variables in place - so instead
use a temporary for ocol0/ocol1 and only write them once at the end of
the shader
GLES doesn't support C-style array initialisers, so stuff like:
Type var[2] = {
VALUE_A,
VALUE_B
};
isn't supported in GLES (it was added in
GL_ARB_shading_language_420pack).
The texture conversion shader used this, so would fail to compile on
GLES.
HLSL does not define roundEven(), only round(). This means that the
output may differ slightly for OpenGL vs Direct3D. However, it ensures
consistency across OpenGL drivers, as round() in GLSL can go either way.
This fixes the rendering of the scan visor in Metroid Prime 2: Echoes,
as seen in https://fifoci.dolphin-emu.org/dff/mp2-scanner/
The alpha channel was off-by-one on Ivy Bridge due to the rounding
after multiplication with colmat. This commit removes this matrix
altogether in most cases, making them simple GLSL swizzles.
This will generate one shader per copy format. For now, it is the same
shader with the colmat hard coded. So it should already improve the GPU
performance a bit, but a rewrite of the shader generator is suggested.
Half of the patch is done by linkmauve1:
VideoCommon: Reorganise the shader writes.
Also skips swapping the window system buffers in headless mode, as there
may not be a surface which can be swapped in the first place. Instead,
we call glFlush() at the end of a frame in this case.
Cel-damage uses the color from the lighting stage of the vertex pipeline
as texture coordinates, but sets numColorChans to zero.
We now calculate the colors in all cases, but override the color before
writing it from the vertex shader if numColorChans is set to a lower value.
This is already initialized in the class definition. This would
previously cause a -Wreorder warning on macOS, as m_config is
defined after m_currently_mapped.
We need this because VS currently doesn't consider
std::is_trivially_copyable<typename
std::remove_volatile<SCPFifoStruct>::type>::value
to be true and because no compiler should consider it
to be true if we replace the volatiles with atomics.
Some lines of code in Dolphin just plainly grabbed the value of
g_ActiveConfig.iEFBScale, which resulted in Auto being treated as
0x rather than the actual automatically selected scale.
There was a race condition between the video thread and the host thread,
if corrections need to be made by VerifyValidity(). Briefly, the config
will contain invalid values. Instead, pause emulation first, which will
flush the video thread, update the config and correct it, then resume
emulation, after which the video thread will detect the config has
changed and act accordingly.
Calling vkCmdClearAttachments with a partial rect, or specifying a
render area in a render pass with the load op set to clear can cause the
GPU to lock up, or raise a bounds violation. This only occurs on MSAA
framebuffers, and it seems when there are multiple clears in a single
command buffer. Worked around by back to the slow path (drawing quads)
when MSAA is enabled.
Currently, this is only the logic op bit, but this will be extended to
the framebuffer fetch/blend modes. In the future, when/if we move to
VideoCommon pipelines, this state will be part of the pipeline UID
anyway, and we can mask it out in the backend by using a two-level map,
so the shaders/programs are shared.
This optimisation doesn't work on PowerVR's Vulkan implementation. We
(incorrectly) disallow Framebuffer objects to be used with a different
load or store op than that which they were created with, despite the
spec allowing such.
This fixes the windwaker intro "smearing"
Modernizes the arrays and makes future simplifications possible (e.g. usages within the software renderer).
It also makes cases where we use array->pointer decay explicit.
The class NonCopyable is, like the name says, supposed to disallow
copying. But should it allow moving?
For a long time, NonCopyable used to not allow moving. (It declared
a deleted copy constructor and assigment operator without declaring
a move constructor and assignment operator, making the compiler
implicitly delete the move constructor and assignment operator.)
That's fine if the classes that inherit from NonCopyable don't need
to be movable or if writing the move constructor and assignment
operator by hand is fine, but that's not the case for all classes,
as I discovered when I was working on the DirectoryBlob PR.
Because of that, I decided to make NonCopyable movable in c7602cc,
allowing me to use NonCopyable in DirectoryBlob.h. That was however
an unfortunate decision, because some of the classes that inherit
from NonCopyable have incorrect behavior when moved by default-
generated move constructors and assignment operators, and do not
explicitly delete the move constructors and assignment operators,
relying on NonCopyable being non-movable.
So what can we do about this? There are four solutions that I can
think of:
1. Make NonCopyable non-movable and tell DirectoryBlob to suck it.
2. Keep allowing moving NonCopyable, and expect that classes that
don't support moving will delete the move constructor and
assignment operator manually. Not only is this inconsistent
(having classes disallow copying one way and disallow moving
another way), but deleting the move constructor and assignment
operator manually is too easy to forget compared to how tricky
the resulting problems are.
3. Have one "MovableNonCopyable" and one "NonMovableNonCopyable".
It works, but it feels rather silly...
4. Don't have a NonCopyable class at all. Considering that deleting
the copy constructor and assignment operator only takes two lines
of code, I don't see much of a reason to keep NonCopyable. I
suppose that there was more of a point in having NonCopyable back
in the pre-C++11 days, when it wasn't possible to use "= delete".
I decided to go with the fourth one (like the commit title says).
The implementation of the commit is fairly straight-forward, though
I would like to point out that I skipped adding "= delete" lines
for classes whose only reason for being uncopyable is that they
contain uncopyable classes like File::IOFile and std::unique_ptr,
because the compiler makes such classes uncopyable automatically.
The switch statements in these functions appear to get transformed into
an if..else chain on NVIDIA's OpenGL/Vulkan drivers, resulting in lower
performance than the D3D counterparts. Transforming the switch into a
binary tree of ifs can increase performance by up to 20%.
Settings that come from the SYSCONF are now included in Dolphin's
config system as part of the base layer. They are handled in a
special way compared to other settings to make sure they are only
loaded from and saved to the SYSCONF (to avoid different, possibly
contradicting sources of truth).
This was breaking Metroid Prime 2: Echoes’s scanner in some rooms, such
as the one in https://fifoci.dolphin-emu.org/dff/mp2-scanner/
It was found on Ivy Bridge on Mesa, the alpha value read back from the
EFB was off-by-4 in multiple objects, which was a conversion error
because int4() is equivalent to floor() and the value wasn’t always
higher.
This is supposed to get efb2tex to the same texture as efb2ram, by applying the related efb copies as updates after each other, in the order of their creation.
Improve bookkeeping around formats. Hopefully make code less confusing.
- Rename TlutFormat -> TLUTFormat to follow conventions.
- Use enum classes to prevent using a Texture format where an EFB Copy format
is expected or vice-versa.
- Use common EFBCopyFormat names regardless of depth and YUV configurations.
This was mainly included for debugging, but could end up being confusing
for users, as well as polluting the GL program cache with a mix of uber
and specialized shaders if the option was changed.
These vertex formats enable all attributes. Inactive attributes are set
to offset=0, and the smallest type possible. This "optimization" stops
the NV compiler from generating variants of vertex shaders.
This is a remake of https://github.com/dolphin-emu/dolphin/pull/3749
Full credit goes to phire.
Old message:
"If none of the texture registers have changed and TMEM hasn't been invalidated or changed in other ways, we can blindly reuse the old texture cache entries without rehashing.
Not only does this fix the bloom effect in Spyro: A Hero's Tail (The game abused texture cache) but it will also provide speedups for other games which use the same texture over multiple draw calls, especially when safe texture cache is in use."
Changed the pr per phire's instructions to only return the current texture(s) if none of the texture registers were changed. If any texture register was changed, fall back to the default hashing and rebuilding textures from memory.
Some code was calling more than one of these functions in a row
(in particular, FileUtil.cpp itself did it a lot...), which is
a waste since it's possible to call stat a single time and then
read all three values from the stat struct. This commit adds a
File::FileInfo class that calls stat once on construction and
then lets Exists/IsDirectory/GetSize be executed very quickly.
The performance improvement mostly matters for functions that
can be handling a lot of files, such as File::ScanDirectoryTree.
I've also done some cleanup in code that uses these functions.
For instance, some code had checks like !Exists() || !IsDirectory(),
which is functionally equivalent to !IsDirectory(), and some
code was using File::GetSize even though there was an IOFile
object that the code could call GetSize on.
This fixes the global-static fifo object causing infinite hangs in some
cases. Notably, failure to initialize a graphics backend would result in
BlockingLoop::Prepare being called but never executing Run(), leaving the
object in a bad state.
This code hadn't been touched since 2010. Nowadays, the panic alert
setting is loaded by ConfigManager and applied in UICommon.
VideoConfig has no business messing with it.
Use @Orphis's FindFFmpeg module from ppsspp:
2149d3db7f
From that commit:
> This new module should be able to handle both libraries in the regular
> paths and fallback to pkg-config.
> It is also able to find dynamic libraries, not just static libraries.
> It will generate imported targets with the name FFmpeg::<lib> that you
> can use in your scripts.
This removes the need for multiple texture files to store the mipmap
chain for a texture. As many mipmaps will be loaded as are present in
the DDS file, and any remaining mipmaps will fall back to the old
behavior.
This is because we re-use BlendingState for our internal drawing (e.g.
RasterFont) and for these shaders, we can't assume the presence of a
second color output.
Currently, we use the alpha channel from the EFB even if the current
format does not include an alpha channel. Now, the alpha channel is set
to 1 if the format does not have an alpha channel, as well as truncating
to 5/6 bits per channel. This matches the EFB-to-texture behavior.
Some widescreen hacks (see below) properly force anamorphic output, but
don't make the last projection in a frame 16:9, so Dolphin doesn't
display it correctly.
This changes the heuristic code to assume a frame is anamorphic based on
the total number of vertex flushes in 4:3 and 16:9 projections that
frame. It also adds a bit of "aspect ratio inertia" by making it harder
to switch aspect ratios, which takes care of aspect ratio flickering
that some games / widescreen hacks would be susceptible with the new
logic.
I've tested this on SSX Tricky's native anamorphic support, Tom Clancy's
Splinter Cell (it stayed in 4:3 the whole time), and on the following
widescreen hacks for which the heuristic doesn't currently work:
Paper Mario: The Thousand-Year Door (Gecko widescreen code from Nintendont)
C202F310 00000003
3DC08042 3DE03FD8
91EEF6D8 4E800020
60000000 00000000
04199598 4E800020
C200F500 00000004
3DE08082 3DC0402B
61CE12A2 91CFA1BC
60000000 387D015C
60000000 00000000
C200F508 00000004
3DE08082 3DC04063
61CEE8D3 91CFA1BC
60000000 7FC3F378
60000000 00000000
The Simpsons: Hit & Run (AR widescreen code from the wiki)
04004600 C002A604
04004604 C09F0014
04004608 FC002040
0400460C 4082000C
04004610 C002A608
04004614 EC630032
04004618 48220508
04041A5C 38600001
04224344 C002A60C
04224B1C 4BDDFAE4
044786B0 3FAAAAAB
04479F28 3FA33333
Fixes bug #10183 [0] introduced by 3bd184a / PR #4467 [1].
TextureCacheBase was no longer calling `entry->Load` for custom textures
since the compute shader decoding logic was added. This adds it back in.
It also slightly restructures the decoding if-group to match the one
below, which I think makes the logic more obvious.
(recommend viewing with `git diff -b` to ignore the indentation changes)
[0]: https://bugs.dolphin-emu.org/issues/10183
[1]: https://github.com/dolphin-emu/dolphin/pull/4467
New Super Mario Bros on PAL still renders at 60 fps, but skips every 5th XFB copy.
So our detection of "per frame" fails, and we require twice the amound of texture objects.
But our pool frees unused textures after 3 frames, so half of them needs to be reallocated
every few frames.
This commit removes the lock for render targets. It was introduced to not update a texture
while it is still in use. But render targets aren't updated while rendering, so this
lock isn't needed. Non-rendertarget textures however aren't as dynamic, so the lock should
have no performance update.
This stops the virtual method call from within the Renderer constructor.
The initialization here for GL had to be moved to VideoBackend, as the
Renderer constructor will not have been executed before the value is
required.
This moves all the byte swapping utilities into a header named Swap.h.
A dedicated header is much more preferable here due to the size of the
code itself. In general usage throughout the codebase, CommonFuncs.h was
generally only included for these functions anyway. These being in their
own header avoids dumping the lesser used utilities into scope. As well
as providing a localized area for more utilities related to byte
swapping in the future (should they be needed). This also makes it nicer
to identify which files depend on the byte swapping utilities in
particular.
Since this is a completely new header, moving the code uncovered a few
indirect includes, as well as making some other inclusions unnecessary.
Using the AVCodecContext contained in AVStream for muxing is officially
discouraged[1] and AVStream::codec was deprecated in favor of
AVStream::codecpar in libavformat 57.33.100 / 57.5.0.
1: [FFmpeg-cvslog] lavf: replace AVStream.codec with AVStream.codecpar: https://ffmpeg.org/pipermail/ffmpeg-cvslog/2016-April/099152.html
Keeps associated data together. It also eliminates the possibility of out
parameters not being initialized properly. For example, consider the
following example:
-- some FramebufferManager implementation --
void FBMgrImpl::GetTargetSize(u32* width, u32* height) override
{
// Do nothing
}
-- somewhere else where the function is used --
u32 width, height;
framebuffer_manager_instance->GetTargetSize(&width, &height);
if (texture_width != width) <-- Uninitialized variable usage
{
...
}
It makes it much more obvious to spot any initialization issues, because
it requires something to be returned, as opposed to allowing an
implementation to just not do anything.
From what I can tell, the emulated GPU places (0,0) at the lower left of
the image, and we were generating texture coordinates so that (0,0) was
at the upper-left in the expansion geometry shader, causing textures
used by point sprites to be flipped vertically.
Fixes the upside-down A button in Mario Golf.
These provide the same semantics, however aggregate initialization
doesn't force the structs to be trivially copyable. memset, on the other
hand, does.
Making changes to ConfigManager.h has always been a pain, because
it means rebuilding half of Dolphin, since a lot of files depend on
and include this header.
However, it turns out some includes are unnecessary. This commit
removes ConfigManager includes from files which don't contain
SConfig or GPUDeterminismMode or GPU_DETERMINISM (which means the
ConfigManager include is not used).
(I've also had to get rid of some indirect includes.)
This is mainly for potential Android fifoci usage, and thus is not
exposed anywhere in the UI. To enable, set DumpFramesAsImages under
Settings in GFX.ini.
This increase the performance of good backends a bit, but slows down the bads one a lot.
Let's fix those backends instead of forcing stupid memcpy in the common code.