mirror of https://github.com/PCSX2/pcsx2.git
GS: Improve target size calcs and remove conservative framebuffer
This commit is contained in:
parent
f218e11d78
commit
6a144f86cf
|
@ -186,7 +186,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
|||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.accurateDATE, "EmuCore/GS", "accurate_date", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.conservativeBufferAllocation, "EmuCore/GS", "conservative_framebuffer", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading",
|
||||
static_cast<int>(TexturePreloadingLevel::Off));
|
||||
|
@ -355,10 +354,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
|||
tr("Implement a more accurate algorithm to compute GS destination alpha testing. "
|
||||
"It improves shadow and transparency rendering."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.conservativeBufferAllocation, tr("Conservative Buffer Allocation"), tr("Checked"),
|
||||
tr("Disabled: Reserves a larger framebuffer to prevent FMV flickers. Increases GPU/memory requirements. "
|
||||
"Disabling this can amplify stuttering due to low RAM/VRAM."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.gpuPaletteConversion, tr("GPU Palette Conversion"), tr("Unchecked"),
|
||||
tr("When enabled GPU converts colormap-textures, otherwise the CPU will. "
|
||||
"It is a trade-off between GPU and CPU."));
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<item>
|
||||
<widget class="QTabWidget" name="hardwareRendererGroup">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
|
@ -642,38 +642,6 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="basicCheckboxGridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="gpuPaletteConversion">
|
||||
<property name="text">
|
||||
<string>GPU Palette Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="conservativeBufferAllocation">
|
||||
<property name="text">
|
||||
<string>Conservative Buffer Allocation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="accurateDATE">
|
||||
<property name="text">
|
||||
<string>Accurate Destination Alpha Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="enableHWFixes">
|
||||
<property name="text">
|
||||
<string>Manual Hardware Renderer Fixes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
|
@ -700,6 +668,31 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="basicCheckboxGridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="accurateDATE">
|
||||
<property name="text">
|
||||
<string>Accurate Destination Alpha Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="gpuPaletteConversion">
|
||||
<property name="text">
|
||||
<string>GPU Palette Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableHWFixes">
|
||||
<property name="text">
|
||||
<string>Manual Hardware Renderer Fixes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="hardwareFixesTab">
|
||||
|
|
|
@ -461,7 +461,6 @@ struct Pcsx2Config
|
|||
HWDisableReadbacks : 1,
|
||||
AccurateDATE : 1,
|
||||
GPUPaletteConversion : 1,
|
||||
ConservativeFramebuffer : 1,
|
||||
AutoFlushSW : 1,
|
||||
PreloadFrameWithGSData : 1,
|
||||
WrapGSMem : 1,
|
||||
|
|
|
@ -829,7 +829,6 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
|||
// reload texture cache when trilinear filtering or TC options change
|
||||
if (
|
||||
(GSConfig.UseHardwareRenderer() && GSConfig.HWMipmap != old_config.HWMipmap) ||
|
||||
GSConfig.ConservativeFramebuffer != old_config.ConservativeFramebuffer ||
|
||||
GSConfig.TexturePreloading != old_config.TexturePreloading ||
|
||||
GSConfig.UserHacks_TriFilter != old_config.UserHacks_TriFilter ||
|
||||
GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion ||
|
||||
|
@ -1456,7 +1455,6 @@ void GSApp::Init()
|
|||
m_default_configuration["pcrtc_overscan"] = "0";
|
||||
m_default_configuration["IntegerScaling"] = "0";
|
||||
m_default_configuration["deinterlace"] = "7";
|
||||
m_default_configuration["conservative_framebuffer"] = "1";
|
||||
m_default_configuration["linear_present"] = "1";
|
||||
m_default_configuration["LoadTextureReplacements"] = "0";
|
||||
m_default_configuration["LoadTextureReplacementsAsync"] = "1";
|
||||
|
|
|
@ -76,12 +76,6 @@ __forceinline bool BitEqual(const T& a, const T& b)
|
|||
return eqb;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ACCURATE_BUFFER_EMULATION
|
||||
static const GSVector2i default_rt_size(2048, 2048);
|
||||
#else
|
||||
static const GSVector2i default_rt_size(0, 0);
|
||||
#endif
|
||||
|
||||
extern Pcsx2Config::GSOptions GSConfig;
|
||||
|
||||
// Maximum texture size to skip preload/hash path.
|
||||
|
|
|
@ -20,12 +20,11 @@
|
|||
#include "GS/Renderers/SW/GSTextureCacheSW.h"
|
||||
#include "GS/Renderers/SW/GSDrawScanline.h"
|
||||
#include "Host.h"
|
||||
#include "common/Align.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
GSRendererHW::GSRendererHW()
|
||||
: GSRenderer()
|
||||
, m_width(default_rt_size.x)
|
||||
, m_height(default_rt_size.y)
|
||||
, m_tc(new GSTextureCache())
|
||||
, m_src(nullptr)
|
||||
, m_reset(false)
|
||||
|
@ -50,7 +49,7 @@ GSRendererHW::GSRendererHW()
|
|||
ResetStates();
|
||||
}
|
||||
|
||||
void GSRendererHW::SetScaling()
|
||||
GSVector2i GSRendererHW::GetOutputSize(int real_h)
|
||||
{
|
||||
GSVector2i crtc_size(GetResolution());
|
||||
|
||||
|
@ -90,63 +89,10 @@ void GSRendererHW::SetScaling()
|
|||
}
|
||||
}
|
||||
|
||||
// Details of (potential) perf impact of a big framebuffer
|
||||
// 1/ extra memory
|
||||
// 2/ texture cache framebuffer rescaling/copy
|
||||
// 3/ upload of framebuffer (preload hack)
|
||||
// 4/ framebuffer clear (color/depth/stencil)
|
||||
// 5/ read back of the frambuffer
|
||||
//
|
||||
// With the solution
|
||||
// 1/ Nothing to do.Except the texture cache bug (channel shuffle effect)
|
||||
// most of the market is 1GB of VRAM (and soon 2GB)
|
||||
// 2/ limit rescaling/copy to the valid data of the framebuffer
|
||||
// 3/ ??? no solution so far
|
||||
// 4a/ stencil can be limited to valid data.
|
||||
// 4b/ is it useful to clear color? depth? (in any case, it ought to be few operation)
|
||||
// 5/ limit the read to the valid data
|
||||
// Include negative display offsets in the height here.
|
||||
crtc_size.y = std::max(crtc_size.y, real_h);
|
||||
|
||||
// Framebuffer width is always a multiple of 64 so at certain cases it can't cover some weird width values.
|
||||
// 480P , 576P use width as 720 which is not referencable by FBW * 64. so it produces 704 ( the closest value multiple by 64).
|
||||
// In such cases, let's just use the CRTC width.
|
||||
const int fb_width = std::max({(int)m_context->FRAME.FBW * 64, crtc_size.x, 512});
|
||||
// GS doesn't have a specific register for the FrameBuffer height. so we get the height
|
||||
// from physical units of the display rectangle in case the game uses a heigher value of height.
|
||||
//
|
||||
// Gregory: the framebuffer must have enough room to draw
|
||||
// * at least 2 frames such as FMV (see OI_BlitFMV)
|
||||
// * high resolution game such as snowblind engine game
|
||||
//
|
||||
// Autodetection isn't a good idea because it will create flickering
|
||||
// If memory consumption is an issue, there are 2 possibilities
|
||||
// * 1/ Avoid to create hundreds of RT
|
||||
// * 2/ Use sparse texture (requires recent HW)
|
||||
//
|
||||
// Avoid to alternate between 640x1280 and 1280x1024 on snow blind engine game
|
||||
// int fb_height = (fb_width < 1024) ? 1280 : 1024;
|
||||
//
|
||||
// Until performance issue is properly fixed, let's keep an option to reduce the framebuffer size.
|
||||
//
|
||||
// m_large_framebuffer has been inverted to m_conservative_framebuffer, it isn't an option that benefits being enabled all the time for everyone.
|
||||
int fb_height = MAX_FRAMEBUFFER_HEIGHT;
|
||||
if (GSConfig.ConservativeFramebuffer)
|
||||
{
|
||||
fb_height = fb_width < 1024 ? std::max(512, crtc_size.y) : 1024;
|
||||
}
|
||||
|
||||
const int upscaled_fb_w = fb_width * GSConfig.UpscaleMultiplier;
|
||||
const int upscaled_fb_h = fb_height * GSConfig.UpscaleMultiplier;
|
||||
const bool good_rt_size = m_width >= upscaled_fb_w && m_height >= upscaled_fb_h;
|
||||
|
||||
// No need to resize for native/custom resolutions as default size will be enough for native and we manually get RT Buffer size for custom.
|
||||
// don't resize until the display rectangle and register states are stabilized.
|
||||
if (good_rt_size)
|
||||
return;
|
||||
|
||||
m_tc->RemovePartial();
|
||||
m_width = upscaled_fb_w;
|
||||
m_height = upscaled_fb_h;
|
||||
printf("Frame buffer size set to %dx%d (%dx%d)\n", fb_width, fb_height, m_width, m_height);
|
||||
return crtc_size * GSVector2i(static_cast<int>(GSConfig.UpscaleMultiplier), static_cast<int>(GSConfig.UpscaleMultiplier));
|
||||
}
|
||||
|
||||
void GSRendererHW::SetTCOffset()
|
||||
|
@ -192,11 +138,6 @@ void GSRendererHW::SetGameCRC(u32 crc, int options)
|
|||
|
||||
bool GSRendererHW::CanUpscale()
|
||||
{
|
||||
if (m_hacks.m_cu && !(this->*m_hacks.m_cu)())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GSConfig.UpscaleMultiplier != 1;
|
||||
}
|
||||
|
||||
|
@ -227,20 +168,12 @@ void GSRendererHW::VSync(u32 field, bool registers_written)
|
|||
if (m_reset)
|
||||
{
|
||||
m_tc->RemoveAll();
|
||||
|
||||
// Reset RT size.
|
||||
m_width = default_rt_size.x;
|
||||
m_height = default_rt_size.y;
|
||||
|
||||
m_reset = false;
|
||||
}
|
||||
|
||||
if (GSConfig.LoadTextureReplacements)
|
||||
GSTextureReplacements::ProcessAsyncLoadedTextures();
|
||||
|
||||
//Check if the frame buffer width or display width has changed
|
||||
SetScaling();
|
||||
|
||||
GSRenderer::VSync(field, registers_written);
|
||||
|
||||
m_tc->IncAge();
|
||||
|
@ -286,7 +219,7 @@ GSTexture* GSRendererHW::GetOutput(int i, int& y_offset)
|
|||
|
||||
GSTexture* t = NULL;
|
||||
|
||||
if (GSTextureCache::Target* rt = m_tc->LookupTarget(TEX0, GetTargetSize(), fb_height))
|
||||
if (GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height))
|
||||
{
|
||||
t = rt->m_texture;
|
||||
|
||||
|
@ -321,7 +254,8 @@ GSTexture* GSRendererHW::GetFeedbackOutput()
|
|||
TEX0.TBW = m_regs->EXTBUF.EXBW;
|
||||
TEX0.PSM = m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPFB.PSM;
|
||||
|
||||
GSTextureCache::Target* rt = m_tc->LookupTarget(TEX0, GetTargetSize(), /*GetFrameRect(i).bottom*/ m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPLAY.DH);
|
||||
const int fb_height = /*GetFrameRect(i).bottom*/ m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPLAY.DH;
|
||||
GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height);
|
||||
|
||||
GSTexture* t = rt->m_texture;
|
||||
|
||||
|
@ -763,35 +697,41 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
|
|||
}
|
||||
}
|
||||
|
||||
GSVector2 GSRendererHW::GetTextureScaleFactor(const bool force_upscaling)
|
||||
{
|
||||
GSVector2 scale_factor{ 1.0f, 1.0f };
|
||||
if (force_upscaling || CanUpscale())
|
||||
{
|
||||
const int multiplier = GetUpscaleMultiplier();
|
||||
scale_factor.x = multiplier;
|
||||
scale_factor.y = multiplier;
|
||||
}
|
||||
|
||||
return scale_factor;
|
||||
}
|
||||
|
||||
GSVector2 GSRendererHW::GetTextureScaleFactor()
|
||||
{
|
||||
return GetTextureScaleFactor(false);
|
||||
const float f_upscale = static_cast<float>(GetUpscaleMultiplier());
|
||||
return GSVector2(f_upscale, f_upscale);
|
||||
}
|
||||
|
||||
GSVector2i GSRendererHW::GetTargetSize()
|
||||
{
|
||||
const GSVector2i t_size = { m_width, m_height };
|
||||
if (GetUpscaleMultiplier() == 1 || CanUpscale())
|
||||
return t_size;
|
||||
// Undo the upscaling for native resolution draws.
|
||||
const GSVector2 up_s = GetTextureScaleFactor(true);
|
||||
return {
|
||||
static_cast<int>(std::ceil(static_cast<float>(t_size.x) / up_s.x)),
|
||||
static_cast<int>(std::ceil(static_cast<float>(t_size.y) / up_s.y)),
|
||||
};
|
||||
// Don't blindly expand out to the scissor size if we're not drawing to it.
|
||||
// e.g. Burnout 3, God of War II, etc.
|
||||
u32 min_height = std::min<u32>(m_context->scissor.in.w, m_r.w);
|
||||
|
||||
// Another thing these games like to do, is draw a 512x896 shuffle, which would result in us
|
||||
// expanding the target out to 896 height, but the extra area would all be black, with the
|
||||
// draw effectively changing nothing for the new area. So, instead, lets try to detect these
|
||||
// draws by double-checking we're not stretching the texture (gradient of <1).
|
||||
if (PRIM->TME && m_vt.m_primclass == GS_SPRITE_CLASS && m_src && (m_src->m_target || m_src->m_from_target))
|
||||
{
|
||||
const float diff = std::abs((m_vt.m_max.p.y - m_vt.m_min.p.y) - (m_vt.m_max.t.y - m_vt.m_min.t.y));
|
||||
if (diff <= 1.0f)
|
||||
{
|
||||
// Clamp to the texture size. We're working in unscaled coordinates here, so undo the upscaling.
|
||||
min_height = std::min(min_height, static_cast<u32>(static_cast<float>(m_src->m_texture->GetHeight()) / m_src->m_texture->GetScale().y));
|
||||
}
|
||||
}
|
||||
|
||||
// Align to even lines, reduces the chance of tiny resizes.
|
||||
min_height = Common::AlignUpPow2(min_height, 2);
|
||||
|
||||
const u32 width = m_context->FRAME.FBW * 64u;
|
||||
const u32 height = m_tc->GetTargetHeight(m_context->FRAME.FBP, m_context->FRAME.FBW, m_context->FRAME.PSM, min_height);
|
||||
|
||||
GL_INS("Target size for %x %u %u: %ux%u", m_context->FRAME.FBP, m_context->FRAME.FBW, m_context->FRAME.PSM, width, height);
|
||||
|
||||
return GSVector2i(static_cast<int>(width * GSConfig.UpscaleMultiplier), static_cast<int>(height * GSConfig.UpscaleMultiplier));
|
||||
}
|
||||
|
||||
void GSRendererHW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
|
||||
|
@ -1605,6 +1545,8 @@ void GSRendererHW::Draw()
|
|||
}
|
||||
}
|
||||
|
||||
// The rectangle of the draw
|
||||
m_r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
|
||||
const GSVector2i t_size = GetTargetSize();
|
||||
|
||||
TEX0.TBP0 = context->FRAME.Block();
|
||||
|
@ -1612,24 +1554,16 @@ void GSRendererHW::Draw()
|
|||
TEX0.PSM = context->FRAME.PSM;
|
||||
|
||||
GSTextureCache::Target* rt = nullptr;
|
||||
GSTexture* rt_tex = nullptr;
|
||||
if (!no_rt)
|
||||
{
|
||||
rt = m_tc->LookupTarget(TEX0, t_size, GSTextureCache::RenderTarget, true, fm);
|
||||
rt_tex = rt->m_texture;
|
||||
}
|
||||
|
||||
TEX0.TBP0 = context->ZBUF.Block();
|
||||
TEX0.TBW = context->FRAME.FBW;
|
||||
TEX0.PSM = context->ZBUF.PSM;
|
||||
|
||||
GSTextureCache::Target* ds = nullptr;
|
||||
GSTexture* ds_tex = nullptr;
|
||||
if (!no_ds)
|
||||
{
|
||||
ds = m_tc->LookupTarget(TEX0, t_size, GSTextureCache::DepthStencil, context->DepthWrite());
|
||||
ds_tex = ds->m_texture;
|
||||
}
|
||||
|
||||
if (rt)
|
||||
{
|
||||
|
@ -1639,38 +1573,24 @@ void GSRendererHW::Draw()
|
|||
rt->m_32_bits_fmt = m_texture_shuffle || (GSLocalMemory::m_psm[context->FRAME.PSM].bpp != 16);
|
||||
}
|
||||
|
||||
// The rectangle of the draw
|
||||
m_r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
|
||||
{
|
||||
// We still need to make sure the dimensions of the targets match.
|
||||
const GSVector2 up_s(GetTextureScaleFactor());
|
||||
const int new_w = std::max(t_size.x, std::max(rt ? rt->m_texture->GetWidth() : 0, ds ? ds->m_texture->GetWidth() : 0));
|
||||
const int new_h = std::max(t_size.y, std::max(rt ? rt->m_texture->GetHeight() : 0, ds ? ds->m_texture->GetHeight() : 0));
|
||||
|
||||
// Ensure draw rect is clamped to framebuffer size. Necessary for updating valid area.
|
||||
m_r = m_r.rintersect(GSVector4i(0, 0, new_w, new_h));
|
||||
|
||||
if (rt)
|
||||
{
|
||||
const GSVector2 up_s = GetTextureScaleFactor();
|
||||
const int up_w = static_cast<int>(std::ceil(static_cast<float>(m_r.z) * up_s.x));
|
||||
const int up_h = static_cast<int>(std::ceil(static_cast<float>(m_r.w) * up_s.y));
|
||||
const int new_w = std::max(up_w, std::max(rt_tex ? rt_tex->GetWidth() : 0, ds_tex ? ds_tex->GetWidth() : 0));
|
||||
const int new_h = std::max(up_h, std::max(rt_tex ? rt_tex->GetHeight() : 0, ds_tex ? ds_tex->GetHeight() : 0));
|
||||
std::array<GSTextureCache::Target*, 2> ts{ rt, ds };
|
||||
for (GSTextureCache::Target* t : ts)
|
||||
{
|
||||
if (t)
|
||||
{
|
||||
// Adjust texture size to fit current draw if necessary.
|
||||
GSTexture* tex = t->m_texture;
|
||||
assert(up_s == tex->GetScale());
|
||||
const int w = tex->GetWidth();
|
||||
const int h = tex->GetHeight();
|
||||
if (w != new_w || h != new_h)
|
||||
{
|
||||
const bool is_rt = t == rt;
|
||||
t->m_texture = is_rt ?
|
||||
g_gs_device->CreateSparseRenderTarget(new_w, new_h, tex->GetFormat()) :
|
||||
g_gs_device->CreateSparseDepthStencil(new_w, new_h, tex->GetFormat());
|
||||
const GSVector4i r{ 0, 0, w, h };
|
||||
g_gs_device->CopyRect(tex, t->m_texture, r, 0, 0);
|
||||
g_gs_device->Recycle(tex);
|
||||
t->m_texture->SetScale(up_s);
|
||||
(is_rt ? rt_tex : ds_tex) = t->m_texture;
|
||||
}
|
||||
pxAssert(rt->m_texture->GetScale() == up_s);
|
||||
rt->ResizeTexture(new_w, new_h, up_s);
|
||||
}
|
||||
if (ds)
|
||||
{
|
||||
pxAssert(ds->m_texture->GetScale() == up_s);
|
||||
ds->ResizeTexture(new_w, new_h, up_s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1708,20 +1628,20 @@ void GSRendererHW::Draw()
|
|||
{
|
||||
s = StringUtil::StdStringFromFormat("%05d_f%lld_rt0_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM));
|
||||
|
||||
if (rt_tex)
|
||||
rt_tex->Save(m_dump_root + s);
|
||||
if (rt->m_texture)
|
||||
rt->m_texture->Save(m_dump_root + s);
|
||||
}
|
||||
|
||||
if (s_savez && s_n >= s_saven)
|
||||
{
|
||||
s = StringUtil::StdStringFromFormat("%05d_f%lld_rz0_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM));
|
||||
|
||||
if (ds_tex)
|
||||
ds_tex->Save(m_dump_root + s);
|
||||
if (ds->m_texture)
|
||||
ds->m_texture->Save(m_dump_root + s);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_hacks.m_oi && !(this->*m_hacks.m_oi)(rt_tex, ds_tex, m_src))
|
||||
if (m_hacks.m_oi && !(this->*m_hacks.m_oi)(rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, m_src))
|
||||
{
|
||||
GL_INS("Warning skipping a draw call (%d)", s_n);
|
||||
return;
|
||||
|
@ -1746,7 +1666,7 @@ void GSRendererHW::Draw()
|
|||
|
||||
OI_GsMemClear();
|
||||
|
||||
OI_DoubleHalfClear(rt_tex, ds_tex);
|
||||
OI_DoubleHalfClear(rt, ds);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1801,7 +1721,7 @@ void GSRendererHW::Draw()
|
|||
|
||||
//
|
||||
|
||||
DrawPrims(rt_tex, ds_tex, m_src);
|
||||
DrawPrims(rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, m_src);
|
||||
|
||||
//
|
||||
|
||||
|
@ -1853,16 +1773,16 @@ void GSRendererHW::Draw()
|
|||
{
|
||||
s = StringUtil::StdStringFromFormat("%05d_f%lld_rt1_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM));
|
||||
|
||||
if (rt_tex)
|
||||
rt_tex->Save(m_dump_root + s);
|
||||
if (rt)
|
||||
rt->m_texture->Save(m_dump_root + s);
|
||||
}
|
||||
|
||||
if (s_savez && s_n >= s_saven)
|
||||
{
|
||||
s = StringUtil::StdStringFromFormat("%05d_f%lld_rz1_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM));
|
||||
|
||||
if (ds_tex)
|
||||
ds_tex->Save(m_dump_root + s);
|
||||
if (ds)
|
||||
rt->m_texture->Save(m_dump_root + s);
|
||||
}
|
||||
|
||||
if (s_savel > 0 && (s_n - s_saven) > s_savel)
|
||||
|
@ -3217,10 +3137,6 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
|
|||
area_out.x, area_out.y, area_out.z, area_out.w);
|
||||
#endif
|
||||
|
||||
const GSVector2i& rtsize = ds ? ds->GetSize() : rt->GetSize();
|
||||
const GSVector2& rtscale = ds ? ds->GetScale() : rt->GetScale();
|
||||
const GSDevice::FeatureSupport features(g_gs_device->Features());
|
||||
|
||||
const bool DATE = m_context->TEST.DATE && m_context->FRAME.PSM != PSM_PSMCT24;
|
||||
bool DATE_PRIMID = false;
|
||||
bool DATE_BARRIER = false;
|
||||
|
@ -3250,6 +3166,7 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
|
|||
// Upscaling hack to avoid various line/grid issues
|
||||
MergeSprite(tex);
|
||||
|
||||
const GSDevice::FeatureSupport features(g_gs_device->Features());
|
||||
if (!features.framebuffer_fetch)
|
||||
m_prim_overlap = PrimitiveOverlap();
|
||||
else
|
||||
|
@ -3418,6 +3335,8 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
|
|||
m_conf.vs.fst = PRIM->FST;
|
||||
|
||||
// FIXME D3D11 and GL support half pixel center. Code could be easier!!!
|
||||
const GSVector2i rtsize(m_conf.ds ? m_conf.ds->GetSize() : m_conf.rt->GetSize());
|
||||
const GSVector2 rtscale(m_conf.ds ? m_conf.ds->GetScale() : m_conf.rt->GetScale());
|
||||
const float sx = 2.0f * rtscale.x / (rtsize.x << 4);
|
||||
const float sy = 2.0f * rtscale.y / (rtsize.y << 4);
|
||||
const float ox = (float)(int)m_context->XYOFFSET.OFX;
|
||||
|
@ -4177,10 +4096,8 @@ bool GSRendererHW::SwPrimRender()
|
|||
GSRendererHW::Hacks::Hacks()
|
||||
: m_oi_map(m_oi_list)
|
||||
, m_oo_map(m_oo_list)
|
||||
, m_cu_map(m_cu_list)
|
||||
, m_oi(NULL)
|
||||
, m_oo(NULL)
|
||||
, m_cu(NULL)
|
||||
{
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::BigMuthaTruckers, CRC::RegionCount, &GSRendererHW::OI_BigMuthaTruckers));
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::DBZBT2, CRC::RegionCount, &GSRendererHW::OI_DBZBTGames));
|
||||
|
@ -4206,7 +4123,6 @@ void GSRendererHW::Hacks::SetGameCRC(const CRC::Game& game)
|
|||
|
||||
m_oi = m_oi_map[hash];
|
||||
m_oo = m_oo_map[hash];
|
||||
m_cu = m_cu_map[hash];
|
||||
|
||||
if (GSConfig.PointListPalette)
|
||||
{
|
||||
|
@ -4220,7 +4136,7 @@ void GSRendererHW::Hacks::SetGameCRC(const CRC::Game& game)
|
|||
// Trick to do a fast clear on the GS
|
||||
// Set frame buffer pointer on the start of the buffer. Set depth buffer pointer on the half buffer
|
||||
// FB + depth write will fill the full buffer.
|
||||
void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
|
||||
void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCache::Target*& ds)
|
||||
{
|
||||
// Note gs mem clear must be tested before calling this function
|
||||
|
||||
|
@ -4266,20 +4182,35 @@ void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
|
|||
GL_INS("OI_DoubleHalfClear:%s: base %x half %x. w_pages %d h_pages %d fbw %d. Color %x",
|
||||
clear_depth ? "depth" : "target", base << 5, half << 5, w_pages, h_pages, m_context->FRAME.FBW, color);
|
||||
|
||||
// Commit texture with a factor 2 on the height
|
||||
GSTexture* t = clear_depth ? ds : rt;
|
||||
const GSVector4i commitRect = ComputeBoundingBox(t->GetScale(), t->GetSize());
|
||||
t->CommitRegion(GSVector2i(commitRect.z, 2 * commitRect.w));
|
||||
// Handle the case where the game stacks FBP and ZBP immediately after one another.
|
||||
// We incorrectly compute the height here, because both the scissor and draw rectangle will only be half
|
||||
// the height of what's effectively being cleared. Spider-Man 2's shadows are a good test case here: it
|
||||
// draws the shadow map to a 128x128 texture, but relies on a 1 pixel border around the edge to "cut off"
|
||||
// the shadows. We cap it to a 256 height, because having a >=512 height framebuffer is very rare, and it
|
||||
// stops us doubling actual framebuffers unintentionally (very common).
|
||||
GSTextureCache::Target* t = clear_depth ? ds : rt;
|
||||
const u32 unscaled_height = static_cast<u32>(static_cast<float>(t->m_texture->GetHeight()) / t->m_texture->GetScale().y);
|
||||
if (unscaled_height == m_context->scissor.in.w && unscaled_height <= 256)
|
||||
{
|
||||
t->ResizeTexture(t->m_texture->GetWidth(), t->m_texture->GetHeight() * 2, t->m_texture->GetScale());
|
||||
if (clear_depth)
|
||||
rt = nullptr;
|
||||
else
|
||||
ds = nullptr;
|
||||
|
||||
// Feed it back into the height cache.
|
||||
m_tc->GetTargetHeight(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, unscaled_height * 2);
|
||||
}
|
||||
|
||||
if (clear_depth)
|
||||
{
|
||||
// Only pure clear are supported for depth
|
||||
ASSERT(color == 0);
|
||||
g_gs_device->ClearDepth(t);
|
||||
g_gs_device->ClearDepth(ds->m_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gs_device->ClearRenderTarget(t, color);
|
||||
g_gs_device->ClearRenderTarget(rt->m_texture, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4295,10 +4226,10 @@ void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
|
|||
|
||||
// If both buffers are side by side we can expect a fast clear in on-going
|
||||
const u32 color = v[1].RGBAQ.U32[0];
|
||||
const GSVector4i commitRect = ComputeBoundingBox(rt->GetScale(), rt->GetSize());
|
||||
rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
|
||||
const GSVector4i commitRect = ComputeBoundingBox(rt->m_texture->GetScale(), rt->m_texture->GetSize());
|
||||
rt->m_texture->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
|
||||
|
||||
g_gs_device->ClearRenderTarget(rt, color);
|
||||
g_gs_device->ClearRenderTarget(rt->m_texture, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4689,12 +4620,14 @@ bool GSRendererHW::OI_SonicUnleashed(GSTexture* rt, GSTexture* ds, GSTextureCach
|
|||
|
||||
GL_INS("OI_SonicUnleashed replace draw by a copy");
|
||||
|
||||
GSTextureCache::Target* src = m_tc->LookupTarget(Texture, GetTargetSize(), GSTextureCache::RenderTarget, true);
|
||||
GSTextureCache::Target* src = m_tc->LookupTarget(Texture, GSVector2i(1, 1), GSTextureCache::RenderTarget, true);
|
||||
|
||||
const GSVector2i size = rt->GetSize();
|
||||
const GSVector2i rt_size(rt->GetSize());
|
||||
const GSVector2i src_size(src->m_texture->GetSize());
|
||||
const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y));
|
||||
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, size.x, size.y);
|
||||
const GSVector4 sRect(0.0f, 0.0f, static_cast<float>(copy_size.x) / static_cast<float>(src_size.x), static_cast<float>(copy_size.y) / static_cast<float>(src_size.y));
|
||||
const GSVector4 dRect(0, 0, copy_size.x, copy_size.y);
|
||||
|
||||
g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false);
|
||||
|
||||
|
|
|
@ -29,9 +29,6 @@ public:
|
|||
static constexpr int MAX_FRAMEBUFFER_HEIGHT = 1280;
|
||||
|
||||
private:
|
||||
int m_width;
|
||||
int m_height;
|
||||
|
||||
static constexpr float SSR_UV_TOLERANCE = 1.0f;
|
||||
|
||||
#pragma region hacks
|
||||
|
@ -43,7 +40,7 @@ private:
|
|||
// Require special argument
|
||||
bool OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Source* t, const GSVector4i& r_draw);
|
||||
void OI_GsMemClear(); // always on
|
||||
void OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds); // always on
|
||||
void OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCache::Target*& ds); // always on
|
||||
|
||||
bool OI_BigMuthaTruckers(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
bool OI_DBZBTGames(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
@ -108,16 +105,13 @@ private:
|
|||
|
||||
std::list<HackEntry<OI_Ptr>> m_oi_list;
|
||||
std::list<HackEntry<OO_Ptr>> m_oo_list;
|
||||
std::list<HackEntry<CU_Ptr>> m_cu_list;
|
||||
|
||||
FunctionMap<OI_Ptr> m_oi_map;
|
||||
FunctionMap<OO_Ptr> m_oo_map;
|
||||
FunctionMap<CU_Ptr> m_cu_map;
|
||||
|
||||
public:
|
||||
OI_Ptr m_oi;
|
||||
OO_Ptr m_oo;
|
||||
CU_Ptr m_cu;
|
||||
|
||||
Hacks();
|
||||
|
||||
|
@ -183,15 +177,14 @@ public:
|
|||
void SetGameCRC(u32 crc, int options) override;
|
||||
bool CanUpscale() override;
|
||||
int GetUpscaleMultiplier() override;
|
||||
void SetScaling();
|
||||
void Lines2Sprites();
|
||||
void EmulateAtst(GSVector4& FogColor_AREF, u8& atst, const bool pass_2);
|
||||
void ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba);
|
||||
GSVector4 RealignTargetTextureCoordinate(const GSTextureCache::Source* tex);
|
||||
GSVector4i ComputeBoundingBox(const GSVector2& rtscale, const GSVector2i& rtsize);
|
||||
void MergeSprite(GSTextureCache::Source* tex);
|
||||
GSVector2 GetTextureScaleFactor(const bool force_upscaling);
|
||||
GSVector2 GetTextureScaleFactor() override;
|
||||
GSVector2i GetOutputSize(int real_h);
|
||||
GSVector2i GetTargetSize();
|
||||
|
||||
void Reset(bool hardware_reset) override;
|
||||
|
|
|
@ -83,6 +83,7 @@ void GSTextureCache::RemoveAll()
|
|||
m_hash_cache_memory_usage = 0;
|
||||
|
||||
m_palette_map.Clear();
|
||||
m_target_heights.clear();
|
||||
}
|
||||
|
||||
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette)
|
||||
|
@ -416,7 +417,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
|||
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_h)
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
const GSVector2& new_s = g_gs_renderer->GetTextureScaleFactor();
|
||||
const GSVector2& new_s = static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor();
|
||||
const u32 bp = TEX0.TBP0;
|
||||
GSVector2 res_size{ 0, 0 };
|
||||
GSVector2i new_size{ 0, 0 };
|
||||
|
@ -619,7 +620,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
|
|||
return dst;
|
||||
}
|
||||
|
||||
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h)
|
||||
GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h)
|
||||
{
|
||||
return LookupTarget(TEX0, size, RenderTarget, true, 0, true, real_h);
|
||||
}
|
||||
|
@ -1187,6 +1188,20 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
|||
const int scaled_w = static_cast<int>(w * scale.x);
|
||||
const int scaled_h = static_cast<int>(h * scale.y);
|
||||
|
||||
// Expand the target when we used a more conservative size.
|
||||
const int required_dh = scaled_dy + scaled_h;
|
||||
if ((scaled_dx + scaled_w) <= dst->m_texture->GetWidth() && required_dh > dst->m_texture->GetHeight())
|
||||
{
|
||||
const int new_height = dy + h;
|
||||
if (new_height > GSRendererHW::MAX_FRAMEBUFFER_HEIGHT)
|
||||
return false;
|
||||
|
||||
const int scaled_new_height = static_cast<int>(static_cast<float>(new_height) * scale.y);
|
||||
GL_INS("Resize %dx%d target to %dx%d for move", dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), dst->m_texture->GetHeight(), scaled_new_height);
|
||||
dst->ResizeTexture(dst->m_texture->GetWidth(), scaled_new_height);
|
||||
GetTargetHeight(DBP, DBW, DPSM, new_height);
|
||||
}
|
||||
|
||||
// Make sure the copy doesn't go out of bounds (it shouldn't).
|
||||
if ((scaled_sx + scaled_w) > src->m_texture->GetWidth() || (scaled_sy + scaled_h) > src->m_texture->GetHeight() ||
|
||||
(scaled_dx + scaled_w) > dst->m_texture->GetWidth() || (scaled_dy + scaled_h) > dst->m_texture->GetHeight())
|
||||
|
@ -1230,6 +1245,36 @@ GSTextureCache::Target* GSTextureCache::GetTargetWithSharedBits(u32 BP, u32 PSM)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
u32 GSTextureCache::GetTargetHeight(u32 fbp, u32 fbw, u32 psm, u32 min_height)
|
||||
{
|
||||
TargetHeightElem search = {};
|
||||
search.fbp = fbp;
|
||||
search.fbw = fbw;
|
||||
search.psm = psm;
|
||||
search.height = min_height;
|
||||
|
||||
for (auto it = m_target_heights.begin(); it != m_target_heights.end(); ++it)
|
||||
{
|
||||
TargetHeightElem& elem = const_cast<TargetHeightElem&>(*it);
|
||||
if (elem.bits == search.bits)
|
||||
{
|
||||
if (elem.height < min_height)
|
||||
{
|
||||
DbgCon.WriteLn("Expand height at %x %u %u from %u to %u", fbp, fbw, psm, elem.height, min_height);
|
||||
elem.height = min_height;
|
||||
}
|
||||
|
||||
m_target_heights.MoveFront(it.Index());
|
||||
elem.age = 0;
|
||||
return elem.height;
|
||||
}
|
||||
}
|
||||
|
||||
DbgCon.WriteLn("New height at %x %u %u: %u", fbp, fbw, psm, min_height);
|
||||
m_target_heights.push_front(search);
|
||||
return min_height;
|
||||
}
|
||||
|
||||
// Hack: remove Target that are strictly included in current rt. Typically uses for FMV
|
||||
// For example, game is rendered at 0x800->0x1000, fmv will be uploaded to 0x0->0x2800
|
||||
// FIXME In theory, we ought to report the data from the sub rt to the main rt. But let's
|
||||
|
@ -1345,6 +1390,20 @@ void GSTextureCache::IncAge()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = m_target_heights.begin(); it != m_target_heights.end();)
|
||||
{
|
||||
TargetHeightElem& elem = const_cast<TargetHeightElem&>(*it);
|
||||
if (elem.age >= max_rt_age)
|
||||
{
|
||||
it = m_target_heights.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
elem.age++;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work.
|
||||
|
@ -1822,7 +1881,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int
|
|||
t->m_texture = g_gs_device->CreateSparseDepthStencil(w, h, GSTexture::Format::DepthStencil, clear);
|
||||
}
|
||||
|
||||
t->m_texture->SetScale(g_gs_renderer->GetTextureScaleFactor());
|
||||
t->m_texture->SetScale(static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor());
|
||||
|
||||
m_dst[type].push_front(t);
|
||||
|
||||
|
@ -1999,6 +2058,47 @@ bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i
|
|||
return overlap;
|
||||
}
|
||||
|
||||
void GSTextureCache::Surface::ResizeTexture(int new_width, int new_height)
|
||||
{
|
||||
ResizeTexture(new_width, new_height, m_texture->GetScale());
|
||||
}
|
||||
|
||||
void GSTextureCache::Surface::ResizeTexture(int new_width, int new_height, GSVector2 new_scale)
|
||||
{
|
||||
const int width = m_texture->GetWidth();
|
||||
const int height = m_texture->GetHeight();
|
||||
if (width == new_width && height == new_height)
|
||||
return;
|
||||
|
||||
const bool clear = (new_width > width || new_height > height);
|
||||
GSTexture* tex = m_texture->IsDepthStencil() ?
|
||||
g_gs_device->CreateSparseDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) :
|
||||
g_gs_device->CreateSparseRenderTarget(new_width, new_height, m_texture->GetFormat(), clear);
|
||||
if (!tex)
|
||||
{
|
||||
Console.Error("(GSTextureCache::Surface::ResizeTexture) Failed to allocate %dx%d texture", new_width, new_height);
|
||||
return;
|
||||
}
|
||||
|
||||
tex->SetScale(new_scale);
|
||||
|
||||
const GSVector4i rc(0, 0, std::min(width, new_width), std::min(height, new_height));
|
||||
if (tex->IsDepthStencil())
|
||||
{
|
||||
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
|
||||
// APIs either. So use a fullscreen quad setting depth instead.
|
||||
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fast memcpy()-like path for color targets.
|
||||
g_gs_device->CopyRect(m_texture, tex, rc, 0, 0);
|
||||
}
|
||||
|
||||
g_gs_device->Recycle(m_texture);
|
||||
m_texture = tex;
|
||||
}
|
||||
|
||||
// GSTextureCache::Source
|
||||
|
||||
GSTextureCache::Source::Source(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool dummy_container)
|
||||
|
@ -2410,6 +2510,9 @@ void GSTextureCache::Target::UpdateIfDirtyIntersects(const GSVector4i& rc)
|
|||
|
||||
void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect)
|
||||
{
|
||||
if (m_valid.eq(GSVector4i::zero()))
|
||||
m_valid = rect;
|
||||
else
|
||||
m_valid = m_valid.runion(rect);
|
||||
|
||||
// Block of the bottom right texel of the validity rectangle, last valid block of the texture
|
||||
|
|
|
@ -92,6 +92,9 @@ public:
|
|||
void UpdateAge();
|
||||
bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
|
||||
bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
|
||||
|
||||
void ResizeTexture(int new_width, int new_height);
|
||||
void ResizeTexture(int new_width, int new_height, GSVector2 new_scale);
|
||||
};
|
||||
|
||||
struct PaletteKey
|
||||
|
@ -243,6 +246,25 @@ public:
|
|||
void RemoveAt(Source* s);
|
||||
};
|
||||
|
||||
struct TargetHeightElem
|
||||
{
|
||||
union
|
||||
{
|
||||
u32 bits;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 fbp : 9;
|
||||
u32 fbw : 6;
|
||||
u32 psm : 6;
|
||||
u32 pad : 11;
|
||||
};
|
||||
};
|
||||
|
||||
u32 height;
|
||||
u32 age;
|
||||
};
|
||||
|
||||
struct SurfaceOffsetKeyElem
|
||||
{
|
||||
u32 psm;
|
||||
|
@ -278,6 +300,7 @@ protected:
|
|||
std::unordered_map<HashCacheKey, HashCacheEntry, HashCacheKeyHash> m_hash_cache;
|
||||
u64 m_hash_cache_memory_usage = 0;
|
||||
FastList<Target*> m_dst[2];
|
||||
FastList<TargetHeightElem> m_target_heights;
|
||||
static u8* m_temp;
|
||||
constexpr static size_t S_SURFACE_OFFSET_CACHE_MAX_SIZE = std::numeric_limits<u16>::max();
|
||||
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
|
||||
|
@ -309,12 +332,14 @@ public:
|
|||
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette = false);
|
||||
|
||||
Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask = 0, const bool is_frame = false, const int real_h = 0);
|
||||
Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h);
|
||||
Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h);
|
||||
|
||||
/// Looks up a target in the cache, and only returns it if the BP/BW/PSM match exactly.
|
||||
Target* GetExactTarget(u32 BP, u32 BW, u32 PSM) const;
|
||||
Target* GetTargetWithSharedBits(u32 BP, u32 PSM) const;
|
||||
|
||||
u32 GetTargetHeight(u32 fbp, u32 fbw, u32 psm, u32 min_height);
|
||||
|
||||
void InvalidateVideoMemType(int type, u32 bp);
|
||||
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
|
||||
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true);
|
||||
|
|
|
@ -191,12 +191,6 @@ const char* dialog_message(int ID, bool* updateText)
|
|||
case IDC_DISABLE_PARTIAL_TC_INV:
|
||||
return cvtString("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise."
|
||||
"\n\nThis hack replaces the partial invalidation with a complete deletion of the texture to reduce the CPU load.\n\nIt helps snowblind engine games.");
|
||||
case IDC_CONSERVATIVE_FB:
|
||||
return cvtString("Disabled: Reserves a larger framebuffer to prevent FMV flickers.\n"
|
||||
"Increases GPU/memory requirements.\n"
|
||||
"Disabling this can amplify stuttering due to low RAM/VRAM.\n\n"
|
||||
"Note: It should be enabled for Armored Core, Destroy All Humans, Gran Turismo and possibly others.\n"
|
||||
"This option does not improve the graphics or the FPS.");
|
||||
case IDC_DITHERING:
|
||||
return cvtString("In the PS2's case, it reduces banding between colors and improves the perceived color depth.\n"
|
||||
"In the PS1's case, it was used more aggressively due to 16-bit colour.\n"
|
||||
|
|
|
@ -50,7 +50,6 @@ enum
|
|||
IDC_PRELOAD_TEXTURES,
|
||||
IDC_ACCURATE_DATE,
|
||||
IDC_PALTEX,
|
||||
IDC_CONSERVATIVE_FB,
|
||||
IDC_AFCOMBO,
|
||||
IDC_DITHERING,
|
||||
IDC_MIPMAP_HW,
|
||||
|
|
|
@ -285,7 +285,6 @@ RendererTab::RendererTab(wxWindow* parent)
|
|||
auto* hw_checks_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
|
||||
m_ui.addCheckBox(hw_checks_box, "Accurate Destination Alpha Test", "accurate_date", IDC_ACCURATE_DATE, hw_prereq);
|
||||
m_ui.addCheckBox(hw_checks_box, "Conservative Buffer Allocation", "conservative_framebuffer", IDC_CONSERVATIVE_FB, upscale_prereq);
|
||||
|
||||
auto* paltex_prereq = m_ui.addCheckBox(hw_checks_box, "GPU Palette Conversion", "paltex", IDC_PALTEX, hw_prereq);
|
||||
auto aniso_prereq = [this, paltex_prereq]{ return m_is_hardware && paltex_prereq->GetValue() == false; };
|
||||
|
|
|
@ -270,7 +270,6 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml:
|
|||
|
||||
static const char* s_gs_hw_fix_names[] = {
|
||||
"autoFlush",
|
||||
"conservativeFramebuffer",
|
||||
"cpuFramebufferConversion",
|
||||
"disableDepthSupport",
|
||||
"wrapGSMem",
|
||||
|
@ -317,7 +316,6 @@ bool GameDatabaseSchema::isUserHackHWFix(GSHWFixId id)
|
|||
case GSHWFixId::Deinterlace:
|
||||
case GSHWFixId::Mipmap:
|
||||
case GSHWFixId::TexturePreloading:
|
||||
case GSHWFixId::ConservativeFramebuffer:
|
||||
case GSHWFixId::PointListPalette:
|
||||
return false;
|
||||
|
||||
|
@ -446,9 +444,6 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti
|
|||
case GSHWFixId::AutoFlush:
|
||||
return (static_cast<int>(config.UserHacks_AutoFlush) == value);
|
||||
|
||||
case GSHWFixId::ConservativeFramebuffer:
|
||||
return (static_cast<int>(config.ConservativeFramebuffer) == value);
|
||||
|
||||
case GSHWFixId::CPUFramebufferConversion:
|
||||
return (static_cast<int>(config.UserHacks_CPUFBConversion) == value);
|
||||
|
||||
|
@ -542,10 +537,6 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
|||
config.UserHacks_AutoFlush = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::ConservativeFramebuffer:
|
||||
config.ConservativeFramebuffer = (value > 0);
|
||||
break;
|
||||
|
||||
case GSHWFixId::CPUFramebufferConversion:
|
||||
config.UserHacks_CPUFBConversion = (value > 0);
|
||||
break;
|
||||
|
|
|
@ -60,7 +60,6 @@ namespace GameDatabaseSchema
|
|||
{
|
||||
// boolean settings
|
||||
AutoFlush,
|
||||
ConservativeFramebuffer,
|
||||
CPUFramebufferConversion,
|
||||
DisableDepthSupport,
|
||||
WrapGSMem,
|
||||
|
|
|
@ -325,7 +325,6 @@ Pcsx2Config::GSOptions::GSOptions()
|
|||
HWDisableReadbacks = false;
|
||||
AccurateDATE = true;
|
||||
GPUPaletteConversion = false;
|
||||
ConservativeFramebuffer = true;
|
||||
AutoFlushSW = true;
|
||||
PreloadFrameWithGSData = false;
|
||||
WrapGSMem = false;
|
||||
|
@ -546,7 +545,6 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
|
|||
GSSettingBool(HWDisableReadbacks);
|
||||
GSSettingBoolEx(AccurateDATE, "accurate_date");
|
||||
GSSettingBoolEx(GPUPaletteConversion, "paltex");
|
||||
GSSettingBoolEx(ConservativeFramebuffer, "conservative_framebuffer");
|
||||
GSSettingBoolEx(AutoFlushSW, "autoflush_sw");
|
||||
GSSettingBoolEx(PreloadFrameWithGSData, "preload_frame_with_gs_data");
|
||||
GSSettingBoolEx(WrapGSMem, "wrap_gs_mem");
|
||||
|
|
Loading…
Reference in New Issue