GPU: Add basic texture filtering support

Still has issues around the edges of text.
This commit is contained in:
Connor McLaughlin 2019-12-07 17:03:54 +10:00
parent c284d3835f
commit 67c67bbb66
10 changed files with 105 additions and 69 deletions

View File

@ -24,6 +24,7 @@ bool GPU_HW::Initialize(HostDisplay* host_display, System* system, DMA* dma, Int
m_resolution_scale = std::clamp<u32>(m_system->GetSettings().gpu_resolution_scale, 1, m_max_resolution_scale); m_resolution_scale = std::clamp<u32>(m_system->GetSettings().gpu_resolution_scale, 1, m_max_resolution_scale);
m_system->GetSettings().max_gpu_resolution_scale = m_max_resolution_scale; m_system->GetSettings().max_gpu_resolution_scale = m_max_resolution_scale;
m_true_color = m_system->GetSettings().gpu_true_color; m_true_color = m_system->GetSettings().gpu_true_color;
m_texture_filtering = m_system->GetSettings().gpu_texture_filtering;
return true; return true;
} }
@ -58,6 +59,7 @@ void GPU_HW::UpdateSettings()
m_resolution_scale = std::clamp<u32>(m_system->GetSettings().gpu_resolution_scale, 1, m_max_resolution_scale); m_resolution_scale = std::clamp<u32>(m_system->GetSettings().gpu_resolution_scale, 1, m_max_resolution_scale);
m_true_color = m_system->GetSettings().gpu_true_color; m_true_color = m_system->GetSettings().gpu_true_color;
m_texture_filtering = m_system->GetSettings().gpu_texture_filtering;
} }
void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command_ptr) void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command_ptr)

View File

@ -157,6 +157,7 @@ protected:
u32 m_resolution_scale = 1; u32 m_resolution_scale = 1;
u32 m_max_resolution_scale = 1; u32 m_max_resolution_scale = 1;
bool m_true_color = false; bool m_true_color = false;
bool m_texture_filtering = false;
bool m_supports_dual_source_blend = false; bool m_supports_dual_source_blend = false;
BatchConfig m_batch = {}; BatchConfig m_batch = {};

View File

@ -119,6 +119,7 @@ void GPU_HW_D3D11::UpdateSettings()
GPU_HW::UpdateSettings(); GPU_HW::UpdateSettings();
CreateFramebuffer(); CreateFramebuffer();
CreateStateObjects();
CompileShaders(); CompileShaders();
UpdateDisplay(); UpdateDisplay();
} }
@ -239,7 +240,7 @@ bool GPU_HW_D3D11::CreateBatchInputLayout()
{"ATTR", 3, DXGI_FORMAT_R32_SINT, 0, offsetof(BatchVertex, texpage), D3D11_INPUT_PER_VERTEX_DATA, 0}}}; {"ATTR", 3, DXGI_FORMAT_R32_SINT, 0, offsetof(BatchVertex, texpage), D3D11_INPUT_PER_VERTEX_DATA, 0}}};
// we need a vertex shader... // we need a vertex shader...
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering,
m_supports_dual_source_blend); m_supports_dual_source_blend);
ComPtr<ID3DBlob> vs_bytecode = D3D11::ShaderCompiler::CompileShader( ComPtr<ID3DBlob> vs_bytecode = D3D11::ShaderCompiler::CompileShader(
D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(), shadergen.GenerateBatchVertexShader(true), false); D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(), shadergen.GenerateBatchVertexShader(true), false);
@ -265,49 +266,54 @@ bool GPU_HW_D3D11::CreateStateObjects()
CD3D11_RASTERIZER_DESC rs_desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT()); CD3D11_RASTERIZER_DESC rs_desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
rs_desc.CullMode = D3D11_CULL_NONE; rs_desc.CullMode = D3D11_CULL_NONE;
rs_desc.ScissorEnable = TRUE; rs_desc.ScissorEnable = TRUE;
hr = m_device->CreateRasterizerState(&rs_desc, m_cull_none_rasterizer_state.GetAddressOf()); hr = m_device->CreateRasterizerState(&rs_desc, m_cull_none_rasterizer_state.ReleaseAndGetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
CD3D11_DEPTH_STENCIL_DESC ds_desc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); CD3D11_DEPTH_STENCIL_DESC ds_desc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
ds_desc.DepthEnable = FALSE; ds_desc.DepthEnable = FALSE;
ds_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; ds_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
hr = m_device->CreateDepthStencilState(&ds_desc, m_depth_disabled_state.GetAddressOf()); hr = m_device->CreateDepthStencilState(&ds_desc, m_depth_disabled_state.ReleaseAndGetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
CD3D11_BLEND_DESC bl_desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); CD3D11_BLEND_DESC bl_desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
hr = m_device->CreateBlendState(&bl_desc, m_blend_disabled_state.GetAddressOf()); hr = m_device->CreateBlendState(&bl_desc, m_blend_disabled_state.ReleaseAndGetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
CD3D11_SAMPLER_DESC sampler_desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); CD3D11_SAMPLER_DESC sampler_desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
hr = m_device->CreateSamplerState(&sampler_desc, m_point_sampler_state.GetAddressOf()); hr = m_device->CreateSamplerState(&sampler_desc, m_point_sampler_state.ReleaseAndGetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; sampler_desc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
hr = m_device->CreateSamplerState(&sampler_desc, m_linear_sampler_state.GetAddressOf()); hr = m_device->CreateSamplerState(&sampler_desc, m_linear_sampler_state.ReleaseAndGetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
m_batch_blend_states[static_cast<u8>(TransparencyMode::Disabled)] = m_blend_disabled_state; for (u8 transparency_mode = 0; transparency_mode < 5; transparency_mode++)
for (u8 transparency_mode = 0; transparency_mode < 4; transparency_mode++)
{ {
bl_desc.RenderTarget[0].BlendEnable = TRUE; if (transparency_mode == static_cast<u8>(TransparencyMode::Disabled) && !m_texture_filtering)
bl_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; {
bl_desc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA; bl_desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
bl_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; }
bl_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; else
bl_desc.RenderTarget[0].BlendOp = {
(transparency_mode == static_cast<u8>(TransparencyMode::BackgroundMinusForeground)) ? bl_desc.RenderTarget[0].BlendEnable = TRUE;
D3D11_BLEND_OP_REV_SUBTRACT : bl_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
D3D11_BLEND_OP_ADD; bl_desc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_ALPHA;
bl_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; bl_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bl_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bl_desc.RenderTarget[0].BlendOp =
(transparency_mode == static_cast<u8>(TransparencyMode::BackgroundMinusForeground)) ?
D3D11_BLEND_OP_REV_SUBTRACT :
D3D11_BLEND_OP_ADD;
bl_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
}
hr = m_device->CreateBlendState(&bl_desc, m_batch_blend_states[transparency_mode].GetAddressOf()); hr = m_device->CreateBlendState(&bl_desc, m_batch_blend_states[transparency_mode].ReleaseAndGetAddressOf());
if (FAILED(hr)) if (FAILED(hr))
return false; return false;
} }
@ -317,8 +323,8 @@ bool GPU_HW_D3D11::CreateStateObjects()
bool GPU_HW_D3D11::CompileShaders() bool GPU_HW_D3D11::CompileShaders()
{ {
const bool debug = true; const bool debug = false;
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering,
m_supports_dual_source_blend); m_supports_dual_source_blend);
m_screen_quad_vertex_shader = D3D11::ShaderCompiler::CompileAndCreateVertexShader( m_screen_quad_vertex_shader = D3D11::ShaderCompiler::CompileAndCreateVertexShader(

View File

@ -265,7 +265,7 @@ void GPU_HW_OpenGL::CreateTextureBuffer()
bool GPU_HW_OpenGL::CompilePrograms() bool GPU_HW_OpenGL::CompilePrograms()
{ {
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering,
m_supports_dual_source_blend); m_supports_dual_source_blend);
for (u32 render_mode = 0; render_mode < 4; render_mode++) for (u32 render_mode = 0; render_mode < 4; render_mode++)

View File

@ -189,7 +189,7 @@ void GPU_HW_OpenGL_ES::DestroyFramebuffer()
bool GPU_HW_OpenGL_ES::CompilePrograms() bool GPU_HW_OpenGL_ES::CompilePrograms()
{ {
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering,
m_supports_dual_source_blend); m_supports_dual_source_blend);
for (u32 render_mode = 0; render_mode < 4; render_mode++) for (u32 render_mode = 0; render_mode < 4; render_mode++)

View File

@ -6,10 +6,10 @@
Log_SetChannel(GPU_HW_ShaderGen); Log_SetChannel(GPU_HW_ShaderGen);
GPU_HW_ShaderGen::GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color, GPU_HW_ShaderGen::GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color,
bool supports_dual_source_blend) bool texture_filtering, bool supports_dual_source_blend)
: m_render_api(render_api), m_resolution_scale(resolution_scale), m_true_color(true_color), : m_render_api(render_api), m_resolution_scale(resolution_scale), m_true_color(true_color),
m_glsl(render_api != HostDisplay::RenderAPI::D3D11), m_glsl_es(render_api == HostDisplay::RenderAPI::OpenGLES), m_texture_filering(texture_filtering), m_glsl(render_api != HostDisplay::RenderAPI::D3D11),
m_supports_dual_source_blend(supports_dual_source_blend) m_glsl_es(render_api == HostDisplay::RenderAPI::OpenGLES), m_supports_dual_source_blend(supports_dual_source_blend)
{ {
if (m_glsl) if (m_glsl)
SetGLSLVersionString(); SetGLSLVersionString();
@ -98,8 +98,12 @@ void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
ss << "#define uint3 uvec3\n"; ss << "#define uint3 uvec3\n";
ss << "#define uint4 uvec4\n"; ss << "#define uint4 uvec4\n";
ss << "#define nointerpolation flat\n"; ss << "#define nointerpolation flat\n";
ss << "#define frac fract\n";
ss << "#define lerp mix\n";
ss << "#define CONSTANT const\n"; ss << "#define CONSTANT const\n";
ss << "#define VECTOR_EQ(a, b) ((a) == (b))\n";
ss << "#define VECTOR_NEQ(a, b) ((a) != (b))\n";
ss << "#define SAMPLE_TEXTURE(name, coords) texture(name, coords)\n"; ss << "#define SAMPLE_TEXTURE(name, coords) texture(name, coords)\n";
ss << "#define LOAD_TEXTURE(name, coords, mip) texelFetch(name, coords, mip)\n"; ss << "#define LOAD_TEXTURE(name, coords, mip) texelFetch(name, coords, mip)\n";
ss << "#define LOAD_TEXTURE_OFFSET(name, coords, mip, offset) texelFetchOffset(name, coords, mip, offset)\n"; ss << "#define LOAD_TEXTURE_OFFSET(name, coords, mip, offset) texelFetchOffset(name, coords, mip, offset)\n";
@ -109,6 +113,8 @@ void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
{ {
ss << "#define HLSL 1\n"; ss << "#define HLSL 1\n";
ss << "#define CONSTANT static const\n"; ss << "#define CONSTANT static const\n";
ss << "#define VECTOR_EQ(a, b) (all((a) == (b)))\n";
ss << "#define VECTOR_NEQ(a, b) (any((a) != (b)))\n";
ss << "#define SAMPLE_TEXTURE(name, coords) name.Sample(name##_ss, coords)\n"; ss << "#define SAMPLE_TEXTURE(name, coords) name.Sample(name##_ss, coords)\n";
ss << "#define LOAD_TEXTURE(name, coords, mip) name.Load(int3(coords, mip))\n"; ss << "#define LOAD_TEXTURE(name, coords, mip) name.Load(int3(coords, mip))\n";
ss << "#define LOAD_TEXTURE_OFFSET(name, coords, mip, offset) name.Load(int3(coords, mip), offset)\n"; ss << "#define LOAD_TEXTURE_OFFSET(name, coords, mip, offset) name.Load(int3(coords, mip), offset)\n";
@ -369,7 +375,7 @@ std::string GPU_HW_ShaderGen::GenerateBatchVertexShader(bool textured)
v_col0 = a_col0; v_col0 = a_col0;
#if TEXTURED #if TEXTURED
v_tex0 = float2(float(a_texcoord & 0xFFFF), float(a_texcoord >> 16)) / float2(255.0, 255.0); v_tex0 = float2(float(a_texcoord & 0xFFFF), float(a_texcoord >> 16));
// base_x,base_y,palette_x,palette_y // base_x,base_y,palette_x,palette_y
v_texpage.x = (a_texpage & 15) * 64 * RESOLUTION_SCALE; v_texpage.x = (a_texpage & 15) * 64 * RESOLUTION_SCALE;
@ -389,8 +395,8 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMod
const GPU::TextureMode actual_texture_mode = texture_mode & ~GPU::TextureMode::RawTextureBit; const GPU::TextureMode actual_texture_mode = texture_mode & ~GPU::TextureMode::RawTextureBit;
const bool raw_texture = (texture_mode & GPU::TextureMode::RawTextureBit) == GPU::TextureMode::RawTextureBit; const bool raw_texture = (texture_mode & GPU::TextureMode::RawTextureBit) == GPU::TextureMode::RawTextureBit;
const bool textured = (texture_mode != GPU::TextureMode::Disabled); const bool textured = (texture_mode != GPU::TextureMode::Disabled);
const bool use_dual_source = const bool use_dual_source = m_supports_dual_source_blend &&
m_supports_dual_source_blend && transparency != GPU_HW::BatchRenderMode::TransparencyDisabled; (transparency != GPU_HW::BatchRenderMode::TransparencyDisabled || m_texture_filering);
std::stringstream ss; std::stringstream ss;
WriteHeader(ss); WriteHeader(ss);
@ -406,6 +412,7 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(GPU_HW::BatchRenderMod
DefineMacro(ss, "RAW_TEXTURE", raw_texture); DefineMacro(ss, "RAW_TEXTURE", raw_texture);
DefineMacro(ss, "DITHERING", dithering); DefineMacro(ss, "DITHERING", dithering);
DefineMacro(ss, "TRUE_COLOR", m_true_color); DefineMacro(ss, "TRUE_COLOR", m_true_color);
DefineMacro(ss, "TEXTURE_FILTERING", m_texture_filering);
DefineMacro(ss, "USE_DUAL_SOURCE", use_dual_source); DefineMacro(ss, "USE_DUAL_SOURCE", use_dual_source);
WriteCommonFunctions(ss); WriteCommonFunctions(ss);
@ -442,27 +449,17 @@ int3 TruncateTo15Bit(int3 icol)
} }
#if TEXTURED #if TEXTURED
int2 ApplyNativeTextureWindow(int2 coords) CONSTANT float4 TRANSPARENT_PIXEL_COLOR = float4(0.0, 0.0, 0.0, 0.0);
int2 ApplyTextureWindow(int2 coords)
{ {
uint x = (uint(coords.x) & ~(u_texture_window_mask.x * 8u)) | ((u_texture_window_offset.x & u_texture_window_mask.x) * 8u); uint x = (uint(coords.x) & ~(u_texture_window_mask.x * 8u)) | ((u_texture_window_offset.x & u_texture_window_mask.x) * 8u);
uint y = (uint(coords.y) & ~(u_texture_window_mask.y * 8u)) | ((u_texture_window_offset.y & u_texture_window_mask.y) * 8u); uint y = (uint(coords.y) & ~(u_texture_window_mask.y * 8u)) | ((u_texture_window_offset.y & u_texture_window_mask.y) * 8u);
return int2(int(x), int(y)); return int2(int(x), int(y));
} }
int2 ApplyTextureWindow(int2 coords) float4 SampleFromVRAM(int4 texpage, int2 icoord)
{ {
if (RESOLUTION_SCALE == 1)
return ApplyNativeTextureWindow(coords);
int2 downscaled_coords = coords / int2(RESOLUTION_SCALE, RESOLUTION_SCALE);
int2 coords_offset = coords % int2(RESOLUTION_SCALE, RESOLUTION_SCALE);
return (ApplyNativeTextureWindow(downscaled_coords) * int2(RESOLUTION_SCALE, RESOLUTION_SCALE)) + coords_offset;
}
int4 SampleFromVRAM(int4 texpage, float2 coord)
{
// from 0..1 to 0..255
int2 icoord = int2(coord * float2(float(255 * RESOLUTION_SCALE), float(255 * RESOLUTION_SCALE)));
icoord = ApplyTextureWindow(icoord); icoord = ApplyTextureWindow(icoord);
// adjust for tightly packed palette formats // adjust for tightly packed palette formats
@ -474,7 +471,7 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
#endif #endif
// fixup coords // fixup coords
int2 vicoord = int2(texpage.x + index_coord.x, fixYCoord(texpage.y + index_coord.y)); int2 vicoord = int2(texpage.x + index_coord.x * RESOLUTION_SCALE, fixYCoord(texpage.y + index_coord.y * RESOLUTION_SCALE));
// load colour/palette // load colour/palette
float4 color = LOAD_TEXTURE(samp0, vicoord, 0); float4 color = LOAD_TEXTURE(samp0, vicoord, 0);
@ -482,11 +479,11 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
// apply palette // apply palette
#if PALETTE #if PALETTE
#if PALETTE_4_BIT #if PALETTE_4_BIT
int subpixel = int(icoord.x / RESOLUTION_SCALE) & 3; int subpixel = int(icoord.x) & 3;
uint vram_value = RGBA8ToRGBA5551(color); uint vram_value = RGBA8ToRGBA5551(color);
int palette_index = int((vram_value >> (subpixel * 4)) & 0x0Fu); int palette_index = int((vram_value >> (subpixel * 4)) & 0x0Fu);
#elif PALETTE_8_BIT #elif PALETTE_8_BIT
int subpixel = int(icoord.x / RESOLUTION_SCALE) & 1; int subpixel = int(icoord.x) & 1;
uint vram_value = RGBA8ToRGBA5551(color); uint vram_value = RGBA8ToRGBA5551(color);
int palette_index = int((vram_value >> (subpixel * 8)) & 0xFFu); int palette_index = int((vram_value >> (subpixel * 8)) & 0xFFu);
#endif #endif
@ -494,7 +491,7 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
color = LOAD_TEXTURE(samp0, palette_icoord, 0); color = LOAD_TEXTURE(samp0, palette_icoord, 0);
#endif #endif
return int4(color * float4(255.0, 255.0, 255.0, 255.0)); return color;
} }
#endif #endif
)"; )";
@ -513,31 +510,55 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
int3 vertcol = int3(v_col0.rgb * float3(255.0, 255.0, 255.0)); int3 vertcol = int3(v_col0.rgb * float3(255.0, 255.0, 255.0));
bool semitransparent; bool semitransparent;
bool new_mask_bit;
int3 icolor; int3 icolor;
float ialpha;
#if TEXTURED #if TEXTURED
int4 texcol = SampleFromVRAM(v_texpage, v_tex0); #if TEXTURE_FILTERING
#if GLSL int2 icoord = int2(v_tex0);
bool transparent = (texcol == int4(0.0, 0.0, 0.0, 0.0)); float2 pcoord = frac(v_tex0) - float2(0.5, 0.5);
#else float2 poffs = sign(pcoord);
bool transparent = (all(texcol == int4(0.0, 0.0, 0.0, 0.0))); pcoord = abs(pcoord);
#endif
if (transparent)
discard;
// Grab semitransparent bit from the texture color. // TODO: Clamp to page
semitransparent = (texcol.a != 0); float4 tl = SampleFromVRAM(v_texpage, int2(v_tex0));
float4 tr = SampleFromVRAM(v_texpage, int2(min(v_tex0.x + poffs.x, 255.0), v_tex0.y));
float4 bl = SampleFromVRAM(v_texpage, int2(v_tex0.x, min(v_tex0.y + poffs.y, 255.0)));
float4 br = SampleFromVRAM(v_texpage, int2(min(v_tex0.x + poffs.x, 255.0), min(v_tex0.y + poffs.y, 255.0)));
// Compute alpha from how many texels aren't pixel color 0000h.
float tl_a = float(VECTOR_NEQ(tl, TRANSPARENT_PIXEL_COLOR));
float tr_a = float(VECTOR_NEQ(tr, TRANSPARENT_PIXEL_COLOR));
float bl_a = float(VECTOR_NEQ(bl, TRANSPARENT_PIXEL_COLOR));
float br_a = float(VECTOR_NEQ(br, TRANSPARENT_PIXEL_COLOR));
// Bilinearly interpolate.
float4 texcol = lerp(lerp(tl, tr, pcoord.x), lerp(bl, br, pcoord.x), pcoord.y);
ialpha = lerp(lerp(tl_a, tr_a, pcoord.x), lerp(bl_a, br_a, pcoord.x), pcoord.y);
if (ialpha == 0.0)
discard;
texcol.rgb /= float3(ialpha, ialpha, ialpha);
semitransparent = (texcol.a != 0.0);
#else
float4 texcol = SampleFromVRAM(v_texpage, int2(v_tex0));
if (VECTOR_EQ(texcol, TRANSPARENT_PIXEL_COLOR))
discard;
semitransparent = (texcol.a != 0.0);
ialpha = 1.0;
#endif
#if RAW_TEXTURE #if RAW_TEXTURE
icolor = texcol.rgb; icolor = int3(texcol.rgb * float3(255.0, 255.0, 255.0));
#else #else
icolor = (vertcol * texcol.rgb) >> 7; icolor = (vertcol * int3(texcol.rgb * float3(255.0, 255.0, 255.0))) >> 7;
#endif #endif
#else #else
// All pixels are semitransparent for untextured polygons. // All pixels are semitransparent for untextured polygons.
semitransparent = true; semitransparent = true;
icolor = vertcol; icolor = vertcol;
ialpha = 1.0;
#endif #endif
// Apply dithering // Apply dithering
@ -565,10 +586,10 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
#endif #endif
#if USE_DUAL_SOURCE #if USE_DUAL_SOURCE
o_col0 = float4(color * u_src_alpha_factor, output_alpha); o_col0 = float4(color * (u_src_alpha_factor * ialpha), output_alpha);
o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor); o_col1 = float4(0.0, 0.0, 0.0, u_dst_alpha_factor / ialpha);
#else #else
o_col0 = float4(color * u_src_alpha_factor, u_dst_alpha_factor); o_col0 = float4(color * (u_src_alpha_factor * ialpha), u_dst_alpha_factor / ialpha);
#endif #endif
} }
else else
@ -578,18 +599,18 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
#endif #endif
#if USE_DUAL_SOURCE #if USE_DUAL_SOURCE
o_col0 = float4(color, output_alpha); o_col0 = float4(color * ialpha, output_alpha);
o_col1 = float4(0.0, 0.0, 0.0, 0.0); o_col1 = float4(0.0, 0.0, 0.0, 0.0);
#else #else
o_col0 = float4(color, 0.0); o_col0 = float4(color * ialpha, 1.0 - ialpha);
#endif #endif
} }
#else #else
// Non-transparency won't enable blending so we can write the mask here regardless. // Non-transparency won't enable blending so we can write the mask here regardless.
o_col0 = float4(color, output_alpha); o_col0 = float4(color * ialpha, output_alpha);
#if USE_DUAL_SOURCE #if USE_DUAL_SOURCE
o_col1 = float4(0.0, 0.0, 0.0, 0.0); o_col1 = float4(0.0, 0.0, 0.0, 1.0 - ialpha);
#endif #endif
#endif #endif
} }

View File

@ -8,7 +8,7 @@ class GPU_HW_ShaderGen
{ {
public: public:
GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color, GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color,
bool supports_dual_source_belnd); bool texture_filtering, bool supports_dual_source_belnd);
~GPU_HW_ShaderGen(); ~GPU_HW_ShaderGen();
std::string GenerateBatchVertexShader(bool textured); std::string GenerateBatchVertexShader(bool textured);
@ -25,6 +25,7 @@ public:
HostDisplay::RenderAPI m_render_api; HostDisplay::RenderAPI m_render_api;
u32 m_resolution_scale; u32 m_resolution_scale;
bool m_true_color; bool m_true_color;
bool m_texture_filering;
bool m_glsl; bool m_glsl;
bool m_glsl_es; bool m_glsl_es;
bool m_supports_dual_source_blend; bool m_supports_dual_source_blend;

View File

@ -57,6 +57,7 @@ void Settings::Load(const char* filename)
gpu_renderer = ParseRendererName(ini.GetValue("GPU", "Renderer", "OpenGL")).value_or(GPURenderer::HardwareOpenGL); gpu_renderer = ParseRendererName(ini.GetValue("GPU", "Renderer", "OpenGL")).value_or(GPURenderer::HardwareOpenGL);
gpu_resolution_scale = static_cast<u32>(ini.GetLongValue("GPU", "ResolutionScale", 1)); gpu_resolution_scale = static_cast<u32>(ini.GetLongValue("GPU", "ResolutionScale", 1));
gpu_true_color = ini.GetBoolValue("GPU", "TrueColor", false); gpu_true_color = ini.GetBoolValue("GPU", "TrueColor", false);
gpu_texture_filtering = ini.GetBoolValue("GPU", "TextureFiltering", false);
display_linear_filtering = ini.GetBoolValue("Display", "LinearFiltering", true); display_linear_filtering = ini.GetBoolValue("Display", "LinearFiltering", true);
@ -89,6 +90,7 @@ bool Settings::Save(const char* filename) const
ini.SetLongValue("GPU", "ResolutionScale", static_cast<long>(gpu_resolution_scale)); ini.SetLongValue("GPU", "ResolutionScale", static_cast<long>(gpu_resolution_scale));
ini.SetBoolValue("GPU", "VSync", video_sync_enabled); ini.SetBoolValue("GPU", "VSync", video_sync_enabled);
ini.SetBoolValue("GPU", "TrueColor", gpu_true_color); ini.SetBoolValue("GPU", "TrueColor", gpu_true_color);
ini.SetBoolValue("GPU", "TextureFiltering", gpu_texture_filtering);
ini.SetBoolValue("Display", "LinearFiltering", display_linear_filtering); ini.SetBoolValue("Display", "LinearFiltering", display_linear_filtering);

View File

@ -20,6 +20,7 @@ struct Settings
u32 gpu_resolution_scale = 1; u32 gpu_resolution_scale = 1;
mutable u32 max_gpu_resolution_scale = 1; mutable u32 max_gpu_resolution_scale = 1;
bool gpu_true_color = false; bool gpu_true_color = false;
bool gpu_texture_filtering = false;
bool display_linear_filtering = true; bool display_linear_filtering = true;
bool display_fullscreen = false; bool display_fullscreen = false;

View File

@ -850,6 +850,7 @@ void SDLHostInterface::DrawQuickSettingsMenu()
} }
gpu_settings_changed |= ImGui::MenuItem("True (24-Bit) Color", nullptr, &m_settings.gpu_true_color); gpu_settings_changed |= ImGui::MenuItem("True (24-Bit) Color", nullptr, &m_settings.gpu_true_color);
gpu_settings_changed |= ImGui::MenuItem("Texture Filtering", nullptr, &m_settings.gpu_texture_filtering);
if (ImGui::MenuItem("Display Linear Filtering", nullptr, &m_settings.display_linear_filtering)) if (ImGui::MenuItem("Display Linear Filtering", nullptr, &m_settings.display_linear_filtering))
{ {
m_display->SetDisplayLinearFiltering(m_settings.display_linear_filtering); m_display->SetDisplayLinearFiltering(m_settings.display_linear_filtering);
@ -1180,6 +1181,7 @@ void SDLHostInterface::DrawSettingsWindow()
} }
ImGui::Checkbox("True 24-bit Color (disables dithering)", &m_settings.gpu_true_color); ImGui::Checkbox("True 24-bit Color (disables dithering)", &m_settings.gpu_true_color);
ImGui::Checkbox("Texture Filtering", &m_settings.gpu_texture_filtering);
} }
ImGui::EndTabItem(); ImGui::EndTabItem();