Merge branch 'master' of https://github.com/dolphin-emu/dolphin into dolphin-emu-master

This commit is contained in:
Nayla Hanegan 2024-10-23 14:29:49 -04:00
commit 4bd7d38a77
1243 changed files with 15939 additions and 15402 deletions

View file

@ -101,7 +101,10 @@ public:
// Binds the backbuffer for rendering. The buffer will be cleared immediately after binding.
// This is where any window size changes are detected, therefore m_backbuffer_width and/or
// m_backbuffer_height may change after this function returns.
virtual void BindBackbuffer(const ClearColor& clear_color = {}) {}
// If this returns false, a problem occurred binding the backbuffer.
// Don't render anything to it, but still call `PresentBackbuffer`, which will reset any
// per-frame resources and prepare for the next frame.
virtual bool BindBackbuffer(const ClearColor& clear_color = {}) { return true; }
// Presents the backbuffer to the window system, or "swaps buffers".
virtual void PresentBackbuffer() {}

View file

@ -60,7 +60,6 @@ struct AbstractPipelineConfig
rhs.rasterization_state.hex, rhs.depth_state.hex, rhs.blending_state.hex,
rhs.framebuffer_state.hex, rhs.usage);
}
bool operator!=(const AbstractPipelineConfig& rhs) const { return !operator==(rhs); }
bool operator<(const AbstractPipelineConfig& rhs) const
{
return std::tie(vertex_format, vertex_shader, geometry_shader, pixel_shader,

View file

@ -151,7 +151,7 @@ ScissorResult::ScissorResult(const BPMemory& bpmemory, std::pair<float, float> v
}
auto cmp = [&](const ScissorRect& lhs, const ScissorRect& rhs) { return IsWorse(lhs, rhs); };
std::sort(m_result.begin(), m_result.end(), cmp);
std::ranges::sort(m_result, cmp);
}
ScissorRect ScissorResult::Best() const

View file

@ -594,22 +594,17 @@ void CommandProcessorManager::SetCpStatusRegister()
void CommandProcessorManager::SetCpControlRegister()
{
if (m_fifo.bFF_GPReadEnable.load(std::memory_order_relaxed) && !m_cp_ctrl_reg.GPReadEnable)
{
m_system.GetFifo().SyncGPUForRegisterAccess();
}
m_fifo.bFF_GPReadEnable.store(m_cp_ctrl_reg.GPReadEnable, std::memory_order_relaxed);
m_fifo.bFF_BPInt.store(m_cp_ctrl_reg.BPInt, std::memory_order_relaxed);
m_fifo.bFF_BPEnable.store(m_cp_ctrl_reg.BPEnable, std::memory_order_relaxed);
m_fifo.bFF_HiWatermarkInt.store(m_cp_ctrl_reg.FifoOverflowIntEnable, std::memory_order_relaxed);
m_fifo.bFF_LoWatermarkInt.store(m_cp_ctrl_reg.FifoUnderflowIntEnable, std::memory_order_relaxed);
m_fifo.bFF_GPLinkEnable.store(m_cp_ctrl_reg.GPLinkEnable, std::memory_order_relaxed);
if (m_fifo.bFF_GPReadEnable.load(std::memory_order_relaxed) && !m_cp_ctrl_reg.GPReadEnable)
{
m_fifo.bFF_GPReadEnable.store(m_cp_ctrl_reg.GPReadEnable, std::memory_order_relaxed);
m_system.GetFifo().FlushGpu();
}
else
{
m_fifo.bFF_GPReadEnable = m_cp_ctrl_reg.GPReadEnable;
}
DEBUG_LOG_FMT(COMMANDPROCESSOR, "\t GPREAD {} | BP {} | Int {} | OvF {} | UndF {} | LINK {}",
m_fifo.bFF_GPReadEnable.load(std::memory_order_relaxed) ? "ON" : "OFF",
m_fifo.bFF_BPEnable.load(std::memory_order_relaxed) ? "ON" : "OFF",

View file

@ -93,6 +93,7 @@ struct alignas(16) VertexShaderConstants
// .x - texMtxInfo, .y - postMtxInfo, [0..1].z = color, [0..1].w = alpha
std::array<uint4, 8> xfmem_pack1;
float4 cached_normal;
float4 cached_tangent;
float4 cached_binormal;
// For UberShader vertex loader

View file

@ -293,6 +293,10 @@ bool FramebufferManager::CreateEFBFramebuffer()
g_gfx->SetAndClearFramebuffer(m_efb_framebuffer.get(), {{0.0f, 0.0f, 0.0f, 0.0f}},
g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? 1.0f :
0.0f);
// Pixel Shader uses EFB scale as a constant, dirty that in case it changed
Core::System::GetInstance().GetPixelShaderManager().Dirty();
return true;
}
@ -760,9 +764,9 @@ bool FramebufferManager::CreateReadbackFramebuffer()
}
m_efb_color_cache.tiles.resize(total_tiles);
std::fill(m_efb_color_cache.tiles.begin(), m_efb_color_cache.tiles.end(), EFBCacheTile{false, 0});
std::ranges::fill(m_efb_color_cache.tiles, EFBCacheTile{false, 0});
m_efb_depth_cache.tiles.resize(total_tiles);
std::fill(m_efb_depth_cache.tiles.begin(), m_efb_depth_cache.tiles.end(), EFBCacheTile{false, 0});
std::ranges::fill(m_efb_depth_cache.tiles, EFBCacheTile{false, 0});
return true;
}

View file

@ -43,7 +43,6 @@ struct GXPipelineUid
{
return std::memcmp(this, &rhs, sizeof(*this)) == 0;
}
bool operator!=(const GXPipelineUid& rhs) const { return !operator==(rhs); }
};
struct GXUberPipelineUid
{
@ -64,7 +63,6 @@ struct GXUberPipelineUid
{
return std::memcmp(this, &rhs, sizeof(*this)) == 0;
}
bool operator!=(const GXUberPipelineUid& rhs) const { return !operator==(rhs); }
};
// Disk cache of pipeline UIDs. We can't use the whole UID as a type as it contains pointers.

View file

@ -330,8 +330,3 @@ void GraphicsModConfig::DeserializeFromProfile(const picojson::object& obj)
}
}
}
bool GraphicsModConfig::operator<(const GraphicsModConfig& other) const
{
return m_weight < other.m_weight;
}

View file

@ -43,6 +43,4 @@ struct GraphicsModConfig
void SerializeToProfile(picojson::object* value) const;
void DeserializeFromProfile(const picojson::object& value);
bool operator<(const GraphicsModConfig& other) const;
};

View file

@ -111,7 +111,7 @@ void GraphicsModGroupConfig::Load()
try_add_mod(graphics_mod_directory, GraphicsModConfig::Source::System);
}
std::sort(m_graphics_mods.begin(), m_graphics_mods.end());
std::ranges::sort(m_graphics_mods, {}, &GraphicsModConfig::m_weight);
for (auto& mod : m_graphics_mods)
{
m_path_to_graphics_mod[mod.GetAbsolutePath()] = &mod;

View file

@ -15,8 +15,3 @@ bool FBInfo::operator==(const FBInfo& other) const
return m_height == other.m_height && m_width == other.m_width &&
m_texture_format == other.m_texture_format;
}
bool FBInfo::operator!=(const FBInfo& other) const
{
return !(*this == other);
}

View file

@ -13,7 +13,6 @@ struct FBInfo
TextureFormat m_texture_format = TextureFormat::I4;
u32 CalculateHash() const;
bool operator==(const FBInfo& other) const;
bool operator!=(const FBInfo& other) const;
};
struct FBInfoHasher

View file

@ -398,40 +398,68 @@ Presenter::ConvertStereoRectangle(const MathUtil::Rectangle<int>& rc) const
float Presenter::CalculateDrawAspectRatio(bool allow_stretch) const
{
auto aspect_mode = g_ActiveConfig.aspect_mode;
float resulting_aspect_ratio;
if (!allow_stretch && aspect_mode == AspectMode::Stretch)
aspect_mode = AspectMode::Auto;
// If stretch is enabled, we prefer the aspect ratio of the window.
if (aspect_mode == AspectMode::Stretch)
return (static_cast<float>(m_backbuffer_width) / static_cast<float>(m_backbuffer_height));
{
resulting_aspect_ratio =
(static_cast<float>(m_backbuffer_width) / static_cast<float>(m_backbuffer_height));
}
else
{
// The actual aspect ratio of the XFB texture is irrelevant, the VI one is the one that matters
const auto& vi = Core::System::GetInstance().GetVideoInterface();
const float source_aspect_ratio = vi.GetAspectRatio();
// The actual aspect ratio of the XFB texture is irrelevant, the VI one is the one that matters
const auto& vi = Core::System::GetInstance().GetVideoInterface();
const float source_aspect_ratio = vi.GetAspectRatio();
// This will scale up the source ~4:3 resolution to its equivalent ~16:9 resolution
if (aspect_mode == AspectMode::ForceWide ||
(aspect_mode == AspectMode::Auto && g_widescreen->IsGameWidescreen()))
{
return SourceAspectRatioToWidescreen(source_aspect_ratio);
}
else if (aspect_mode == AspectMode::Custom)
{
return source_aspect_ratio * (g_ActiveConfig.GetCustomAspectRatio() / (4.0f / 3.0f));
}
// For the "custom stretch" mode, we force the exact target aspect ratio, without
// acknowleding the difference between the source aspect ratio and 4:3.
else if (aspect_mode == AspectMode::CustomStretch)
{
return g_ActiveConfig.GetCustomAspectRatio();
}
else if (aspect_mode == AspectMode::Raw)
{
return m_xfb_entry ? (static_cast<float>(m_last_xfb_width) / m_last_xfb_height) : 1.f;
// This will scale up the source ~4:3 resolution to its equivalent ~16:9 resolution
if (aspect_mode == AspectMode::ForceWide ||
(aspect_mode == AspectMode::Auto && g_widescreen->IsGameWidescreen()))
{
resulting_aspect_ratio = SourceAspectRatioToWidescreen(source_aspect_ratio);
}
else if (aspect_mode == AspectMode::Custom)
{
resulting_aspect_ratio =
source_aspect_ratio * (g_ActiveConfig.GetCustomAspectRatio() / (4.0f / 3.0f));
}
// For the "custom stretch" mode, we force the exact target aspect ratio, without
// acknowledging the difference between the source aspect ratio and 4:3.
else if (aspect_mode == AspectMode::CustomStretch)
{
resulting_aspect_ratio = g_ActiveConfig.GetCustomAspectRatio();
}
else if (aspect_mode == AspectMode::Raw)
{
resulting_aspect_ratio =
m_xfb_entry ? (static_cast<float>(m_last_xfb_width) / m_last_xfb_height) : 1.f;
}
else
{
resulting_aspect_ratio = source_aspect_ratio;
}
}
return source_aspect_ratio;
if (g_ActiveConfig.stereo_per_eye_resolution_full)
{
if (g_ActiveConfig.stereo_mode == StereoMode::SBS)
{
// Render twice as wide if using side-by-side 3D, since the 3D will halve the horizontal
// resolution
resulting_aspect_ratio *= 2.0;
}
else if (g_ActiveConfig.stereo_mode == StereoMode::TAB)
{
// Render twice as tall if using top-and-bottom 3D, since the 3D will halve the vertical
// resolution
resulting_aspect_ratio /= 2.0;
}
}
return resulting_aspect_ratio;
}
void Presenter::AdjustRectanglesToFitBounds(MathUtil::Rectangle<int>* target_rect,
@ -816,10 +844,10 @@ void Presenter::Present()
UpdateDrawRectangle();
g_gfx->BeginUtilityDrawing();
g_gfx->BindBackbuffer({{0.0f, 0.0f, 0.0f, 1.0f}});
const bool backbuffer_bound = g_gfx->BindBackbuffer({{0.0f, 0.0f, 0.0f, 1.0f}});
// Render the XFB to the screen.
if (m_xfb_entry)
if (backbuffer_bound && m_xfb_entry)
{
// Adjust the source rectangle instead of using an oversized viewport to render the XFB.
auto render_target_rc = GetTargetRectangle();
@ -832,7 +860,8 @@ void Presenter::Present()
if (m_onscreen_ui)
{
m_onscreen_ui->Finalize();
m_onscreen_ui->DrawImGui();
if (backbuffer_bound)
m_onscreen_ui->DrawImGui();
}
// Present to the window system.

View file

@ -47,7 +47,6 @@ union RasterizationState
}
bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; }
bool operator!=(const RasterizationState& rhs) const { return !operator==(rhs); }
bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; }
BitField<0, 2, CullMode> cullmode;
@ -73,7 +72,6 @@ union FramebufferState
}
bool operator==(const FramebufferState& rhs) const { return hex == rhs.hex; }
bool operator!=(const FramebufferState& rhs) const { return !operator==(rhs); }
BitField<0, 8, AbstractTextureFormat> color_texture_format;
BitField<8, 8, AbstractTextureFormat> depth_texture_format;
@ -108,7 +106,6 @@ union DepthState
}
bool operator==(const DepthState& rhs) const { return hex == rhs.hex; }
bool operator!=(const DepthState& rhs) const { return !operator==(rhs); }
bool operator<(const DepthState& rhs) const { return hex < rhs.hex; }
BitField<0, 1, u32> testenable;
@ -143,7 +140,6 @@ union BlendingState
}
bool operator==(const BlendingState& rhs) const { return hex == rhs.hex; }
bool operator!=(const BlendingState& rhs) const { return !operator==(rhs); }
bool operator<(const BlendingState& rhs) const { return hex < rhs.hex; }
BitField<0, 1, u32> blendenable;
@ -185,7 +181,6 @@ struct SamplerState
}
bool operator==(const SamplerState& rhs) const { return Hex() == rhs.Hex(); }
bool operator!=(const SamplerState& rhs) const { return !operator==(rhs); }
bool operator<(const SamplerState& rhs) const { return Hex() < rhs.Hex(); }
constexpr u64 Hex() const { return tm0.hex | (static_cast<u64>(tm1.hex) << 32); }

View file

@ -80,8 +80,6 @@ public:
return memcmp(GetUidData(), obj.GetUidData(), GetUidDataSize()) == 0;
}
bool operator!=(const ShaderUid& obj) const { return !operator==(obj); }
// determines the storage order inside STL containers
bool operator<(const ShaderUid& obj) const
{
@ -285,6 +283,7 @@ void WriteSwitch(ShaderCode& out, APIType ApiType, std::string_view variable,
#define I_POSTTRANSFORMMATRICES "cpostmtx"
#define I_PIXELCENTERCORRECTION "cpixelcenter"
#define I_VIEWPORT_SIZE "cviewport"
#define I_CACHED_NORMAL "cnormal"
#define I_CACHED_TANGENT "ctangent"
#define I_CACHED_BINORMAL "cbinormal"
@ -308,6 +307,7 @@ static const char s_shader_uniforms[] = "\tuint components;\n"
"\tfloat4 " I_PIXELCENTERCORRECTION ";\n"
"\tfloat2 " I_VIEWPORT_SIZE ";\n"
"\tuint4 xfmem_pack1[8];\n"
"\tfloat4 " I_CACHED_NORMAL ";\n"
"\tfloat4 " I_CACHED_TANGENT ";\n"
"\tfloat4 " I_CACHED_BINORMAL ";\n"
"\tuint vertex_stride;\n"

View file

@ -176,7 +176,7 @@ void Statistics::AddScissorRect()
}
else
{
add = std::find_if(scissors.begin(), scissors.end(), [&](auto& s) {
add = std::ranges::find_if(scissors, [&](auto& s) {
return s.Matches(scissor, show_scissors, show_viewports);
}) == scissors.end();
}

View file

@ -2814,7 +2814,7 @@ TextureCacheBase::InvalidateTexture(TexAddrCache::iterator iter, bool discard_pe
// Xenoblade's sunset scene, where 35 copies are done per frame, and 25 of them are
// copied to the same address, and can be skipped.
ReleaseEFBCopyStagingTexture(std::move(entry->pending_efb_copy));
auto pending_it = std::find(m_pending_efb_copies.begin(), m_pending_efb_copies.end(), entry);
auto pending_it = std::ranges::find(m_pending_efb_copies, entry);
if (pending_it != m_pending_efb_copies.end())
m_pending_efb_copies.erase(pending_it);
}

View file

@ -63,7 +63,6 @@ struct TextureAndTLUTFormat
return texfmt == other.texfmt;
}
bool operator!=(const TextureAndTLUTFormat& other) const { return !operator==(other); }
TextureFormat texfmt;
TLUTFormat tlutfmt;
};

View file

@ -13,11 +13,6 @@ bool TextureConfig::operator==(const TextureConfig& o) const
std::tie(o.width, o.height, o.levels, o.layers, o.samples, o.format, o.flags, o.type);
}
bool TextureConfig::operator!=(const TextureConfig& o) const
{
return !operator==(o);
}
MathUtil::Rectangle<int> TextureConfig::GetRect() const
{
return {0, 0, static_cast<int>(width), static_cast<int>(height)};

View file

@ -59,7 +59,6 @@ struct TextureConfig
}
bool operator==(const TextureConfig& o) const;
bool operator!=(const TextureConfig& o) const;
MathUtil::Rectangle<int> GetRect() const;
MathUtil::Rectangle<int> GetMipRect(u32 level) const;
size_t GetStride() const;

View file

@ -115,30 +115,14 @@ static inline void DecodeBytes_IA4(u32* dst, const u8* src)
static inline void DecodeBytes_RGB5A3(u32* dst, const u16* src)
{
#if 0
for (int x = 0; x < 4; x++)
dst[x] = DecodePixel_RGB5A3(Common::swap16(src[x]));
#else
dst[0] = DecodePixel_RGB5A3(Common::swap16(src[0]));
dst[1] = DecodePixel_RGB5A3(Common::swap16(src[1]));
dst[2] = DecodePixel_RGB5A3(Common::swap16(src[2]));
dst[3] = DecodePixel_RGB5A3(Common::swap16(src[3]));
#endif
}
static inline void DecodeBytes_RGBA8(u32* dst, const u16* src, const u16* src2)
{
#if 0
for (int x = 0; x < 4; x++)
{
dst[x] = ((src[x] & 0xFF) << 24) | ((src[x] & 0xFF00)>>8) | (src2[x] << 8);
}
#else
dst[0] = ((src[0] & 0xFF) << 24) | ((src[0] & 0xFF00) >> 8) | (src2[0] << 8);
dst[1] = ((src[1] & 0xFF) << 24) | ((src[1] & 0xFF00) >> 8) | (src2[1] << 8);
dst[2] = ((src[2] & 0xFF) << 24) | ((src[2] & 0xFF00) >> 8) | (src2[2] << 8);
dst[3] = ((src[3] & 0xFF) << 24) | ((src[3] & 0xFF00) >> 8) | (src2[3] << 8);
#endif
dst[x] = ((src[x] & 0xFF) << 24) | ((src[x] & 0xFF00) >> 8) | (src2[x] << 8);
}
static void DecodeDXTBlock(u32* dst, const DXTBlock* src, int pitch)

View file

@ -251,47 +251,53 @@ float3 load_input_float3_rawtex(uint vtx_offset, uint attr_offset) {{
"o.pos = float4(dot(" I_PROJECTION "[0], pos), dot(" I_PROJECTION
"[1], pos), dot(" I_PROJECTION "[2], pos), dot(" I_PROJECTION "[3], pos));\n"
"\n"
"float3 _rawnormal;\n"
"float3 _rawtangent;\n"
"float3 _rawbinormal;\n"
"if ((components & {}u) != 0u) // VB_HAS_NORMAL\n"
"{{\n",
Common::ToUnderlying(VB_HAS_NORMAL));
LoadVertexAttribute(out, host_config, 2, "rawnormal", "float3", "float3");
out.Write(" _rawnormal = rawnormal;\n"
"}}\n"
"else\n"
"{{\n"
" _rawnormal = " I_CACHED_NORMAL ".xyz;\n"
"}}\n"
"\n"
"if ((components & {}u) != 0u) // VB_HAS_TANGENT\n"
"{{\n",
Common::ToUnderlying(VB_HAS_TANGENT));
LoadVertexAttribute(out, host_config, 2, "rawtangent", "float3", "float3");
out.Write(" _rawtangent = rawtangent;\n"
"}}\n"
"else\n"
"{{\n"
" _rawtangent = " I_CACHED_TANGENT ".xyz;\n"
"}}\n"
"\n"
"if ((components & {}u) != 0u) // VB_HAS_BINORMAL\n"
"{{\n",
Common::ToUnderlying(VB_HAS_BINORMAL));
LoadVertexAttribute(out, host_config, 2, "rawbinormal", "float3", "float3");
out.Write(" _rawbinormal = rawbinormal;\n"
"}}\n"
"else\n"
"{{\n"
" _rawbinormal = " I_CACHED_BINORMAL ".xyz;\n"
"}}\n"
"\n"
"// The scale of the transform matrix is used to control the size of the emboss map\n"
"// effect by changing the scale of the transformed binormals (which only get used by\n"
"// emboss map texgens). By normalising the first transformed normal (which is used\n"
"// by lighting calculations and needs to be unit length), the same transform matrix\n"
"// can do double duty, scaling for emboss mapping, and not scaling for lighting.\n"
"float3 _normal = float3(0.0, 0.0, 0.0);\n"
"if ((components & {}u) != 0u) // VB_HAS_NORMAL\n"
"{{\n",
Common::ToUnderlying(VB_HAS_NORMAL));
LoadVertexAttribute(out, host_config, 2, "rawnormal", "float3", "float3");
out.Write(" _normal = normalize(float3(dot(N0, rawnormal), dot(N1, rawnormal), dot(N2, "
"rawnormal)));\n"
"}}\n"
"\n"
"float3 _tangent = float3(0.0, 0.0, 0.0);\n"
"if ((components & {}u) != 0u) // VB_HAS_TANGENT\n"
"{{\n",
Common::ToUnderlying(VB_HAS_TANGENT));
LoadVertexAttribute(out, host_config, 2, "rawtangent", "float3", "float3");
out.Write(" _tangent = float3(dot(N0, rawtangent), dot(N1, rawtangent), dot(N2, rawtangent));\n"
"}}\n"
"else\n"
"{{\n"
" _tangent = float3(dot(N0, " I_CACHED_TANGENT ".xyz), dot(N1, " I_CACHED_TANGENT
".xyz), dot(N2, " I_CACHED_TANGENT ".xyz));\n"
"}}\n"
"\n"
"float3 _binormal = float3(0.0, 0.0, 0.0);\n"
"if ((components & {}u) != 0u) // VB_HAS_BINORMAL\n"
"{{\n",
Common::ToUnderlying(VB_HAS_BINORMAL));
LoadVertexAttribute(out, host_config, 2, "rawbinormal", "float3", "float3");
out.Write(" _binormal = float3(dot(N0, rawbinormal), dot(N1, rawbinormal), dot(N2, "
"rawbinormal));\n"
"}}\n"
"else\n"
"{{\n"
" _binormal = float3(dot(N0, " I_CACHED_BINORMAL ".xyz), dot(N1, " I_CACHED_BINORMAL
".xyz), dot(N2, " I_CACHED_BINORMAL ".xyz));\n"
"}}\n"
"\n");
"float3 _normal = normalize(float3(dot(N0, _rawnormal), dot(N1, _rawnormal), dot(N2, "
"_rawnormal)));\n"
"float3 _tangent = float3(dot(N0, _rawtangent), dot(N1, _rawtangent), dot(N2, "
"_rawtangent));\n"
"float3 _binormal = float3(dot(N0, _rawbinormal), dot(N1, _rawbinormal), dot(N2, "
"_rawbinormal));\n");
// Hardware Lighting
out.Write("// xfmem.numColorChans controls the number of color channels available to TEV,\n"

View file

@ -164,6 +164,13 @@ void VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentFor
m_float_emit.STR(128, coords, EncodeRegTo64(scratch2_reg), ArithOption(remaining_reg, true));
SetJumpTarget(dont_store);
}
else if (native_format == &m_native_vtx_decl.normals[0])
{
FixupBranch dont_store = CBNZ(remaining_reg);
MOVP2R(EncodeRegTo64(scratch2_reg), VertexLoaderManager::normal_cache.data());
m_float_emit.STR(128, IndexType::Unsigned, coords, EncodeRegTo64(scratch2_reg), 0);
SetJumpTarget(dont_store);
}
else if (native_format == &m_native_vtx_decl.normals[1])
{
FixupBranch dont_store = CBNZ(remaining_reg);

View file

@ -11,6 +11,7 @@
#include <vector>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include "Common/Assert.h"
#include "Common/BitUtils.h"
@ -67,6 +68,7 @@ public:
VertexLoaderManager::position_matrix_index_cache;
const std::array<std::array<float, 4>, 3> old_position_cache =
VertexLoaderManager::position_cache;
const std::array<float, 4> old_normal_cache = VertexLoaderManager::normal_cache;
const std::array<float, 4> old_tangent_cache = VertexLoaderManager::tangent_cache;
const std::array<float, 4> old_binormal_cache = VertexLoaderManager::binormal_cache;
@ -76,12 +78,14 @@ public:
VertexLoaderManager::position_matrix_index_cache;
const std::array<std::array<float, 4>, 3> a_position_cache =
VertexLoaderManager::position_cache;
const std::array<float, 4> a_normal_cache = VertexLoaderManager::normal_cache;
const std::array<float, 4> a_tangent_cache = VertexLoaderManager::tangent_cache;
const std::array<float, 4> a_binormal_cache = VertexLoaderManager::binormal_cache;
// Reset state before running b
VertexLoaderManager::position_matrix_index_cache = old_position_matrix_index_cache;
VertexLoaderManager::position_cache = old_position_cache;
VertexLoaderManager::normal_cache = old_normal_cache;
VertexLoaderManager::tangent_cache = old_tangent_cache;
VertexLoaderManager::binormal_cache = old_binormal_cache;
@ -91,6 +95,7 @@ public:
VertexLoaderManager::position_matrix_index_cache;
const std::array<std::array<float, 4>, 3> b_position_cache =
VertexLoaderManager::position_cache;
const std::array<float, 4> b_normal_cache = VertexLoaderManager::normal_cache;
const std::array<float, 4> b_tangent_cache = VertexLoaderManager::tangent_cache;
const std::array<float, 4> b_binormal_cache = VertexLoaderManager::binormal_cache;
@ -139,6 +144,12 @@ public:
fmt::join(b_position_cache[1], ", "), fmt::join(b_position_cache[2], ", "));
// The last element is allowed to be garbage for SIMD overwrites
ASSERT_MSG(VIDEO,
std::equal(a_normal_cache.begin(), a_normal_cache.begin() + 3,
b_normal_cache.begin(), b_normal_cache.begin() + 3, bit_equal),
"Expected matching normal caches after loading (a: {}; b: {})",
fmt::join(a_normal_cache, ", "), fmt::join(b_normal_cache, ", "));
ASSERT_MSG(VIDEO,
std::equal(a_tangent_cache.begin(), a_tangent_cache.begin() + 3,
b_tangent_cache.begin(), b_tangent_cache.begin() + 3, bit_equal),

View file

@ -40,6 +40,7 @@ namespace VertexLoaderManager
std::array<u32, 3> position_matrix_index_cache;
// 3 vertices, 4 floats each to allow SIMD overwrite
alignas(sizeof(std::array<float, 4>)) std::array<std::array<float, 4>, 3> position_cache;
alignas(sizeof(std::array<float, 4>)) std::array<float, 4> normal_cache;
alignas(sizeof(std::array<float, 4>)) std::array<float, 4> tangent_cache;
alignas(sizeof(std::array<float, 4>)) std::array<float, 4> binormal_cache;

View file

@ -62,6 +62,10 @@ void UpdateVertexArrayPointers();
// These arrays are in reverse order.
extern std::array<std::array<float, 4>, 3> position_cache;
extern std::array<u32, 3> position_matrix_index_cache;
// Needed for the game "LIT", which has text that has lighting enabled, but doesn't have normal
// vectors. The normals from the last drawn object are used instead.
// See https://bugs.dolphin-emu.org/issues/13635
extern std::array<float, 4> normal_cache;
// Store the tangent and binormal vectors for games that use emboss texgens when the vertex format
// doesn't include them (e.g. RS2 and RS3). These too are 4 floats each for SIMD overwrites.
extern std::array<float, 4> tangent_cache;

View file

@ -137,6 +137,14 @@ void VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute,
MOVUPS(MPIC(VertexLoaderManager::position_cache.data(), scratch3, SCALE_4), coords);
SetJumpTarget(dont_store);
}
else if (native_format == &m_native_vtx_decl.normals[0])
{
TEST(32, R(remaining_reg), R(remaining_reg));
FixupBranch dont_store = J_CC(CC_NZ);
// For similar reasons, the cached normal is 4 floats each
MOVUPS(MPIC(VertexLoaderManager::normal_cache.data()), coords);
SetJumpTarget(dont_store);
}
else if (native_format == &m_native_vtx_decl.normals[1])
{
TEST(32, R(remaining_reg), R(remaining_reg));

View file

@ -49,7 +49,9 @@ void ReadIndirect(VertexLoader* loader, const T* data)
const float value = FracAdjust(Common::FromBigEndian(data[i]));
if (loader->m_remaining == 0)
{
if (i >= 3 && i < 6)
if (i < 3)
VertexLoaderManager::normal_cache[i] = value;
else if (i >= 3 && i < 6)
VertexLoaderManager::tangent_cache[i - 3] = value;
else if (i >= 6 && i < 9)
VertexLoaderManager::binormal_cache[i - 6] = value;

View file

@ -558,7 +558,7 @@ void VertexManagerBase::Flush()
pixel_shader_manager.constants.time_ms = seconds_elapsed * 1000;
}
CalculateBinormals(VertexLoaderManager::GetCurrentVertexFormat());
CalculateNormals(VertexLoaderManager::GetCurrentVertexFormat());
// Calculate ZSlope for zfreeze
const auto used_textures = UsedTextures();
std::vector<std::string> texture_names;
@ -699,6 +699,7 @@ void VertexManagerBase::DoState(PointerWrap& p)
}
p.Do(m_zslope);
p.Do(VertexLoaderManager::normal_cache);
p.Do(VertexLoaderManager::tangent_cache);
p.Do(VertexLoaderManager::binormal_cache);
}
@ -769,7 +770,7 @@ void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format)
m_zslope.dirty = true;
}
void VertexManagerBase::CalculateBinormals(NativeVertexFormat* format)
void VertexManagerBase::CalculateNormals(NativeVertexFormat* format)
{
const PortableVertexDeclaration vert_decl = format->GetVertexDeclaration();
@ -794,6 +795,16 @@ void VertexManagerBase::CalculateBinormals(NativeVertexFormat* format)
vertex_shader_manager.constants.cached_binormal = VertexLoaderManager::binormal_cache;
vertex_shader_manager.dirty = true;
}
if (vert_decl.normals[0].enable)
return;
VertexLoaderManager::normal_cache[3] = 0;
if (vertex_shader_manager.constants.cached_normal != VertexLoaderManager::normal_cache)
{
vertex_shader_manager.constants.cached_normal = VertexLoaderManager::normal_cache;
vertex_shader_manager.dirty = true;
}
}
void VertexManagerBase::UpdatePipelineConfig()
@ -954,8 +965,7 @@ void VertexManagerBase::OnDraw()
// Check if this draw is scheduled to kick a command buffer.
// The draw counters will always be sorted so a binary search is possible here.
if (std::binary_search(m_scheduled_command_buffer_kicks.begin(),
m_scheduled_command_buffer_kicks.end(), m_draw_counter))
if (std::ranges::binary_search(m_scheduled_command_buffer_kicks, m_draw_counter))
{
// Kick a command buffer on the background thread.
g_gfx->Flush();
@ -1041,19 +1051,6 @@ void VertexManagerBase::OnEndFrame()
}
}
#if 0
{
std::ostringstream ss;
std::for_each(m_cpu_accesses_this_frame.begin(), m_cpu_accesses_this_frame.end(), [&ss](u32 idx) { ss << idx << ","; });
WARN_LOG_FMT(VIDEO, "CPU EFB accesses in last frame: {}", ss.str());
}
{
std::ostringstream ss;
std::for_each(m_scheduled_command_buffer_kicks.begin(), m_scheduled_command_buffer_kicks.end(), [&ss](u32 idx) { ss << idx << ","; });
WARN_LOG_FMT(VIDEO, "Scheduled command buffer kicks: {}", ss.str());
}
#endif
m_cpu_accesses_this_frame.clear();
// We invalidate the pipeline object at the start of the frame.

View file

@ -192,7 +192,7 @@ protected:
u32 GetRemainingIndices(OpcodeDecoder::Primitive primitive) const;
void CalculateZSlope(NativeVertexFormat* format);
void CalculateBinormals(NativeVertexFormat* format);
void CalculateNormals(NativeVertexFormat* format);
BitSet32 UsedTextures() const;

View file

@ -312,56 +312,43 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
out.Write("int posidx = int(posmtx.r);\n"
"float4 P0 = " I_TRANSFORMMATRICES "[posidx];\n"
"float4 P1 = " I_TRANSFORMMATRICES "[posidx + 1];\n"
"float4 P2 = " I_TRANSFORMMATRICES "[posidx + 2];\n");
if ((uid_data->components & VB_HAS_NORMAL) != 0)
{
out.Write("int normidx = posidx & 31;\n"
"float3 N0 = " I_NORMALMATRICES "[normidx].xyz;\n"
"float3 N1 = " I_NORMALMATRICES "[normidx + 1].xyz;\n"
"float3 N2 = " I_NORMALMATRICES "[normidx + 2].xyz;\n");
}
"float4 P2 = " I_TRANSFORMMATRICES "[posidx + 2];\n"
"int normidx = posidx & 31;\n"
"float3 N0 = " I_NORMALMATRICES "[normidx].xyz;\n"
"float3 N1 = " I_NORMALMATRICES "[normidx + 1].xyz;\n"
"float3 N2 = " I_NORMALMATRICES "[normidx + 2].xyz;\n");
}
else
{
// One shared matrix
out.Write("float4 P0 = " I_POSNORMALMATRIX "[0];\n"
"float4 P1 = " I_POSNORMALMATRIX "[1];\n"
"float4 P2 = " I_POSNORMALMATRIX "[2];\n");
if ((uid_data->components & VB_HAS_NORMAL) != 0)
{
out.Write("float3 N0 = " I_POSNORMALMATRIX "[3].xyz;\n"
"float3 N1 = " I_POSNORMALMATRIX "[4].xyz;\n"
"float3 N2 = " I_POSNORMALMATRIX "[5].xyz;\n");
}
"float4 P2 = " I_POSNORMALMATRIX "[2];\n"
"float3 N0 = " I_POSNORMALMATRIX "[3].xyz;\n"
"float3 N1 = " I_POSNORMALMATRIX "[4].xyz;\n"
"float3 N2 = " I_POSNORMALMATRIX "[5].xyz;\n");
}
out.Write("// Multiply the position vector by the position matrix\n"
"float4 pos = float4(dot(P0, rawpos), dot(P1, rawpos), dot(P2, rawpos), 1.0);\n");
if ((uid_data->components & VB_HAS_NORMAL) != 0)
{
if ((uid_data->components & VB_HAS_TANGENT) == 0)
out.Write("float3 rawtangent = " I_CACHED_TANGENT ".xyz;\n");
if ((uid_data->components & VB_HAS_BINORMAL) == 0)
out.Write("float3 rawbinormal = " I_CACHED_BINORMAL ".xyz;\n");
if ((uid_data->components & VB_HAS_NORMAL) == 0)
out.Write("float3 rawnormal = " I_CACHED_NORMAL ".xyz;\n");
if ((uid_data->components & VB_HAS_TANGENT) == 0)
out.Write("float3 rawtangent = " I_CACHED_TANGENT ".xyz;\n");
if ((uid_data->components & VB_HAS_BINORMAL) == 0)
out.Write("float3 rawbinormal = " I_CACHED_BINORMAL ".xyz;\n");
// The scale of the transform matrix is used to control the size of the emboss map effect, by
// changing the scale of the transformed binormals (which only get used by emboss map texgens).
// By normalising the first transformed normal (which is used by lighting calculations and needs
// to be unit length), the same transform matrix can do double duty, scaling for emboss mapping,
// and not scaling for lighting.
out.Write("float3 _normal = normalize(float3(dot(N0, rawnormal), dot(N1, rawnormal), dot(N2, "
"rawnormal)));\n"
"float3 _tangent = float3(dot(N0, rawtangent), dot(N1, rawtangent), dot(N2, "
"rawtangent));\n"
"float3 _binormal = float3(dot(N0, rawbinormal), dot(N1, rawbinormal), dot(N2, "
"rawbinormal));\n");
}
else
{
out.Write("float3 _normal = float3(0.0, 0.0, 0.0);\n");
out.Write("float3 _binormal = float3(0.0, 0.0, 0.0);\n");
out.Write("float3 _tangent = float3(0.0, 0.0, 0.0);\n");
}
// The scale of the transform matrix is used to control the size of the emboss map effect, by
// changing the scale of the transformed binormals (which only get used by emboss map texgens).
// By normalising the first transformed normal (which is used by lighting calculations and needs
// to be unit length), the same transform matrix can do double duty, scaling for emboss mapping,
// and not scaling for lighting.
out.Write("float3 _normal = normalize(float3(dot(N0, rawnormal), dot(N1, rawnormal), dot(N2, "
"rawnormal)));\n"
"float3 _tangent = float3(dot(N0, rawtangent), dot(N1, rawtangent), dot(N2, "
"rawtangent));\n"
"float3 _binormal = float3(dot(N0, rawbinormal), dot(N1, rawbinormal), dot(N2, "
"rawbinormal));\n");
out.Write("o.pos = float4(dot(" I_PROJECTION "[0], pos), dot(" I_PROJECTION
"[1], pos), dot(" I_PROJECTION "[2], pos), dot(" I_PROJECTION "[3], pos));\n");

View file

@ -148,8 +148,14 @@ bool VertexShaderManager::UseVertexDepthRange()
return true;
// If an inverted depth range is unsupported, we also need to check if the range is inverted.
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange && xfmem.viewport.zRange < 0.0f)
return true;
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
{
if (xfmem.viewport.zRange < 0.0f)
return true;
if (xfmem.viewport.zRange > xfmem.viewport.farZ)
return true;
}
// If an oversized depth range or a ztexture is used, we need to calculate the depth range
// in the vertex shader.

View file

@ -52,6 +52,7 @@
#include "VideoCommon/GeometryShaderManager.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
@ -283,6 +284,11 @@ void VideoBackendBase::ActivateBackend(const std::string& name)
void VideoBackendBase::PopulateBackendInfo(const WindowSystemInfo& wsi)
{
// If the core has been initialized, the backend info will have been populated already. Doing it
// again would be unnecessary and could cause the UI thread to race with the GPU thread.
if (!Core::IsUninitialized(Core::System::GetInstance()))
return;
g_Config.Refresh();
// Reset backend_info so if the backend forgets to initialize something it doesn't end up using
// a value from the previously used renderer
@ -295,14 +301,6 @@ void VideoBackendBase::PopulateBackendInfo(const WindowSystemInfo& wsi)
g_Config.VerifyValidity();
}
void VideoBackendBase::PopulateBackendInfoFromUI(const WindowSystemInfo& wsi)
{
// If the core is running, the backend info will have been populated already.
// If we did it here, the UI thread can race with the with the GPU thread.
if (!Core::IsRunning(Core::System::GetInstance()))
PopulateBackendInfo(wsi);
}
void VideoBackendBase::DoState(PointerWrap& p)
{
auto& system = Core::System::GetInstance();
@ -392,6 +390,12 @@ bool VideoBackendBase::InitializeShared(std::unique_ptr<AbstractGfx> gfx,
g_Config.VerifyValidity();
UpdateActiveConfig();
if (g_Config.bDumpTextures)
{
OSD::AddMessage(fmt::format("Texture Dumping is enabled. This will reduce performance."),
OSD::Duration::NORMAL);
}
g_shader_cache->InitializeShaderCache();
return true;

View file

@ -70,8 +70,6 @@ public:
// Fills the backend_info fields with the capabilities of the selected backend/device.
static void PopulateBackendInfo(const WindowSystemInfo& wsi);
// Called by the UI thread when the graphics config is opened.
static void PopulateBackendInfoFromUI(const WindowSystemInfo& wsi);
// Wrapper function which pushes the event to the GPU thread.
void DoState(PointerWrap& p);

View file

@ -172,6 +172,7 @@ void VideoConfig::Refresh()
color_correction.fHDRPaperWhiteNits = Config::Get(Config::GFX_CC_HDR_PAPER_WHITE_NITS);
stereo_mode = Config::Get(Config::GFX_STEREO_MODE);
stereo_per_eye_resolution_full = Config::Get(Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL);
iStereoDepth = Config::Get(Config::GFX_STEREO_DEPTH);
iStereoConvergencePercentage = Config::Get(Config::GFX_STEREO_CONVERGENCE_PERCENTAGE);
bStereoSwapEyes = Config::Get(Config::GFX_STEREO_SWAP_EYES);

View file

@ -242,6 +242,7 @@ struct VideoConfig final
// Stereoscopy
StereoMode stereo_mode{};
bool stereo_per_eye_resolution_full = false;
int iStereoDepth = 0;
int iStereoConvergence = 0;
int iStereoConvergencePercentage = 0;

View file

@ -15,9 +15,8 @@ std::unique_ptr<WidescreenManager> g_widescreen;
WidescreenManager::WidescreenManager()
{
std::optional<bool> is_game_widescreen = GetWidescreenOverride();
if (is_game_widescreen.has_value())
m_is_game_widescreen = is_game_widescreen.value();
if (std::optional<bool> is_game_widescreen = GetWidescreenOverride())
m_is_game_widescreen = *is_game_widescreen;
// Throw a warning as unsupported aspect ratio modes have no specific behavior to them
const bool is_valid_suggested_aspect_mode =
@ -34,14 +33,13 @@ WidescreenManager::WidescreenManager()
[this](u32 bits) {
if (bits & (CONFIG_CHANGE_BIT_ASPECT_RATIO))
{
std::optional<bool> is_game_widescreen = GetWidescreenOverride();
// If the widescreen flag isn't being overridden by any settings,
// reset it to default if heuristic aren't running or to the last
// heuristic value if they were running.
if (!is_game_widescreen.has_value())
is_game_widescreen = (m_heuristic_state == HeuristicState::Active_Found_Anamorphic);
if (is_game_widescreen.has_value())
m_is_game_widescreen = is_game_widescreen.value();
if (std::optional<bool> is_game_widescreen = GetWidescreenOverride())
m_is_game_widescreen = *is_game_widescreen;
else
m_is_game_widescreen = (m_heuristic_state == HeuristicState::Active_Found_Anamorphic);
}
},
"Widescreen");

View file

@ -646,7 +646,7 @@ std::pair<std::string, std::string> GetXFTransferInfo(u16 base_address, u8 trans
std::pair<std::string, std::string> GetXFIndexedLoadInfo(CPArray array, u32 index, u16 address,
u8 size)
{
const auto desc = fmt::format("Load {} bytes to XF address {:03x} from CP array {} row {}", size,
const auto desc = fmt::format("Load {} words to XF address {:03x} from CP array {} row {}", size,
address, array, index);
fmt::memory_buffer written;
for (u32 i = 0; i < size; i++)