mirror of
https://github.com/stenzek/duckstation.git
synced 2025-12-28 05:24:19 +00:00
GPU: Add option to crop vertex colours before modulation
aka "old" GPU.
This commit is contained in:
parent
ad0312ec82
commit
b55f4041bf
@ -3957,6 +3957,11 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
|
||||
MenuHeading(FSUI_VSTR("Advanced Rendering Options"));
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_BOLT, "Threaded Rendering"),
|
||||
FSUI_VSTR("Uses a second thread for drawing graphics. Provides a significant speed improvement "
|
||||
"particularly with the software renderer, and is safe to use."),
|
||||
"GPU", "UseThread", true);
|
||||
|
||||
if (is_hardware)
|
||||
{
|
||||
DrawEnumSetting(bsi, FSUI_ICONVSTR(ICON_FA_GRIP_LINES_VERTICAL, "Line Detection"),
|
||||
@ -3971,6 +3976,11 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"less noticeable. Usually safe to enable."),
|
||||
"GPU", "ScaledInterlacing", true, resolution_scale > 1);
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_SWATCHBOOK, "Texture Modulation Cropping (\"Old/v0\" GPU)"),
|
||||
FSUI_VSTR("Crops vertex colours to 5:5:5 before modulating with the texture colour, which "
|
||||
"typically results in more visible banding."),
|
||||
"GPU", "EnableModulationCrop", false);
|
||||
|
||||
DrawToggleSetting(
|
||||
bsi, FSUI_ICONVSTR(ICON_FA_DOWNLOAD, "Use Software Renderer For Readbacks"),
|
||||
FSUI_VSTR("Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in "
|
||||
@ -3978,11 +3988,6 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"GPU", "UseSoftwareRendererForReadbacks", false);
|
||||
}
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_BOLT, "Threaded Rendering"),
|
||||
FSUI_VSTR("Uses a second thread for drawing graphics. Provides a significant speed improvement "
|
||||
"particularly with the software renderer, and is safe to use."),
|
||||
"GPU", "UseThread", true);
|
||||
|
||||
if (is_hardware && pgxp_enabled)
|
||||
{
|
||||
MenuHeading(FSUI_VSTR("PGXP (Precision Geometry Transform Pipeline)"));
|
||||
|
||||
@ -215,6 +215,7 @@ TRANSLATE_NOOP("FullscreenUI", "Create");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Create New...");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Crop Mode");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Crops vertex colours to 5:5:5 before modulating with the texture colour, which typically results in more visible banding.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Culling Correction");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Custom");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Dark");
|
||||
@ -761,6 +762,7 @@ TRANSLATE_NOOP("FullscreenUI", "Synchronizes presentation of the console's frame
|
||||
TRANSLATE_NOOP("FullscreenUI", "Temporarily disables all enhancements, useful when testing.");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Test Unofficial Achievements");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Texture Filtering");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Texture Modulation Cropping (\"Old/v0\" GPU)");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Texture Replacements");
|
||||
TRANSLATE_NOOP("FullscreenUI", "Textures Directory");
|
||||
TRANSLATE_NOOP("FullscreenUI", "The SDL input source supports most controllers.");
|
||||
|
||||
@ -530,6 +530,7 @@ bool GPU_HW::UpdateSettings(const GPUSettings& old_settings, Error* error)
|
||||
g_gpu_settings.gpu_scaled_interlacing != old_settings.gpu_scaled_interlacing)) ||
|
||||
(resolution_scale > 1 && g_gpu_settings.gpu_texture_filter == GPUTextureFilter::Nearest &&
|
||||
g_gpu_settings.gpu_force_round_texcoords != old_settings.gpu_force_round_texcoords) ||
|
||||
g_gpu_settings.gpu_modulation_crop != old_settings.gpu_modulation_crop ||
|
||||
g_gpu_settings.IsUsingShaderBlending() != old_settings.IsUsingShaderBlending() ||
|
||||
m_texture_filtering != g_gpu_settings.gpu_texture_filter ||
|
||||
m_sprite_texture_filtering != g_gpu_settings.gpu_sprite_texture_filter || m_clamp_uvs != clamp_uvs ||
|
||||
@ -1106,6 +1107,7 @@ bool GPU_HW::CompilePipelines(Error* error)
|
||||
const bool per_sample_shading = (msaa && g_gpu_settings.gpu_per_sample_shading && features.per_sample_shading);
|
||||
const bool force_round_texcoords =
|
||||
(upscaled && m_texture_filtering == GPUTextureFilter::Nearest && g_gpu_settings.gpu_force_round_texcoords);
|
||||
const bool modulation_crop = g_gpu_settings.gpu_modulation_crop;
|
||||
const bool true_color = g_gpu_settings.IsUsingTrueColor();
|
||||
const bool scaled_dithering = (!m_true_color && upscaled && g_gpu_settings.IsUsingScaledDithering());
|
||||
const bool scaled_interlacing = (upscaled && g_gpu_settings.gpu_scaled_interlacing);
|
||||
@ -1315,10 +1317,10 @@ bool GPU_HW::CompilePipelines(Error* error)
|
||||
const std::string fs = shadergen.GenerateBatchFragmentShader(
|
||||
static_cast<BatchRenderMode>(render_mode), static_cast<GPUTransparencyMode>(transparency_mode),
|
||||
shader_texmode, texture_filter, texture_filter_is_blended, upscaled, msaa, per_sample_shading,
|
||||
uv_limits, !sprite && force_round_texcoords, true_color, ConvertToBoolUnchecked(dithering),
|
||||
scaled_dithering, disable_color_perspective, ConvertToBoolUnchecked(interlacing), scaled_interlacing,
|
||||
ConvertToBoolUnchecked(check_mask), m_write_mask_as_depth, use_rov, needs_rov_depth, rov_depth_test,
|
||||
rov_depth_write);
|
||||
uv_limits, !sprite && force_round_texcoords, modulation_crop, true_color,
|
||||
ConvertToBoolUnchecked(dithering), scaled_dithering, disable_color_perspective,
|
||||
ConvertToBoolUnchecked(interlacing), scaled_interlacing, ConvertToBoolUnchecked(check_mask),
|
||||
m_write_mask_as_depth, use_rov, needs_rov_depth, rov_depth_test, rov_depth_write);
|
||||
|
||||
if (!(batch_fragment_shaders[depth_test][render_mode][transparency_mode][texture_mode][check_mask]
|
||||
[dithering][interlacing] = g_gpu_device->CreateShader(
|
||||
@ -2876,7 +2878,9 @@ void GPU_HW::DrawSprite(const GPUBackendDrawRectangleCommand* cmd)
|
||||
if (draw_with_software_renderer)
|
||||
{
|
||||
const GPU_SW_Rasterizer::DrawRectangleFunction DrawFunction = GPU_SW_Rasterizer::GetDrawRectangleFunction(
|
||||
cmd->texture_enable, cmd->raw_texture_enable, cmd->transparency_enable);
|
||||
GPU_SW_Rasterizer::GetModulationMode(cmd->texture_enable, cmd->raw_texture_enable,
|
||||
g_gpu_settings.gpu_modulation_crop),
|
||||
cmd->transparency_enable);
|
||||
DrawFunction(cmd);
|
||||
}
|
||||
}
|
||||
@ -2907,7 +2911,10 @@ void GPU_HW::DrawPolygon(const GPUBackendDrawPolygonCommand* cmd)
|
||||
if (m_draw_with_software_renderer)
|
||||
{
|
||||
const GPU_SW_Rasterizer::DrawTriangleFunction DrawFunction = GPU_SW_Rasterizer::GetDrawTriangleFunction(
|
||||
cmd->shading_enable, cmd->texture_enable, cmd->raw_texture_enable, cmd->transparency_enable);
|
||||
cmd->shading_enable,
|
||||
GPU_SW_Rasterizer::GetModulationMode(cmd->texture_enable, cmd->raw_texture_enable,
|
||||
g_gpu_settings.gpu_modulation_crop),
|
||||
cmd->transparency_enable);
|
||||
DrawFunction(cmd, &cmd->vertices[0], &cmd->vertices[1], &cmd->vertices[2]);
|
||||
if (cmd->num_vertices > 3)
|
||||
DrawFunction(cmd, &cmd->vertices[2], &cmd->vertices[1], &cmd->vertices[3]);
|
||||
@ -2951,7 +2958,10 @@ void GPU_HW::DrawPrecisePolygon(const GPUBackendDrawPrecisePolygonCommand* cmd)
|
||||
if (m_draw_with_software_renderer)
|
||||
{
|
||||
const GPU_SW_Rasterizer::DrawTriangleFunction DrawFunction = GPU_SW_Rasterizer::GetDrawTriangleFunction(
|
||||
cmd->shading_enable, cmd->texture_enable, cmd->raw_texture_enable, cmd->transparency_enable);
|
||||
cmd->shading_enable,
|
||||
GPU_SW_Rasterizer::GetModulationMode(cmd->texture_enable, cmd->raw_texture_enable,
|
||||
g_gpu_settings.gpu_modulation_crop),
|
||||
cmd->transparency_enable);
|
||||
GPUBackendDrawPolygonCommand::Vertex sw_vertices[4];
|
||||
for (u32 i = 0; i < cmd->num_vertices; i++)
|
||||
{
|
||||
|
||||
@ -727,7 +727,8 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
||||
}
|
||||
else if (texture_filter == GPUTextureFilter::MMPX)
|
||||
{
|
||||
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, bcoords + float2((xoffs), (yoffs)), uv_limits))\n";
|
||||
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, bcoords + float2((xoffs), (yoffs)), "
|
||||
"uv_limits))\n";
|
||||
|
||||
/*
|
||||
* This part of the shader is from MMPX.glc from https://casual-effects.com/research/McGuire2021PixelArt/index.html
|
||||
@ -834,7 +835,8 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
||||
}
|
||||
else if (texture_filter == GPUTextureFilter::MMPXEnhanced)
|
||||
{
|
||||
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, bcoords + float2((xoffs), (yoffs)), uv_limits))\n";
|
||||
ss << "#define src(xoffs, yoffs) packUnorm4x8(SampleFromVRAM(texpage, bcoords + float2((xoffs), (yoffs)), "
|
||||
"uv_limits))\n";
|
||||
|
||||
/*
|
||||
* This part of the shader is from MMPX.glc from https://casual-effects.com/research/McGuire2021PixelArt/index.html
|
||||
@ -1180,9 +1182,10 @@ void FilteredSampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords, float4 uv_limi
|
||||
std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(
|
||||
GPU_HW::BatchRenderMode render_mode, GPUTransparencyMode transparency, GPU_HW::BatchTextureMode texture_mode,
|
||||
GPUTextureFilter texture_filtering, bool is_blended_texture_filtering, bool upscaled, bool msaa,
|
||||
bool per_sample_shading, bool uv_limits, bool force_round_texcoords, bool true_color, bool dithering,
|
||||
bool scaled_dithering, bool disable_color_perspective, bool interlacing, bool scaled_interlacing, bool check_mask,
|
||||
bool write_mask_as_depth, bool use_rov, bool use_rov_depth, bool rov_depth_test, bool rov_depth_write) const
|
||||
bool per_sample_shading, bool uv_limits, bool force_round_texcoords, bool modulation_crop, bool true_color,
|
||||
bool dithering, bool scaled_dithering, bool disable_color_perspective, bool interlacing, bool scaled_interlacing,
|
||||
bool check_mask, bool write_mask_as_depth, bool use_rov, bool use_rov_depth, bool rov_depth_test,
|
||||
bool rov_depth_write) const
|
||||
{
|
||||
DebugAssert(!true_color || !dithering); // Should not be doing dithering+true color.
|
||||
|
||||
@ -1216,6 +1219,7 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(
|
||||
DefineMacro(ss, "DITHERING_SCALED", dithering && scaled_dithering);
|
||||
DefineMacro(ss, "INTERLACING", interlacing);
|
||||
DefineMacro(ss, "INTERLACING_SCALED", interlacing && scaled_interlacing);
|
||||
DefineMacro(ss, "MODULATION_CROP", modulation_crop);
|
||||
DefineMacro(ss, "TRUE_COLOR", true_color);
|
||||
DefineMacro(ss, "TEXTURE_FILTERING", texture_filtering != GPUTextureFilter::Nearest);
|
||||
DefineMacro(ss, "TEXTURE_ALPHA_BLENDING", is_blended_texture_filtering);
|
||||
@ -1498,7 +1502,11 @@ float4 SampleFromVRAM(TEXPAGE_VALUE texpage, DECLARE_UV_LIMITS(float2 coords, fl
|
||||
// If not using true color, truncate the framebuffer colors to 5-bit.
|
||||
#if !TRUE_COLOR
|
||||
icolor = uint3(texcol.rgb * float3(255.0, 255.0, 255.0)) >> 3;
|
||||
icolor = (icolor * vertcol) >> 4;
|
||||
#if MODULATION_CROP
|
||||
icolor = (icolor * (vertcol >> 3)) >> 1;
|
||||
#else
|
||||
icolor = (icolor * vertcol) >> 4;
|
||||
#endif
|
||||
#if DITHERING
|
||||
icolor = ApplyDithering(fragpos, icolor);
|
||||
#else
|
||||
@ -1506,7 +1514,11 @@ float4 SampleFromVRAM(TEXPAGE_VALUE texpage, DECLARE_UV_LIMITS(float2 coords, fl
|
||||
#endif
|
||||
#else
|
||||
icolor = uint3(texcol.rgb * float3(255.0, 255.0, 255.0));
|
||||
icolor = (icolor * vertcol) >> 7;
|
||||
#if MODULATION_CROP
|
||||
icolor = (icolor * (vertcol >> 3)) >> 4;
|
||||
#else
|
||||
icolor = (icolor * vertcol) >> 7;
|
||||
#endif
|
||||
icolor = min(icolor, uint3(255u, 255u, 255u));
|
||||
#endif
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ public:
|
||||
GPU_HW::BatchTextureMode texture_mode, GPUTextureFilter texture_filtering,
|
||||
bool is_blended_texture_filtering, bool upscaled, bool msaa,
|
||||
bool per_sample_shading, bool uv_limits, bool force_round_texcoords,
|
||||
bool true_color, bool dithering, bool scaled_dithering,
|
||||
bool modulation_crop, bool true_color, bool dithering, bool scaled_dithering,
|
||||
bool disable_color_perspective, bool interlacing, bool scaled_interlacing,
|
||||
bool check_mask, bool write_mask_as_depth, bool use_rov, bool use_rov_depth,
|
||||
bool rov_depth_test, bool rov_depth_write) const;
|
||||
|
||||
@ -107,7 +107,10 @@ void GPU_SW::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32
|
||||
void GPU_SW::DrawPolygon(const GPUBackendDrawPolygonCommand* cmd)
|
||||
{
|
||||
const GPU_SW_Rasterizer::DrawTriangleFunction DrawFunction = GPU_SW_Rasterizer::GetDrawTriangleFunction(
|
||||
cmd->shading_enable, cmd->texture_enable, cmd->raw_texture_enable, cmd->transparency_enable);
|
||||
cmd->shading_enable,
|
||||
GPU_SW_Rasterizer::GetModulationMode(cmd->texture_enable, cmd->raw_texture_enable,
|
||||
g_gpu_settings.gpu_modulation_crop),
|
||||
cmd->transparency_enable);
|
||||
|
||||
DrawFunction(cmd, &cmd->vertices[0], &cmd->vertices[1], &cmd->vertices[2]);
|
||||
if (cmd->num_vertices > 3)
|
||||
@ -117,7 +120,10 @@ void GPU_SW::DrawPolygon(const GPUBackendDrawPolygonCommand* cmd)
|
||||
void GPU_SW::DrawPrecisePolygon(const GPUBackendDrawPrecisePolygonCommand* cmd)
|
||||
{
|
||||
const GPU_SW_Rasterizer::DrawTriangleFunction DrawFunction = GPU_SW_Rasterizer::GetDrawTriangleFunction(
|
||||
cmd->shading_enable, cmd->texture_enable, cmd->raw_texture_enable, cmd->transparency_enable);
|
||||
cmd->shading_enable,
|
||||
GPU_SW_Rasterizer::GetModulationMode(cmd->texture_enable, cmd->raw_texture_enable,
|
||||
g_gpu_settings.gpu_modulation_crop),
|
||||
cmd->transparency_enable);
|
||||
|
||||
// Need to cut out the irrelevant bits.
|
||||
// TODO: In _theory_ we could use the fixed-point parts here.
|
||||
@ -148,8 +154,10 @@ void GPU_SW::DrawSprite(const GPUBackendDrawRectangleCommand* cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
const GPU_SW_Rasterizer::DrawRectangleFunction DrawFunction =
|
||||
GPU_SW_Rasterizer::GetDrawRectangleFunction(cmd->texture_enable, cmd->raw_texture_enable, cmd->transparency_enable);
|
||||
const GPU_SW_Rasterizer::DrawRectangleFunction DrawFunction = GPU_SW_Rasterizer::GetDrawRectangleFunction(
|
||||
GPU_SW_Rasterizer::GetModulationMode(cmd->texture_enable, cmd->raw_texture_enable,
|
||||
g_gpu_settings.gpu_modulation_crop),
|
||||
cmd->transparency_enable);
|
||||
|
||||
DrawFunction(cmd);
|
||||
}
|
||||
|
||||
@ -14,6 +14,14 @@
|
||||
|
||||
namespace GPU_SW_Rasterizer {
|
||||
|
||||
enum class TextureModulationMode : u8
|
||||
{
|
||||
Disabled, // No texturing
|
||||
NoModulation, // "Raw Texture"
|
||||
Modulate8Bit, // Modulate with 8-bit color
|
||||
Modulate5Bit, // Modulate with 5-bit color
|
||||
};
|
||||
|
||||
// this is actually (31 * 255) >> 4) == 494, but to simplify addressing we use the next power of two (512)
|
||||
inline constexpr u32 DITHER_LUT_SIZE = 512;
|
||||
using DitherLUT = std::array<std::array<std::array<u8, DITHER_LUT_SIZE>, DITHER_MATRIX_SIZE>, DITHER_MATRIX_SIZE>;
|
||||
@ -25,12 +33,12 @@ extern GPUDrawingArea g_drawing_area;
|
||||
extern void UpdateCLUT(GPUTexturePaletteReg reg, bool clut_is_8bit);
|
||||
|
||||
using DrawRectangleFunction = void (*)(const GPUBackendDrawRectangleCommand* cmd);
|
||||
typedef const DrawRectangleFunction DrawRectangleFunctionTable[2][2][2];
|
||||
typedef const DrawRectangleFunction DrawRectangleFunctionTable[4][2];
|
||||
|
||||
using DrawTriangleFunction = void (*)(const GPUBackendDrawCommand* cmd, const GPUBackendDrawPolygonCommand::Vertex* v0,
|
||||
const GPUBackendDrawPolygonCommand::Vertex* v1,
|
||||
const GPUBackendDrawPolygonCommand::Vertex* v2);
|
||||
typedef const DrawTriangleFunction DrawTriangleFunctionTable[2][2][2][2];
|
||||
typedef const DrawTriangleFunction DrawTriangleFunctionTable[2][4][2];
|
||||
|
||||
using DrawLineFunction = void (*)(const GPUBackendDrawCommand* cmd, const GPUBackendDrawLineCommand::Vertex* p0,
|
||||
const GPUBackendDrawLineCommand::Vertex* p1);
|
||||
@ -52,22 +60,30 @@ extern CopyVRAMFunction CopyVRAM;
|
||||
|
||||
extern void SelectImplementation();
|
||||
|
||||
ALWAYS_INLINE TextureModulationMode GetModulationMode(bool texture_enable, bool raw_texture_enable,
|
||||
bool modulation_crop)
|
||||
{
|
||||
return (texture_enable ? (raw_texture_enable ? TextureModulationMode::NoModulation :
|
||||
(modulation_crop ? TextureModulationMode::Modulate5Bit :
|
||||
TextureModulationMode::Modulate8Bit)) :
|
||||
TextureModulationMode::Disabled);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE DrawLineFunction GetDrawLineFunction(bool shading_enable, bool transparency_enable)
|
||||
{
|
||||
return (*DrawLineFunctions)[u8(shading_enable)][u8(transparency_enable)];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE DrawRectangleFunction GetDrawRectangleFunction(bool texture_enable, bool raw_texture_enable,
|
||||
ALWAYS_INLINE DrawRectangleFunction GetDrawRectangleFunction(TextureModulationMode modulation_mode,
|
||||
bool transparency_enable)
|
||||
{
|
||||
return (*DrawRectangleFunctions)[u8(texture_enable)][u8(raw_texture_enable)][u8(transparency_enable)];
|
||||
return (*DrawRectangleFunctions)[u8(modulation_mode)][u8(transparency_enable)];
|
||||
}
|
||||
|
||||
ALWAYS_INLINE DrawTriangleFunction GetDrawTriangleFunction(bool shading_enable, bool texture_enable,
|
||||
bool raw_texture_enable, bool transparency_enable)
|
||||
ALWAYS_INLINE DrawTriangleFunction GetDrawTriangleFunction(bool shading_enable, TextureModulationMode modulation_mode,
|
||||
bool transparency_enable)
|
||||
{
|
||||
return (
|
||||
*DrawTriangleFunctions)[u8(shading_enable)][u8(texture_enable)][u8(raw_texture_enable)][u8(transparency_enable)];
|
||||
return (*DrawTriangleFunctions)[u8(shading_enable)][u8(modulation_mode)][u8(transparency_enable)];
|
||||
}
|
||||
|
||||
#define DECLARE_ALTERNATIVE_RASTERIZER(isa) \
|
||||
|
||||
@ -77,11 +77,13 @@ static u32 s_bad_counter = 0;
|
||||
return std::make_tuple(static_cast<u8>(rgb24), static_cast<u8>(rgb24 >> 8), static_cast<u8>(rgb24 >> 16));
|
||||
}
|
||||
|
||||
template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
[[maybe_unused]] ALWAYS_INLINE_RELEASE static void ShadePixel(const GPUBackendDrawCommand* cmd, u32 x, u32 y,
|
||||
u8 color_r, u8 color_g, u8 color_b, u8 texcoord_x,
|
||||
u8 texcoord_y)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
|
||||
u16 color;
|
||||
if constexpr (texture_enable)
|
||||
{
|
||||
@ -123,7 +125,7 @@ template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
if (texture_color == 0)
|
||||
return;
|
||||
|
||||
if constexpr (raw_texture_enable)
|
||||
if constexpr (modulation_mode == TextureModulationMode::NoModulation)
|
||||
{
|
||||
color = texture_color;
|
||||
}
|
||||
@ -133,12 +135,26 @@ template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
const u32 dither_y = (dithering_enable) ? (y & 3u) : 2u;
|
||||
const u32 dither_x = (dithering_enable) ? (x & 3u) : 3u;
|
||||
|
||||
color =
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16(texture_color & 0x1Fu) * u16(color_r)) >> 4]) << 0) |
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16((texture_color >> 5) & 0x1Fu) * u16(color_g)) >> 4]) << 5) |
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16((texture_color >> 10) & 0x1Fu) * u16(color_b)) >> 4])
|
||||
<< 10) |
|
||||
(texture_color & 0x8000u);
|
||||
if (modulation_mode == TextureModulationMode::Modulate8Bit)
|
||||
{
|
||||
color =
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16(texture_color & 0x1Fu) * u16(color_r)) >> 4]) << 0) |
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16((texture_color >> 5) & 0x1Fu) * u16(color_g)) >> 4])
|
||||
<< 5) |
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16((texture_color >> 10) & 0x1Fu) * u16(color_b)) >> 4])
|
||||
<< 10) |
|
||||
(texture_color & 0x8000u);
|
||||
}
|
||||
else
|
||||
{
|
||||
color =
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16(texture_color & 0x1Fu) * u16(color_r >> 3)) >> 1]) << 0) |
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16((texture_color >> 5) & 0x1Fu) * u16(color_g >> 3)) >> 1])
|
||||
<< 5) |
|
||||
(ZeroExtend16(g_dither_lut[dither_y][dither_x][(u16((texture_color >> 10) & 0x1Fu) * u16(color_b >> 3)) >> 1])
|
||||
<< 10) |
|
||||
(texture_color & 0x8000u);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -225,7 +241,7 @@ template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
|
||||
#ifndef USE_VECTOR
|
||||
|
||||
template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
static void DrawRectangle(const GPUBackendDrawRectangleCommand* cmd)
|
||||
{
|
||||
const s32 origin_x = cmd->x;
|
||||
@ -254,8 +270,8 @@ static void DrawRectangle(const GPUBackendDrawRectangleCommand* cmd)
|
||||
|
||||
const u8 texcoord_x = Truncate8(ZeroExtend32(origin_texcoord_x) + offset_x);
|
||||
|
||||
ShadePixel<texture_enable, raw_texture_enable, transparency_enable>(cmd, static_cast<u32>(x), draw_y, r, g, b,
|
||||
texcoord_x, texcoord_y);
|
||||
ShadePixel<modulation_mode, transparency_enable>(cmd, static_cast<u32>(x), draw_y, r, g, b, texcoord_x,
|
||||
texcoord_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -505,13 +521,15 @@ struct PixelVectors
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
ALWAYS_INLINE_RELEASE static void ShadePixel(const PixelVectors<texture_enable>& RESTRICT pv,
|
||||
GPUTextureMode texture_mode, GPUTransparencyMode transparency_mode,
|
||||
bool mask_bit_test, u32 start_x, u32 y, GSVectorNi vertex_color_rg,
|
||||
GSVectorNi vertex_color_ba, GSVectorNi texcoord_x, GSVectorNi texcoord_y,
|
||||
GSVectorNi preserve_mask, GSVectorNi dither)
|
||||
template<TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
ALWAYS_INLINE_RELEASE static void
|
||||
ShadePixel(const PixelVectors<modulation_mode != TextureModulationMode::Disabled>& RESTRICT pv,
|
||||
GPUTextureMode texture_mode, GPUTransparencyMode transparency_mode, bool mask_bit_test, u32 start_x, u32 y,
|
||||
GSVectorNi vertex_color_rg, GSVectorNi vertex_color_ba, GSVectorNi texcoord_x, GSVectorNi texcoord_y,
|
||||
GSVectorNi preserve_mask, GSVectorNi dither)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
|
||||
static constexpr GSVectorNi coord_mask_x = GSVectorNi::cxpr(VRAM_WIDTH_MASK);
|
||||
static constexpr GSVectorNi coord_mask_y = GSVectorNi::cxpr(VRAM_HEIGHT_MASK);
|
||||
|
||||
@ -568,7 +586,7 @@ ALWAYS_INLINE_RELEASE static void ShadePixel(const PixelVectors<texture_enable>&
|
||||
|
||||
preserve_mask = preserve_mask | texture_transparent_mask;
|
||||
|
||||
if constexpr (raw_texture_enable)
|
||||
if constexpr (modulation_mode == TextureModulationMode::NoModulation)
|
||||
{
|
||||
color = texture_color;
|
||||
}
|
||||
@ -577,13 +595,27 @@ ALWAYS_INLINE_RELEASE static void ShadePixel(const PixelVectors<texture_enable>&
|
||||
GSVectorNi trg, tba;
|
||||
RGB5A1ToRG_BA(texture_color, trg, tba);
|
||||
|
||||
// now we have both the texture and vertex color in RG/GA pairs, for 4 pixels, which we can multiply
|
||||
GSVectorNi rg = trg.mul16l(vertex_color_rg);
|
||||
GSVectorNi ba = tba.mul16l(vertex_color_ba);
|
||||
GSVectorNi rg, ba;
|
||||
if constexpr (modulation_mode == TextureModulationMode::Modulate8Bit)
|
||||
{
|
||||
// now we have both the texture and vertex color in RG/GA pairs, for 4 pixels, which we can multiply
|
||||
rg = trg.mul16l(vertex_color_rg);
|
||||
ba = tba.mul16l(vertex_color_ba);
|
||||
|
||||
// Convert to 5bit.
|
||||
rg = rg.sra16<4>().add16(dither).max_s16(GSVectorNi::zero()).sra16<3>();
|
||||
ba = ba.sra16<4>().add16(dither).max_s16(GSVectorNi::zero()).sra16<3>();
|
||||
// Convert to 5bit.
|
||||
rg = rg.sra16<4>().add16(dither).max_s16(GSVectorNi::zero()).sra16<3>();
|
||||
ba = ba.sra16<4>().add16(dither).max_s16(GSVectorNi::zero()).sra16<3>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// now we have both the texture and vertex color in RG/GA pairs, for 4 pixels, which we can multiply
|
||||
rg = trg.mul16l(vertex_color_rg.sra16<3>());
|
||||
ba = tba.mul16l(vertex_color_ba.sra16<3>());
|
||||
|
||||
// Convert to 5bit.
|
||||
rg = rg.sra16<1>().add16(dither).max_s16(GSVectorNi::zero()).sra16<3>();
|
||||
ba = ba.sra16<1>().add16(dither).max_s16(GSVectorNi::zero()).sra16<3>();
|
||||
}
|
||||
|
||||
// Bit15 gets passed through as-is.
|
||||
ba = ba.blend16<0xaa>(tba);
|
||||
@ -703,9 +735,11 @@ ALWAYS_INLINE_RELEASE static void ShadePixel(const PixelVectors<texture_enable>&
|
||||
StoreVector(start_x, y, color);
|
||||
}
|
||||
|
||||
template<bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
static void DrawRectangle(const GPUBackendDrawRectangleCommand* RESTRICT cmd)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
|
||||
const s32 origin_x = cmd->x;
|
||||
const s32 origin_y = cmd->y;
|
||||
|
||||
@ -752,9 +786,9 @@ static void DrawRectangle(const GPUBackendDrawRectangleCommand* RESTRICT cmd)
|
||||
preserve_mask = preserve_mask | xvec.gt32(pv.clip_right);
|
||||
if (!preserve_mask.alltrue())
|
||||
{
|
||||
ShadePixel<texture_enable, raw_texture_enable, transparency_enable>(
|
||||
pv, cmd->draw_mode.texture_mode, transparency_mode, mask_bit_test, x, draw_y, rg, ba, row_texcoord_x,
|
||||
texcoord_y, preserve_mask, GSVectorNi::zero());
|
||||
ShadePixel<modulation_mode, transparency_enable>(pv, cmd->draw_mode.texture_mode, transparency_mode,
|
||||
mask_bit_test, x, draw_y, rg, ba, row_texcoord_x, texcoord_y,
|
||||
preserve_mask, GSVectorNi::zero());
|
||||
}
|
||||
|
||||
xvec = xvec.add32(PIXELS_PER_VEC_VEC);
|
||||
@ -770,7 +804,7 @@ static void DrawRectangle(const GPUBackendDrawRectangleCommand* RESTRICT cmd)
|
||||
}
|
||||
|
||||
#ifdef CHECK_VECTOR
|
||||
CHECK_VRAM(GPU_SW_Rasterizer::DrawRectangleFunctions[texture_enable][raw_texture_enable][transparency_enable](cmd));
|
||||
CHECK_VRAM(GPU_SW_Rasterizer::DrawRectangleFunctions[u8(modulation_mode)][transparency_enable](cmd));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -841,8 +875,8 @@ static void DrawLine(const GPUBackendDrawCommand* RESTRICT cmd, const GPUBackend
|
||||
const u8 g = shading_enable ? unfp_rgb(curg) : p0->g;
|
||||
const u8 b = shading_enable ? unfp_rgb(curb) : p0->b;
|
||||
|
||||
ShadePixel<false, false, transparency_enable>(cmd, static_cast<u32>(x), static_cast<u32>(y) & VRAM_HEIGHT_MASK, r,
|
||||
g, b, 0, 0);
|
||||
ShadePixel<TextureModulationMode::Disabled, transparency_enable>(
|
||||
cmd, static_cast<u32>(x), static_cast<u32>(y) & VRAM_HEIGHT_MASK, r, g, b, 0, 0);
|
||||
}
|
||||
|
||||
curx += dxdk;
|
||||
@ -983,10 +1017,12 @@ struct TrianglePart
|
||||
|
||||
#ifndef USE_VECTOR
|
||||
|
||||
template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<bool shading_enable, TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
static void DrawSpan(const GPUBackendDrawCommand* RESTRICT cmd, s32 y, s32 x_start, s32 x_bound, UVStepper uv,
|
||||
const UVSteps& RESTRICT uvstep, RGBStepper rgb, const RGBSteps& RESTRICT rgbstep)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
|
||||
s32 width = x_bound - x_start;
|
||||
s32 current_x = TruncateGPUVertexPosition(x_start);
|
||||
|
||||
@ -1012,8 +1048,8 @@ static void DrawSpan(const GPUBackendDrawCommand* RESTRICT cmd, s32 y, s32 x_sta
|
||||
|
||||
do
|
||||
{
|
||||
ShadePixel<texture_enable, raw_texture_enable, transparency_enable>(
|
||||
cmd, static_cast<u32>(current_x), static_cast<u32>(y), rgb.GetR(), rgb.GetG(), rgb.GetB(), uv.GetU(), uv.GetV());
|
||||
ShadePixel<modulation_mode, transparency_enable>(cmd, static_cast<u32>(current_x), static_cast<u32>(y), rgb.GetR(),
|
||||
rgb.GetG(), rgb.GetB(), uv.GetU(), uv.GetV());
|
||||
|
||||
current_x++;
|
||||
if constexpr (texture_enable)
|
||||
@ -1023,12 +1059,13 @@ static void DrawSpan(const GPUBackendDrawCommand* RESTRICT cmd, s32 y, s32 x_sta
|
||||
} while (--width > 0);
|
||||
}
|
||||
|
||||
template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<bool shading_enable, TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand* RESTRICT cmd,
|
||||
const TrianglePart& RESTRICT tp, const UVStepper& RESTRICT uv,
|
||||
const UVSteps& RESTRICT uvstep, const RGBStepper& RESTRICT rgb,
|
||||
const RGBSteps& RESTRICT rgbstep)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
static constexpr auto unfp_xy = [](s64 xfp) -> s32 { return static_cast<s32>(static_cast<u64>(xfp) >> 32); };
|
||||
|
||||
const u64 left_x_step = tp.step_x[0];
|
||||
@ -1074,8 +1111,8 @@ ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand*
|
||||
continue;
|
||||
}
|
||||
|
||||
DrawSpan<shading_enable, texture_enable, raw_texture_enable, transparency_enable>(
|
||||
cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x), unfp_xy(right_x), luv, uvstep, lrgb, rgbstep);
|
||||
DrawSpan<shading_enable, modulation_mode, transparency_enable>(cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x),
|
||||
unfp_xy(right_x), luv, uvstep, lrgb, rgbstep);
|
||||
} while (current_y > end_y);
|
||||
}
|
||||
else
|
||||
@ -1103,8 +1140,8 @@ ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand*
|
||||
(!cmd->interlaced_rendering ||
|
||||
cmd->active_line_lsb != ConvertToBoolUnchecked(static_cast<u32>(current_y) & 1u)))
|
||||
{
|
||||
DrawSpan<shading_enable, texture_enable, raw_texture_enable, transparency_enable>(
|
||||
cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x), unfp_xy(right_x), luv, uvstep, lrgb, rgbstep);
|
||||
DrawSpan<shading_enable, modulation_mode, transparency_enable>(cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x),
|
||||
unfp_xy(right_x), luv, uvstep, lrgb, rgbstep);
|
||||
}
|
||||
|
||||
current_y++;
|
||||
@ -1163,12 +1200,14 @@ struct TriangleVectors : PixelVectors<texture_enable>
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
ALWAYS_INLINE_RELEASE static void DrawSpan(const GPUBackendDrawCommand* RESTRICT cmd, s32 y, s32 x_start, s32 x_bound,
|
||||
UVStepper uv, const UVSteps& RESTRICT uvstep, RGBStepper rgb,
|
||||
const RGBSteps& RESTRICT rgbstep,
|
||||
const TriangleVectors<shading_enable, texture_enable>& RESTRICT tv)
|
||||
template<bool shading_enable, TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
ALWAYS_INLINE_RELEASE static void
|
||||
DrawSpan(const GPUBackendDrawCommand* RESTRICT cmd, s32 y, s32 x_start, s32 x_bound, UVStepper uv,
|
||||
const UVSteps& RESTRICT uvstep, RGBStepper rgb, const RGBSteps& RESTRICT rgbstep,
|
||||
const TriangleVectors<shading_enable, modulation_mode != TextureModulationMode::Disabled>& RESTRICT tv)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
|
||||
s32 width = x_bound - x_start;
|
||||
s32 current_x = TruncateGPUVertexPosition(x_start);
|
||||
|
||||
@ -1247,9 +1286,9 @@ ALWAYS_INLINE_RELEASE static void DrawSpan(const GPUBackendDrawCommand* RESTRICT
|
||||
preserve_mask = preserve_mask | xvec.gt32(tv.clip_right);
|
||||
if (!preserve_mask.alltrue())
|
||||
{
|
||||
ShadePixel<texture_enable, raw_texture_enable, transparency_enable>(
|
||||
tv, cmd->draw_mode.texture_mode, transparency_mode, mask_bit_test, static_cast<u32>(current_x),
|
||||
static_cast<u32>(y), rg, b, u, v, preserve_mask, dither);
|
||||
ShadePixel<modulation_mode, transparency_enable>(tv, cmd->draw_mode.texture_mode, transparency_mode,
|
||||
mask_bit_test, static_cast<u32>(current_x), static_cast<u32>(y),
|
||||
rg, b, u, v, preserve_mask, dither);
|
||||
}
|
||||
|
||||
current_x += PIXELS_PER_VEC;
|
||||
@ -1272,12 +1311,13 @@ ALWAYS_INLINE_RELEASE static void DrawSpan(const GPUBackendDrawCommand* RESTRICT
|
||||
}
|
||||
}
|
||||
|
||||
template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<bool shading_enable, TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand* RESTRICT cmd,
|
||||
const TrianglePart& RESTRICT tp, const UVStepper& RESTRICT uv,
|
||||
const UVSteps& RESTRICT uvstep, const RGBStepper& RESTRICT rgb,
|
||||
const RGBSteps& RESTRICT rgbstep)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
static constexpr auto unfp_xy = [](s64 xfp) -> s32 { return static_cast<s32>(static_cast<u64>(xfp) >> 32); };
|
||||
|
||||
const u64 left_x_step = tp.step_x[0];
|
||||
@ -1325,8 +1365,8 @@ ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand*
|
||||
continue;
|
||||
}
|
||||
|
||||
DrawSpan<shading_enable, texture_enable, raw_texture_enable, transparency_enable>(
|
||||
cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x), unfp_xy(right_x), luv, uvstep, lrgb, rgbstep, tv);
|
||||
DrawSpan<shading_enable, modulation_mode, transparency_enable>(cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x),
|
||||
unfp_xy(right_x), luv, uvstep, lrgb, rgbstep, tv);
|
||||
} while (current_y > end_y);
|
||||
}
|
||||
else
|
||||
@ -1356,7 +1396,7 @@ ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand*
|
||||
(!cmd->interlaced_rendering ||
|
||||
cmd->active_line_lsb != ConvertToBoolUnchecked(static_cast<u32>(current_y) & 1u)))
|
||||
{
|
||||
DrawSpan<shading_enable, texture_enable, raw_texture_enable, transparency_enable>(
|
||||
DrawSpan<shading_enable, modulation_mode, transparency_enable>(
|
||||
cmd, y & VRAM_HEIGHT_MASK, unfp_xy(left_x), unfp_xy(right_x), luv, uvstep, lrgb, rgbstep, tv);
|
||||
}
|
||||
|
||||
@ -1374,12 +1414,14 @@ ALWAYS_INLINE_RELEASE static void DrawTrianglePart(const GPUBackendDrawCommand*
|
||||
|
||||
#endif // USE_VECTOR
|
||||
|
||||
template<bool shading_enable, bool texture_enable, bool raw_texture_enable, bool transparency_enable>
|
||||
template<bool shading_enable, TextureModulationMode modulation_mode, bool transparency_enable>
|
||||
static void DrawTriangle(const GPUBackendDrawCommand* RESTRICT cmd,
|
||||
const GPUBackendDrawPolygonCommand::Vertex* RESTRICT v0,
|
||||
const GPUBackendDrawPolygonCommand::Vertex* RESTRICT v1,
|
||||
const GPUBackendDrawPolygonCommand::Vertex* RESTRICT v2)
|
||||
{
|
||||
static constexpr bool texture_enable = (modulation_mode != TextureModulationMode::Disabled);
|
||||
|
||||
#ifdef CHECK_VECTOR
|
||||
const GPUBackendDrawPolygonCommand::Vertex* RESTRICT orig_v0 = v0;
|
||||
const GPUBackendDrawPolygonCommand::Vertex* RESTRICT orig_v1 = v1;
|
||||
@ -1514,35 +1556,85 @@ static void DrawTriangle(const GPUBackendDrawCommand* RESTRICT cmd,
|
||||
|
||||
for (u32 i = 0; i < 2; i++)
|
||||
{
|
||||
DrawTrianglePart<shading_enable, texture_enable, raw_texture_enable, transparency_enable>(cmd, triparts[i], uv,
|
||||
uvstep, rgb, rgbstep);
|
||||
DrawTrianglePart<shading_enable, modulation_mode, transparency_enable>(cmd, triparts[i], uv, uvstep, rgb, rgbstep);
|
||||
}
|
||||
|
||||
#ifdef CHECK_VECTOR
|
||||
CHECK_VRAM(
|
||||
GPU_SW_Rasterizer::DrawTriangleFunctions[shading_enable][texture_enable][raw_texture_enable][transparency_enable](
|
||||
cmd, orig_v0, orig_v1, orig_v2));
|
||||
CHECK_VRAM(GPU_SW_Rasterizer::DrawTriangleFunctions[shading_enable][u8(modulation_mode)][transparency_enable](
|
||||
cmd, orig_v0, orig_v1, orig_v2));
|
||||
#endif
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
constinit const DrawRectangleFunctionTable DrawRectangleFunctions = {
|
||||
{{&DrawRectangle<false, false, false>, &DrawRectangle<false, false, true>},
|
||||
{&DrawRectangle<false, false, false>, &DrawRectangle<false, false, true>}},
|
||||
{{&DrawRectangle<true, false, false>, &DrawRectangle<true, false, true>},
|
||||
{&DrawRectangle<true, true, false>, &DrawRectangle<true, true, true>}}};
|
||||
{
|
||||
&DrawRectangle<TextureModulationMode::Disabled, false>,
|
||||
&DrawRectangle<TextureModulationMode::Disabled, true>,
|
||||
},
|
||||
{
|
||||
&DrawRectangle<TextureModulationMode::NoModulation, false>,
|
||||
&DrawRectangle<TextureModulationMode::NoModulation, true>,
|
||||
},
|
||||
{
|
||||
&DrawRectangle<TextureModulationMode::Modulate8Bit, false>,
|
||||
&DrawRectangle<TextureModulationMode::Modulate8Bit, true>,
|
||||
},
|
||||
{
|
||||
&DrawRectangle<TextureModulationMode::Modulate5Bit, false>,
|
||||
&DrawRectangle<TextureModulationMode::Modulate5Bit, true>,
|
||||
},
|
||||
};
|
||||
|
||||
constinit const DrawLineFunctionTable DrawLineFunctions = {{&DrawLine<false, false>, &DrawLine<false, true>},
|
||||
{&DrawLine<true, false>, &DrawLine<true, true>}};
|
||||
constinit const DrawLineFunctionTable DrawLineFunctions = {
|
||||
{
|
||||
&DrawLine<false, false>,
|
||||
&DrawLine<false, true>
|
||||
},
|
||||
{
|
||||
&DrawLine<true, false>,
|
||||
&DrawLine<true, true>
|
||||
}
|
||||
};
|
||||
|
||||
constinit const DrawTriangleFunctionTable DrawTriangleFunctions = {
|
||||
{{{&DrawTriangle<false, false, false, false>, &DrawTriangle<false, false, false, true>},
|
||||
{&DrawTriangle<false, false, false, false>, &DrawTriangle<false, false, false, true>}},
|
||||
{{&DrawTriangle<false, true, false, false>, &DrawTriangle<false, true, false, true>},
|
||||
{&DrawTriangle<false, true, true, false>, &DrawTriangle<false, true, true, true>}}},
|
||||
{{{&DrawTriangle<true, false, false, false>, &DrawTriangle<true, false, false, true>},
|
||||
{&DrawTriangle<true, false, false, false>, &DrawTriangle<true, false, false, true>}},
|
||||
{{&DrawTriangle<true, true, false, false>, &DrawTriangle<true, true, false, true>},
|
||||
{&DrawTriangle<true, true, true, false>, &DrawTriangle<true, true, true, true>}}}};
|
||||
{
|
||||
{
|
||||
&DrawTriangle<false, TextureModulationMode::Disabled, false>,
|
||||
&DrawTriangle<false, TextureModulationMode::Disabled, true>
|
||||
},
|
||||
{
|
||||
&DrawTriangle<false, TextureModulationMode::NoModulation, false>,
|
||||
&DrawTriangle<false, TextureModulationMode::NoModulation, true>
|
||||
},
|
||||
{
|
||||
&DrawTriangle<false, TextureModulationMode::Modulate8Bit, false>,
|
||||
&DrawTriangle<false, TextureModulationMode::Modulate8Bit, true>
|
||||
},
|
||||
{
|
||||
&DrawTriangle<false, TextureModulationMode::Modulate5Bit, false>,
|
||||
&DrawTriangle<false, TextureModulationMode::Modulate5Bit, true>
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
&DrawTriangle<true, TextureModulationMode::Disabled, false>,
|
||||
&DrawTriangle<true, TextureModulationMode::Disabled, true>
|
||||
},
|
||||
{
|
||||
&DrawTriangle<true, TextureModulationMode::NoModulation, false>,
|
||||
&DrawTriangle<true, TextureModulationMode::NoModulation, true>
|
||||
},
|
||||
{
|
||||
&DrawTriangle<true, TextureModulationMode::Modulate8Bit, false>,
|
||||
&DrawTriangle<true, TextureModulationMode::Modulate8Bit, true>
|
||||
},
|
||||
{
|
||||
&DrawTriangle<true, TextureModulationMode::Modulate5Bit, false>,
|
||||
&DrawTriangle<true, TextureModulationMode::Modulate5Bit, true>
|
||||
}
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static void FillVRAMImpl(u32 x, u32 y, u32 width, u32 height, u32 color, bool interlaced, u8 active_line_lsb)
|
||||
{
|
||||
|
||||
@ -301,6 +301,7 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
|
||||
si.GetStringValue("GPU", "ForceVideoTiming", GetForceVideoTimingName(DEFAULT_FORCE_VIDEO_TIMING_MODE)).c_str())
|
||||
.value_or(DEFAULT_FORCE_VIDEO_TIMING_MODE);
|
||||
gpu_widescreen_rendering = gpu_widescreen_hack = si.GetBoolValue("GPU", "WidescreenHack", false);
|
||||
gpu_modulation_crop = si.GetBoolValue("GPU", "EnableModulationCrop", false);
|
||||
gpu_texture_cache = si.GetBoolValue("GPU", "EnableTextureCache", false);
|
||||
display_24bit_chroma_smoothing = si.GetBoolValue("GPU", "ChromaSmoothing24Bit", false);
|
||||
gpu_pgxp_enable = si.GetBoolValue("GPU", "PGXPEnable", false);
|
||||
@ -680,6 +681,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
||||
si.SetStringValue("GPU", "WireframeMode", GetGPUWireframeModeName(gpu_wireframe_mode));
|
||||
si.SetStringValue("GPU", "ForceVideoTiming", GetForceVideoTimingName(gpu_force_video_timing));
|
||||
si.SetBoolValue("GPU", "WidescreenHack", gpu_widescreen_rendering);
|
||||
si.SetBoolValue("GPU", "EnableModulationCrop", gpu_modulation_crop);
|
||||
si.SetBoolValue("GPU", "EnableTextureCache", gpu_texture_cache);
|
||||
si.SetBoolValue("GPU", "ChromaSmoothing24Bit", display_24bit_chroma_smoothing);
|
||||
si.SetBoolValue("GPU", "PGXPEnable", gpu_pgxp_enable);
|
||||
@ -1102,6 +1104,7 @@ void Settings::ApplySettingRestrictions()
|
||||
gpu_force_video_timing = ForceVideoTimingMode::Disabled;
|
||||
gpu_widescreen_rendering = false;
|
||||
gpu_widescreen_hack = false;
|
||||
gpu_modulation_crop = false;
|
||||
gpu_texture_cache = false;
|
||||
gpu_pgxp_enable = false;
|
||||
display_deinterlacing_mode = DisplayDeinterlacingMode::Adaptive;
|
||||
|
||||
@ -80,6 +80,7 @@ struct GPUSettings
|
||||
bool gpu_force_round_texcoords : 1 = false;
|
||||
bool gpu_widescreen_rendering : 1 = false;
|
||||
bool gpu_widescreen_hack : 1 = false;
|
||||
bool gpu_modulation_crop : 1 = false;
|
||||
bool gpu_texture_cache : 1 = false;
|
||||
bool gpu_show_vram : 1 = false;
|
||||
bool gpu_dump_cpu_to_vram_copies : 1 = false;
|
||||
|
||||
@ -5,4 +5,4 @@
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
inline constexpr u32 SHADER_CACHE_VERSION = 36;
|
||||
inline constexpr u32 SHADER_CACHE_VERSION = 37;
|
||||
|
||||
@ -4600,6 +4600,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
||||
g_settings.gpu_downsample_mode != old_settings.gpu_downsample_mode ||
|
||||
g_settings.gpu_downsample_scale != old_settings.gpu_downsample_scale ||
|
||||
g_settings.gpu_wireframe_mode != old_settings.gpu_wireframe_mode ||
|
||||
g_settings.gpu_modulation_crop != old_settings.gpu_modulation_crop ||
|
||||
g_settings.gpu_texture_cache != old_settings.gpu_texture_cache ||
|
||||
g_settings.display_deinterlacing_mode != old_settings.display_deinterlacing_mode ||
|
||||
g_settings.display_24bit_chroma_smoothing != old_settings.display_24bit_chroma_smoothing ||
|
||||
@ -4959,6 +4960,8 @@ void System::WarnAboutUnsafeSettings()
|
||||
append(TRANSLATE_SV("System", "Widescreen rendering disabled."));
|
||||
if (g_settings.gpu_pgxp_enable)
|
||||
append(TRANSLATE_SV("System", "PGXP disabled."));
|
||||
if (g_settings.gpu_modulation_crop)
|
||||
append(TRANSLATE_SV("System", "Texture modulation cropping disabled."));
|
||||
if (g_settings.gpu_texture_cache)
|
||||
append(TRANSLATE_SV("System", "GPU texture cache disabled."));
|
||||
if (g_settings.display_24bit_chroma_smoothing)
|
||||
|
||||
@ -171,6 +171,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuThread, "GPU", "UseThread", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.maxQueuedFrames, "GPU", "MaxQueuedFrames",
|
||||
Settings::DEFAULT_GPU_MAX_QUEUED_FRAMES);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.modulationCrop, "GPU", "EnableModulationCrop", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledInterlacing, "GPU", "ScaledInterlacing", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useSoftwareRendererForReadbacks, "GPU",
|
||||
"UseSoftwareRendererForReadbacks", false);
|
||||
@ -527,6 +528,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.gpuThread, tr("Threaded Rendering"), tr("Checked"),
|
||||
tr("Uses a second thread for drawing graphics. Provides a significant speed improvement "
|
||||
"particularly with the software renderer, and is safe to use."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.modulationCrop, tr("Texture Modulation Cropping (\"Old/v0\" GPU)"), tr("Unchecked"),
|
||||
tr("Crops vertex colours to 5:5:5 before modulating with the texture colour, which typically results in more "
|
||||
"visible banding. This is a characteristic of the \"old\" GPUs found in early model consoles."));
|
||||
dialog->registerWidgetHelp(m_ui.scaledInterlacing, tr("Scaled Interlacing"), tr("Checked"),
|
||||
tr("Scales line skipping in interlaced rendering to the internal resolution. This makes "
|
||||
"the combing less obvious at higher resolutions. Usually safe to enable."));
|
||||
|
||||
@ -554,9 +554,9 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useSoftwareRendererForReadbacks">
|
||||
<widget class="QCheckBox" name="modulationCrop">
|
||||
<property name="text">
|
||||
<string>Software Renderer Readbacks</string>
|
||||
<string>Texture Modulation Cropping ("Old/v0 GPU")</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -567,6 +567,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="useSoftwareRendererForReadbacks">
|
||||
<property name="text">
|
||||
<string>Software Renderer Readbacks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user