mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-13 03:29:11 +00:00
Merge branch 'master' of https://github.com/dolphin-emu/dolphin into dolphin-emu-master
This commit is contained in:
commit
4bd7d38a77
1243 changed files with 15939 additions and 15402 deletions
|
@ -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() {}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -330,8 +330,3 @@ void GraphicsModConfig::DeserializeFromProfile(const picojson::object& obj)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GraphicsModConfig::operator<(const GraphicsModConfig& other) const
|
||||
{
|
||||
return m_weight < other.m_weight;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,4 @@ struct GraphicsModConfig
|
|||
|
||||
void SerializeToProfile(picojson::object* value) const;
|
||||
void DeserializeFromProfile(const picojson::object& value);
|
||||
|
||||
bool operator<(const GraphicsModConfig& other) const;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,6 @@ struct TextureAndTLUTFormat
|
|||
return texfmt == other.texfmt;
|
||||
}
|
||||
|
||||
bool operator!=(const TextureAndTLUTFormat& other) const { return !operator==(other); }
|
||||
TextureFormat texfmt;
|
||||
TLUTFormat tlutfmt;
|
||||
};
|
||||
|
|
|
@ -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)};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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++)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue