Skip to content

Commit

Permalink
gsdx: split texture filtering option
Browse files Browse the repository at this point in the history
Bilinear applies to all renderer
* Common code done in GSVertexTrace
* Extend it with forced but sprite (trade-off between linear/upscale glitches)
* Linux GUI option was moved at the top with the renderer selection

Trilinear is moved to OGL hack

close #1837

Thanks to Flatout for the review and feedback.
It will take care to update the Window GUI :)
  • Loading branch information
gregory38 committed Mar 10, 2017
1 parent f443804 commit b54a824
Show file tree
Hide file tree
Showing 17 changed files with 111 additions and 115 deletions.
17 changes: 11 additions & 6 deletions plugins/GSdx/GS.h
Expand Up @@ -1416,14 +1416,19 @@ enum class GSVideoMode : uint8
DTV_1080I
};

enum class Filtering : uint8
enum class BiFiltering : uint8
{
Nearest,
Bilinear_Forced,
Bilinear_PS2,
Trilinear,
Trilinear_Bilinear_Forced,
Trilinear_Always
PS2,
Forced_But_Sprite,
Forced,
};

enum class TriFiltering : uint8
{
None,
PS2,
Forced,
};

enum class CRCHackLevel : uint8
Expand Down
7 changes: 4 additions & 3 deletions plugins/GSdx/GSDeviceOGL.cpp
Expand Up @@ -76,7 +76,9 @@ GSDeviceOGL::GSDeviceOGL()
GLState::Clear();

m_mipmap = theApp.GetConfigI("mipmap");
m_filter = static_cast<Filtering>(theApp.GetConfigI("filter"));
m_filter = static_cast<TriFiltering>(theApp.GetConfigI("UserHacks_TriFilter"));
if (!theApp.GetConfigB("UserHacks"))
m_filter = TriFiltering::None;

// Reset the debug file
#ifdef ENABLE_OGL_DEBUG
Expand Down Expand Up @@ -234,9 +236,8 @@ GSTexture* GSDeviceOGL::CreateSurface(int type, int w, int h, bool msaa, int fmt
{
GL_PUSH("Create surface");

bool trilinear = m_filter == Filtering::Trilinear || m_filter == Filtering::Trilinear_Bilinear_Forced || m_filter == Filtering::Trilinear_Always;
// A wrapper to call GSTextureOGL, with the different kind of parameter
GSTextureOGL* t = new GSTextureOGL(type, w, h, fmt, m_fbo_read, m_mipmap > 1 || trilinear);
GSTextureOGL* t = new GSTextureOGL(type, w, h, fmt, m_fbo_read, m_mipmap > 1 || m_filter != TriFiltering::None);

// NOTE: I'm not sure RenderTarget always need to be cleared. It could be costly for big upscale.
// FIXME: it will be more logical to do it in FetchSurface. This code is only called at first creation
Expand Down
2 changes: 1 addition & 1 deletion plugins/GSdx/GSDeviceOGL.h
Expand Up @@ -411,7 +411,7 @@ class GSDeviceOGL final : public GSDevice
uint32 m_msaa; // Level of Msaa
int m_force_texture_clear;
int m_mipmap;
Filtering m_filter;
TriFiltering m_filter;

static bool m_debug_gl_call;
static FILE* m_debug_gl_file;
Expand Down
14 changes: 9 additions & 5 deletions plugins/GSdx/GSLinuxDialog.cpp
Expand Up @@ -219,9 +219,6 @@ GtkWidget* CreateTableInBox(GtkWidget* parent_box, const char* frame_title, int

void populate_hw_table(GtkWidget* hw_table)
{
GtkWidget* filter_label = left_label("Texture Filtering:");
GtkWidget* filter_combo_box = CreateComboBoxFromVector(theApp.m_gs_filter, "filter");

GtkWidget* fsaa_label = left_label("Internal Resolution:");
GtkWidget* fsaa_combo_box = CreateComboBoxFromVector(theApp.m_gs_upscale_multiplier, "upscale_multiplier");

Expand Down Expand Up @@ -249,7 +246,6 @@ void populate_hw_table(GtkWidget* hw_table)
AddTooltip(large_fb_check, IDC_LARGE_FB);
AddTooltip(crc_label, crc_combo_box, IDC_CRC_LEVEL);
AddTooltip(acc_bld_label, acc_bld_combo_box, IDC_ACCURATE_BLEND_UNIT);
AddTooltip(filter_label, filter_combo_box, IDC_FILTER);
AddTooltip(af_label, af_combo_box, IDC_AFCOMBO);
gtk_widget_set_tooltip_text(hack_enable_check, "Enable the HW hack option panel");
AddTooltip(mipmap_label, IDC_MIPMAP_HW);
Expand All @@ -259,7 +255,6 @@ void populate_hw_table(GtkWidget* hw_table)
InsertWidgetInTable(hw_table , paltex_check , acc_date_check);
InsertWidgetInTable(hw_table , large_fb_check, hack_enable_check);
InsertWidgetInTable(hw_table , fsaa_label , fsaa_combo_box);
InsertWidgetInTable(hw_table , filter_label , filter_combo_box);
InsertWidgetInTable(hw_table , af_label , af_combo_box);
InsertWidgetInTable(hw_table , acc_bld_label , acc_bld_combo_box);
InsertWidgetInTable(hw_table , crc_label , crc_combo_box);
Expand Down Expand Up @@ -359,6 +354,8 @@ void populate_hack_table(GtkWidget* hack_table)
GtkWidget* hack_sprite_label = left_label("Alpha-Sprite Hack:");
GtkWidget* stretch_hack_box = CreateComboBoxFromVector(theApp.m_gs_hack, "UserHacks_round_sprite_offset");
GtkWidget* stretch_hack_label = left_label("Align Sprite Texture:");
GtkWidget* trilinear_box = CreateComboBoxFromVector(theApp.m_gs_trifilter, "UserHacks_TriFilter");
GtkWidget* trilinear_label = left_label("Trilinear Filtering:");

// Reuse windows helper string :)
AddTooltip(hack_offset_label, IDC_OFFSETHACK);
Expand All @@ -376,6 +373,8 @@ void populate_hack_table(GtkWidget* hack_table)
AddTooltip(hack_depth_check, IDC_TC_DEPTH);
AddTooltip(hack_auto_flush, IDC_AUTO_FLUSH);
AddTooltip(hack_unscale_prim, IDC_UNSCALE_POINT_LINE);
AddTooltip(trilinear_box, IDC_TRI_FILTER);
AddTooltip(trilinear_label, IDC_TRI_FILTER);


s_table_line = 0;
Expand All @@ -390,6 +389,7 @@ void populate_hack_table(GtkWidget* hack_table)
InsertWidgetInTable(hack_table , stretch_hack_label , stretch_hack_box );
InsertWidgetInTable(hack_table , hack_skipdraw_label , hack_skipdraw_spin);
InsertWidgetInTable(hack_table , hack_tco_label , hack_tco_entry);
InsertWidgetInTable(hack_table , trilinear_label , trilinear_box);
}

void populate_main_table(GtkWidget* main_table)
Expand All @@ -398,11 +398,15 @@ void populate_main_table(GtkWidget* main_table)
GtkWidget* render_combo_box = CreateComboBoxFromVector(theApp.m_gs_renderers, "Renderer");
GtkWidget* interlace_label = left_label("Interlacing (F5):");
GtkWidget* interlace_combo_box = CreateComboBoxFromVector(theApp.m_gs_interlace, "interlace");
GtkWidget* filter_label = left_label("Texture Filtering:");
GtkWidget* filter_combo_box = CreateComboBoxFromVector(theApp.m_gs_bifilter, "filter");

AddTooltip(filter_label, filter_combo_box, IDC_FILTER);

s_table_line = 0;
InsertWidgetInTable(main_table, render_label, render_combo_box);
InsertWidgetInTable(main_table, interlace_label, interlace_combo_box);
InsertWidgetInTable(main_table, filter_label , filter_combo_box);
}

void populate_debug_table(GtkWidget* debug_table)
Expand Down
1 change: 0 additions & 1 deletion plugins/GSdx/GSRenderer.cpp
Expand Up @@ -45,7 +45,6 @@ GSRenderer::GSRenderer()
m_interlace = theApp.GetConfigI("interlace") % s_interlace_nb;
m_aspectratio = theApp.GetConfigI("AspectRatio") % s_aspect_ratio_nb;
m_shader = theApp.GetConfigI("TVShader") % s_post_shader_nb;
m_filter = static_cast<Filtering>(theApp.GetConfigI("filter"));
m_vsync = theApp.GetConfigB("vsync");
m_aa1 = theApp.GetConfigB("aa1");
m_fxaa = theApp.GetConfigB("fxaa");
Expand Down
1 change: 0 additions & 1 deletion plugins/GSdx/GSRenderer.h
Expand Up @@ -48,7 +48,6 @@ class GSRenderer : public GSState
bool m_fxaa;
bool m_shadeboost;
bool m_texture_shuffle;
Filtering m_filter;
GSVector2i m_real_size;

virtual GSTexture* GetOutput(int i, int& y_offset) = 0;
Expand Down
4 changes: 1 addition & 3 deletions plugins/GSdx/GSRendererDX.cpp
Expand Up @@ -478,10 +478,8 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
// After the conversion the texture will be RGBA8 (aka 32 bits) hence the 0 below
int gpu_tex_fmt = (tex->m_target) ? cpsm.fmt : 0;

bool bilinear = m_filter == Filtering::Bilinear_PS2 || m_filter == Filtering::Trilinear ? m_vt.IsLinear() : m_filter != Filtering::Nearest;
bool bilinear = m_vt.IsLinear();
bool simple_sample = !tex->m_palette && gpu_tex_fmt == 0 && m_context->CLAMP.WMS < 2 && m_context->CLAMP.WMT < 2;
// Don't force extra filtering on sprite (it creates various upscaling issue)
bilinear &= !((m_vt.m_primclass == GS_SPRITE_CLASS) && m_userhacks_round_sprite_offset && !m_vt.IsLinear());

ps_sel.wms = m_context->CLAMP.WMS;
ps_sel.wmt = m_context->CLAMP.WMT;
Expand Down
36 changes: 8 additions & 28 deletions plugins/GSdx/GSRendererOGL.cpp
Expand Up @@ -40,6 +40,7 @@ GSRendererOGL::GSRendererOGL()
UserHacks_merge_sprite = theApp.GetConfigB("UserHacks_merge_pp_sprite");
UserHacks_unscale_pt_ln = theApp.GetConfigB("UserHacks_unscale_point_line");
UserHacks_HPO = theApp.GetConfigI("UserHacks_HalfPixelOffset");
UserHacks_tri_filter = static_cast<TriFiltering>(theApp.GetConfigI("UserHacks_TriFilter"));

m_prim_overlap = PRIM_OVERLAP_UNKNOW;
ResetStates();
Expand All @@ -51,6 +52,7 @@ GSRendererOGL::GSRendererOGL()
UserHacks_merge_sprite = false;
UserHacks_unscale_pt_ln = false;
UserHacks_HPO = 0;
UserHacks_tri_filter = TriFiltering::None;
}
}

Expand Down Expand Up @@ -744,7 +746,7 @@ void GSRendererOGL::RealignTargetTextureCoordinate(const GSTextureCache::Source*

GSVertex* v = &m_vertex.buff[0];
const GSVector2& scale = tex->m_texture->GetScale();
bool linear = m_vt.IsLinear();
bool linear = m_vt.IsRealLinear();
int t_position = v[0].U;
GSVector4 half_offset(0.0f);

Expand Down Expand Up @@ -814,50 +816,28 @@ void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex)
bool shader_emulated_sampler = tex->m_palette || cpsm.fmt != 0 || complex_wms_wmt || psm.depth;
bool trilinear_manual = need_mipmap && m_mipmap == 2;

bool bilinear = false;
bool bilinear = m_vt.IsLinear();
int trilinear = 0;
bool trilinear_auto = false;
switch (m_filter)
switch (UserHacks_tri_filter)
{
case Filtering::Nearest:
bilinear = false;
break;

case Filtering::Bilinear_Forced:
bilinear = true;
break;

case Filtering::Bilinear_PS2:
bilinear = m_vt.IsLinear();
break;

case Filtering::Trilinear_Always:
bilinear = true;
case TriFiltering::Forced:
trilinear = static_cast<uint8>(GS_MIN_FILTER::Linear_Mipmap_Linear);
trilinear_auto = m_mipmap != 2;
break;

case Filtering::Trilinear:
bilinear = m_vt.IsLinear();
case TriFiltering::PS2:
if (need_mipmap && m_mipmap != 2) {
trilinear = m_context->TEX1.MMIN;
trilinear_auto = true;
}
break;

case Filtering::Trilinear_Bilinear_Forced:
bilinear = true;
if (need_mipmap && m_mipmap != 2) {
trilinear = (m_context->TEX1.MMIN | 4) & 0x5;
trilinear_auto = true;
}
case TriFiltering::None:
default:
break;
}

// Don't force extra filtering on sprite (it creates various upscaling issue)
bilinear &= !((m_vt.m_primclass == GS_SPRITE_CLASS) && m_userhacks_round_sprite_offset && !m_vt.IsLinear());

// 1 and 0 are equivalent
m_ps_sel.wms = (wms & 2) ? wms : 0;
m_ps_sel.wmt = (wmt & 2) ? wmt : 0;
Expand Down
1 change: 1 addition & 0 deletions plugins/GSdx/GSRendererOGL.h
Expand Up @@ -55,6 +55,7 @@ class GSRendererOGL final : public GSRendererHW
bool UserHacks_merge_sprite;
bool UserHacks_unscale_pt_ln;
int UserHacks_HPO;
TriFiltering UserHacks_tri_filter;

GSDeviceOGL::VSConstantBuffer vs_cb;
GSDeviceOGL::PSConstantBuffer ps_cb;
Expand Down
12 changes: 9 additions & 3 deletions plugins/GSdx/GSSetting.cpp
Expand Up @@ -33,11 +33,17 @@ const char* dialog_message(int ID, bool* updateText) {
case IDC_FILTER:
return "Control the texture filtering of the emulation.\n\n"
"Nearest:\nAlways disable interpolation, rendering will be blocky.\n\n"
"Bilinear Forced (excluding sprite):\nAlways enable interpolation except for sprites (FMV/Text/2D elements)."
" Rendering is smoother but it could generate a few glitches. If upscaling is enabled, this setting is recommended over 'Bilinear Forced'\n\n"
"Bilinear Forced:\nAlways enable interpolation. Rendering is smoother but it could generate some glitches.\n\n"
"Bilinear PS2:\nUse same mode as the PS2. It is the more accurate option.\n\n"
"Bilinear PS2:\nUse same mode as the PS2. It is the more accurate option.\n\n";
#ifdef __unix__
case IDC_TRI_FILTER:
return "Control the texture tri-filtering of the emulation.\n\n"
"None:\nNo extra trilinear filtering.\n\n"
"Trilinear:\nUse OpenGL trilinear interpolation when PS2 uses mipmaps.\n\n"
"Trilinear Forced Bilinear:\nSame as above but always enable bilinear interpolation.\n\n"
"Trilinear Ultra:\nAlways enable full trilinear interpolation. Warning Slow!\n\n";
"Trilinear Forced:\nAlways enable full trilinear interpolation. Warning Slow!\n\n";
#endif
case IDC_CRC_LEVEL:
return "Control the number of Auto-CRC hacks applied to games.\n\n"
"None:\nRemove nearly all CRC hacks (debug only).\n\n"
Expand Down
1 change: 1 addition & 0 deletions plugins/GSdx/GSSetting.h
Expand Up @@ -43,6 +43,7 @@ const char* dialog_message(int ID, bool* updateText = NULL);
#ifndef _WIN32
enum {
IDC_FILTER,
IDC_TRI_FILTER,
IDC_SKIPDRAWHACK,
IDC_SKIPDRAWHACKEDIT,
IDC_ALPHAHACK,
Expand Down
27 changes: 1 addition & 26 deletions plugins/GSdx/GSSettingsDlg.cpp
Expand Up @@ -151,7 +151,7 @@ void GSSettingsDlg::OnInit()
ComboBoxInit(IDC_INTERLACE, theApp.m_gs_interlace, theApp.GetConfigI("interlace"));
ComboBoxInit(IDC_UPSCALE_MULTIPLIER, theApp.m_gs_upscale_multiplier, theApp.GetConfigI("upscale_multiplier"));
ComboBoxInit(IDC_AFCOMBO, theApp.m_gs_max_anisotropy, theApp.GetConfigI("MaxAnisotropy"));
ComboBoxInit(IDC_FILTER, theApp.m_gs_filter, theApp.GetConfigI("filter"));
ComboBoxInit(IDC_FILTER, theApp.m_gs_bifilter, theApp.GetConfigI("filter"));
ComboBoxInit(IDC_ACCURATE_BLEND_UNIT, theApp.m_gs_acc_blend_level, theApp.GetConfigI("accurate_blending_unit"));
ComboBoxInit(IDC_CRC_LEVEL, theApp.m_gs_crc_level, theApp.GetConfigI("crc_hack_level"));

Expand Down Expand Up @@ -190,33 +190,9 @@ void GSSettingsDlg::OnInit()
AddTooltip(IDC_LOGZ);
AddTooltip(IDC_LARGE_FB);

UpdateFilteringCombobox();
UpdateControls();
}

void GSSettingsDlg::UpdateFilteringCombobox()
{
INT_PTR i;
ComboBoxGetSelData(IDC_RENDERER, i);
bool opengl = static_cast<GSRendererType>(i) == GSRendererType::OGL_HW;
bool hw_mode = opengl || static_cast<GSRendererType>(i) == GSRendererType::DX1011_HW || static_cast<GSRendererType>(i) == GSRendererType::DX9_HW;
if (!hw_mode)
return;

uint8 filter = (ComboBoxGetSelData(IDC_FILTER, i)) ? static_cast<uint8>(i) : static_cast<uint8>(theApp.GetConfigI("filter"));
if (!opengl) //Currently Trilinear is only exclusive to OpenGL, remove those combobox items when any other renderer is used
{
auto head = theApp.m_gs_filter.begin();
auto tail = head + static_cast<uint8>(Filtering::Trilinear);
vector<GSSetting> list(head, tail);
ComboBoxInit(IDC_FILTER, list, std::max(uint8(Filtering::Nearest), std::min(filter, uint8(Filtering::Bilinear_PS2))));
}
else
{
ComboBoxInit(IDC_FILTER, theApp.m_gs_filter, filter);
}
}

bool GSSettingsDlg::OnCommand(HWND hWnd, UINT id, UINT code)
{
switch (id)
Expand All @@ -231,7 +207,6 @@ bool GSSettingsDlg::OnCommand(HWND hWnd, UINT id, UINT code)
case IDC_RENDERER:
if (code == CBN_SELCHANGE)
{
UpdateFilteringCombobox();
UpdateControls();
}
break;
Expand Down
3 changes: 1 addition & 2 deletions plugins/GSdx/GSSettingsDlg.h
Expand Up @@ -88,15 +88,14 @@ class GSSettingsDlg : public GSDialog
D3D_FEATURE_LEVEL level;
Adapter(const std::string &n, const std::string &i, const D3D_FEATURE_LEVEL &l) : name(n), id(i), level(l) {}
};

std::vector<Adapter> adapters;

vector<GSSetting> m_ocl_devs;
uint32 m_lastValidMsaa; // used to revert to previous dialog value if the user changed to invalid one, or lesser one and canceled

void UpdateRenderers();
void UpdateControls();
void UpdateFilteringCombobox();

protected:
void OnInit();
Expand Down

0 comments on commit b54a824

Please sign in to comment.