GPU: Refactor and simplify deinterlacing

Both HW and SW deal with half-height buffers coming in now.
This commit is contained in:
Stenzek 2024-12-30 14:36:14 +10:00
parent 9cd9042563
commit c5bd4101b3
No known key found for this signature in database
9 changed files with 86 additions and 149 deletions

View File

@ -1883,19 +1883,22 @@ void GPU::ClearDisplay()
void GPU::UpdateDisplay(bool submit_frame)
{
const bool interlaced = IsInterlacedDisplayEnabled();
const u8 interlaced_field = GetInterlacedDisplayField();
const bool line_skip = (interlaced && m_GPUSTAT.vertical_resolution);
GPUBackendUpdateDisplayCommand* cmd = GPUBackend::NewUpdateDisplayCommand();
cmd->display_width = m_crtc_state.display_width;
cmd->display_height = m_crtc_state.display_height;
cmd->display_origin_left = m_crtc_state.display_origin_left;
cmd->display_origin_top = m_crtc_state.display_origin_top;
cmd->display_vram_left = m_crtc_state.display_vram_left;
cmd->display_vram_top = m_crtc_state.display_vram_top;
cmd->display_vram_top = m_crtc_state.display_vram_top + (interlaced_field & BoolToUInt8(line_skip));
cmd->display_vram_width = m_crtc_state.display_vram_width;
cmd->display_vram_height = m_crtc_state.display_vram_height;
cmd->display_vram_height = m_crtc_state.display_vram_height >> BoolToUInt8(interlaced);
cmd->X = m_crtc_state.regs.X;
cmd->interlaced_display_enabled = IsInterlacedDisplayEnabled();
cmd->interlaced_display_field = ConvertToBoolUnchecked(GetInterlacedDisplayField());
cmd->interlaced_display_interleaved = cmd->interlaced_display_enabled && m_GPUSTAT.vertical_resolution;
cmd->interlaced_display_enabled = interlaced;
cmd->interlaced_display_field = ConvertToBoolUnchecked(interlaced_field);
cmd->interlaced_display_interleaved = line_skip;
cmd->display_24bit = m_GPUSTAT.display_area_color_depth_24;
cmd->display_disabled = IsDisplayDisabled();
cmd->display_pixel_aspect_ratio = ComputePixelAspectRatio();

View File

@ -578,30 +578,15 @@ bool GPUBackend::CompileDisplayPipelines(bool display, bool deinterlace, bool ch
if (deinterlace)
{
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
std::unique_ptr<GPUShader> vso = g_gpu_device->CreateShader(GPUShaderStage::Vertex, shadergen.GetLanguage(),
shadergen.GenerateScreenQuadVertexShader(), error);
if (!vso)
return false;
GL_OBJECT_NAME(vso, "Deinterlace Vertex Shader");
std::unique_ptr<GPUShader> fso;
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
shadergen.GenerateInterleavedFieldExtractFragmentShader(), error)))
{
return false;
}
GL_OBJECT_NAME(fso, "Deinterlace Field Extract Fragment Shader");
plconfig.layout = GPUPipeline::Layout::SingleTextureAndPushConstants;
plconfig.vertex_shader = vso.get();
plconfig.fragment_shader = fso.get();
if (!(m_deinterlace_extract_pipeline = g_gpu_device->CreatePipeline(plconfig, error)))
return false;
GL_OBJECT_NAME(m_deinterlace_extract_pipeline, "Deinterlace Field Extract Pipeline");
plconfig.SetTargetFormats(GPUTexture::Format::RGBA8);
switch (g_gpu_settings.display_deinterlacing_mode)
{
@ -611,11 +596,10 @@ bool GPUBackend::CompileDisplayPipelines(bool display, bool deinterlace, bool ch
case DisplayDeinterlacingMode::Weave:
{
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
shadergen.GenerateDeinterlaceWeaveFragmentShader(), error)))
{
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(
GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateDeinterlaceWeaveFragmentShader(), error);
if (!fso)
return false;
}
GL_OBJECT_NAME(fso, "Weave Deinterlace Fragment Shader");
@ -631,11 +615,10 @@ bool GPUBackend::CompileDisplayPipelines(bool display, bool deinterlace, bool ch
case DisplayDeinterlacingMode::Blend:
{
if (!(fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
shadergen.GenerateDeinterlaceBlendFragmentShader(), error)))
{
std::unique_ptr<GPUShader> fso = g_gpu_device->CreateShader(
GPUShaderStage::Fragment, shadergen.GetLanguage(), shadergen.GenerateDeinterlaceBlendFragmentShader(), error);
if (!fso)
return false;
}
GL_OBJECT_NAME(fso, "Blend Deinterlace Fragment Shader");
@ -651,8 +634,9 @@ bool GPUBackend::CompileDisplayPipelines(bool display, bool deinterlace, bool ch
case DisplayDeinterlacingMode::Adaptive:
{
fso = g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
shadergen.GenerateFastMADReconstructFragmentShader(), error);
std::unique_ptr<GPUShader> fso =
g_gpu_device->CreateShader(GPUShaderStage::Fragment, shadergen.GetLanguage(),
shadergen.GenerateFastMADReconstructFragmentShader(), error);
if (!fso)
return false;
@ -704,13 +688,14 @@ bool GPUBackend::CompileDisplayPipelines(bool display, bool deinterlace, bool ch
void GPUBackend::HandleUpdateDisplayCommand(const GPUBackendUpdateDisplayCommand* cmd)
{
// Height has to be doubled because we halved it on the GPU side.
const GPUBackendUpdateDisplayCommand* ccmd = static_cast<const GPUBackendUpdateDisplayCommand*>(cmd);
m_display_width = ccmd->display_width;
m_display_height = ccmd->display_height;
m_display_origin_left = ccmd->display_origin_left;
m_display_origin_top = ccmd->display_origin_top;
m_display_vram_width = ccmd->display_vram_width;
m_display_vram_height = ccmd->display_vram_height;
m_display_vram_height = (ccmd->display_vram_height << BoolToUInt32(ccmd->interlaced_display_enabled));
m_display_pixel_aspect_ratio = ccmd->display_pixel_aspect_ratio;
UpdateDisplay(ccmd);
@ -1022,7 +1007,7 @@ void GPUBackend::DestroyDeinterlaceTextures()
m_current_deinterlace_buffer = 0;
}
bool GPUBackend::Deinterlace(u32 field, u32 line_skip)
bool GPUBackend::Deinterlace(u32 field)
{
GPUTexture* src = m_display_texture;
const u32 x = m_display_texture_view_x;
@ -1030,24 +1015,39 @@ bool GPUBackend::Deinterlace(u32 field, u32 line_skip)
const u32 width = m_display_texture_view_width;
const u32 height = m_display_texture_view_height;
const auto copy_to_field_buffer = [&](u32 buffer) {
if (!m_deinterlace_buffers[buffer] || m_deinterlace_buffers[buffer]->GetWidth() != width ||
m_deinterlace_buffers[buffer]->GetHeight() != height ||
m_deinterlace_buffers[buffer]->GetFormat() != src->GetFormat())
{
if (!g_gpu_device->ResizeTexture(&m_deinterlace_buffers[buffer], width, height, GPUTexture::Type::Texture,
src->GetFormat(), GPUTexture::Flags::None, false)) [[unlikely]]
{
return false;
}
GL_OBJECT_NAME_FMT(m_deinterlace_buffers[buffer], "Blend Deinterlace Buffer {}", buffer);
}
GL_INS_FMT("Copy {}x{} from {},{} to field buffer {}", width, height, x, y, buffer);
g_gpu_device->CopyTextureRegion(m_deinterlace_buffers[buffer].get(), 0, 0, 0, 0, m_display_texture, x, y, 0, 0,
width, height);
return true;
};
src->MakeReadyForSampling();
switch (g_gpu_settings.display_deinterlacing_mode)
{
case DisplayDeinterlacingMode::Disabled:
{
if (line_skip == 0)
return true;
// Still have to extract the field.
if (!DeinterlaceExtractField(0, src, x, y, width, height, line_skip)) [[unlikely]]
return false;
SetDisplayTexture(m_deinterlace_buffers[0].get(), m_display_depth_buffer, 0, 0, width, height);
GL_INS("Deinterlacing disabled, displaying field texture");
return true;
}
case DisplayDeinterlacingMode::Weave:
{
GL_SCOPE_FMT("DeinterlaceWeave({{{},{}}}, {}x{}, field={}, line_skip={})", x, y, width, height, field, line_skip);
GL_SCOPE_FMT("DeinterlaceWeave({{{},{}}}, {}x{}, field={})", x, y, width, height, field);
const u32 full_height = height * 2;
if (!DeinterlaceSetTargetSize(width, full_height, true)) [[unlikely]]
@ -1061,7 +1061,7 @@ bool GPUBackend::Deinterlace(u32 field, u32 line_skip)
g_gpu_device->SetRenderTarget(m_deinterlace_texture.get());
g_gpu_device->SetPipeline(m_deinterlace_pipeline.get());
g_gpu_device->SetTextureSampler(0, src, g_gpu_device->GetNearestSampler());
const u32 uniforms[] = {x, y, field, line_skip};
const u32 uniforms[4] = {x, y, field, 0};
g_gpu_device->PushUniformBuffer(uniforms, sizeof(uniforms));
g_gpu_device->SetViewportAndScissor(0, 0, width, full_height);
g_gpu_device->Draw(3, 0);
@ -1075,20 +1075,20 @@ bool GPUBackend::Deinterlace(u32 field, u32 line_skip)
{
constexpr u32 NUM_BLEND_BUFFERS = 2;
GL_SCOPE_FMT("DeinterlaceBlend({{{},{}}}, {}x{}, field={}, line_skip={})", x, y, width, height, field, line_skip);
GL_SCOPE_FMT("DeinterlaceBlend({{{},{}}}, {}x{}, field={})", x, y, width, height, field);
const u32 this_buffer = m_current_deinterlace_buffer;
m_current_deinterlace_buffer = (m_current_deinterlace_buffer + 1u) % NUM_BLEND_BUFFERS;
GL_INS_FMT("Current buffer: {}", this_buffer);
if (!DeinterlaceExtractField(this_buffer, src, x, y, width, height, line_skip) ||
!DeinterlaceSetTargetSize(width, height, false)) [[unlikely]]
if (!DeinterlaceSetTargetSize(width, height, false) || !copy_to_field_buffer(this_buffer)) [[unlikely]]
{
ClearDisplayTexture();
return false;
}
// TODO: could be implemented with alpha blending instead..
copy_to_field_buffer(this_buffer);
// TODO: could be implemented with alpha blending instead..
g_gpu_device->InvalidateRenderTarget(m_deinterlace_texture.get());
g_gpu_device->SetRenderTarget(m_deinterlace_texture.get());
g_gpu_device->SetPipeline(m_deinterlace_pipeline.get());
@ -1105,15 +1105,13 @@ bool GPUBackend::Deinterlace(u32 field, u32 line_skip)
case DisplayDeinterlacingMode::Adaptive:
{
GL_SCOPE_FMT("DeinterlaceAdaptive({{{},{}}}, {}x{}, field={}, line_skip={})", x, y, width, height, field,
line_skip);
GL_SCOPE_FMT("DeinterlaceAdaptive({{{},{}}}, {}x{}, field={})", x, y, width, height, field);
const u32 full_height = height * 2;
const u32 this_buffer = m_current_deinterlace_buffer;
const u32 full_height = height * 2;
m_current_deinterlace_buffer = (m_current_deinterlace_buffer + 1u) % DEINTERLACE_BUFFER_COUNT;
GL_INS_FMT("Current buffer: {}", this_buffer);
if (!DeinterlaceExtractField(this_buffer, src, x, y, width, height, line_skip) ||
!DeinterlaceSetTargetSize(width, full_height, false)) [[unlikely]]
if (!DeinterlaceSetTargetSize(width, full_height, false) || !copy_to_field_buffer(this_buffer)) [[unlikely]]
{
ClearDisplayTexture();
return false;
@ -1143,50 +1141,6 @@ bool GPUBackend::Deinterlace(u32 field, u32 line_skip)
}
}
bool GPUBackend::DeinterlaceExtractField(u32 dst_bufidx, GPUTexture* src, u32 x, u32 y, u32 width, u32 height,
u32 line_skip)
{
if (!m_deinterlace_buffers[dst_bufidx] || m_deinterlace_buffers[dst_bufidx]->GetWidth() != width ||
m_deinterlace_buffers[dst_bufidx]->GetHeight() != height)
{
if (!g_gpu_device->ResizeTexture(&m_deinterlace_buffers[dst_bufidx], width, height, GPUTexture::Type::RenderTarget,
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, false)) [[unlikely]]
{
return false;
}
GL_OBJECT_NAME_FMT(m_deinterlace_buffers[dst_bufidx], "Blend Deinterlace Buffer {}", dst_bufidx);
}
GPUTexture* dst = m_deinterlace_buffers[dst_bufidx].get();
g_gpu_device->InvalidateRenderTarget(dst);
// If we're not skipping lines, then we can simply copy the texture.
if (line_skip == 0 && src->GetFormat() == dst->GetFormat())
{
GL_INS_FMT("DeinterlaceExtractField({{{},{}}} {}x{} line_skip={}) => copy direct", x, y, width, height, line_skip);
g_gpu_device->CopyTextureRegion(dst, 0, 0, 0, 0, src, x, y, 0, 0, width, height);
}
else
{
GL_SCOPE_FMT("DeinterlaceExtractField({{{},{}}} {}x{} line_skip={}) => shader copy", x, y, width, height,
line_skip);
// Otherwise, we need to extract every other line from the texture.
src->MakeReadyForSampling();
g_gpu_device->SetRenderTarget(dst);
g_gpu_device->SetPipeline(m_deinterlace_extract_pipeline.get());
g_gpu_device->SetTextureSampler(0, src, g_gpu_device->GetNearestSampler());
const u32 uniforms[] = {x, y, line_skip};
g_gpu_device->PushUniformBuffer(uniforms, sizeof(uniforms));
g_gpu_device->SetViewportAndScissor(0, 0, width, height);
g_gpu_device->Draw(3, 0);
}
dst->MakeReadyForSampling();
return true;
}
bool GPUBackend::DeinterlaceSetTargetSize(u32 width, u32 height, bool preserve)
{
if (!m_deinterlace_texture || m_deinterlace_texture->GetWidth() != width ||

View File

@ -167,8 +167,7 @@ protected:
/// Sends the current frame to media capture.
void SendDisplayToMediaCapture(MediaCapture* cap);
bool Deinterlace(u32 field, u32 line_skip);
bool DeinterlaceExtractField(u32 dst_bufidx, GPUTexture* src, u32 x, u32 y, u32 width, u32 height, u32 line_skip);
bool Deinterlace(u32 field);
bool DeinterlaceSetTargetSize(u32 width, u32 height, bool preserve);
void DestroyDeinterlaceTextures();
bool ApplyChromaSmoothing();
@ -185,7 +184,6 @@ protected:
u32 m_current_deinterlace_buffer = 0;
std::unique_ptr<GPUPipeline> m_deinterlace_pipeline;
std::unique_ptr<GPUPipeline> m_deinterlace_extract_pipeline;
std::array<std::unique_ptr<GPUTexture>, DEINTERLACE_BUFFER_COUNT> m_deinterlace_buffers;
std::unique_ptr<GPUTexture> m_deinterlace_texture;

View File

@ -3843,14 +3843,12 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
const bool interlaced = cmd->interlaced_display_enabled;
const u32 interlaced_field = BoolToUInt32(cmd->interlaced_display_field);
const u32 line_skip = BoolToUInt32(cmd->interlaced_display_interleaved);
const u32 resolution_scale = cmd->display_24bit ? 1 : m_resolution_scale;
const u32 scaled_vram_offset_x = cmd->display_vram_left * resolution_scale;
const u32 scaled_vram_offset_y = (cmd->display_vram_top * resolution_scale) +
((interlaced && cmd->interlaced_display_interleaved) ? interlaced_field : 0);
const u32 scaled_vram_offset_y = cmd->display_vram_top * resolution_scale;
const u32 scaled_display_width = cmd->display_vram_width * resolution_scale;
const u32 scaled_display_height = cmd->display_vram_height * resolution_scale;
const u32 read_height = interlaced ? (scaled_display_height / 2u) : scaled_display_height;
const u32 line_skip = cmd->interlaced_display_interleaved;
bool drew_anything = false;
// Don't bother grabbing depth if postfx doesn't need it.
@ -3864,20 +3862,20 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
ClearDisplayTexture();
return;
}
else if (!cmd->display_24bit && !IsUsingMultisampling() &&
else if (!cmd->display_24bit && line_skip == 0 && !IsUsingMultisampling() &&
(scaled_vram_offset_x + scaled_display_width) <= m_vram_texture->GetWidth() &&
(scaled_vram_offset_y + scaled_display_height) <= m_vram_texture->GetHeight() &&
!PostProcessing::InternalChain.IsActive())
{
SetDisplayTexture(m_vram_texture.get(), depth_source, scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, read_height);
scaled_display_width, scaled_display_height);
// Fast path if no copies are needed.
if (interlaced)
{
GL_INS("Deinterlace fast path");
drew_anything = true;
Deinterlace(interlaced_field, line_skip);
Deinterlace(interlaced_field);
}
else
{
@ -3887,9 +3885,9 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
else
{
if (!m_vram_extract_texture || m_vram_extract_texture->GetWidth() != scaled_display_width ||
m_vram_extract_texture->GetHeight() != read_height)
m_vram_extract_texture->GetHeight() != scaled_display_height)
{
if (!g_gpu_device->ResizeTexture(&m_vram_extract_texture, scaled_display_width, read_height,
if (!g_gpu_device->ResizeTexture(&m_vram_extract_texture, scaled_display_width, scaled_display_height,
GPUTexture::Type::RenderTarget, GPUTexture::Format::RGBA8,
GPUTexture::Flags::None)) [[unlikely]]
{
@ -3929,8 +3927,8 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
GL_INS_FMT("VRAM extract, depth = {}, 24bpp = {}, skip_x = {}, line_skip = {}", depth_source ? "yes" : "no",
cmd->display_24bit, skip_x, line_skip);
GL_INS_FMT("Source: {},{} => {},{} ({}x{})", reinterpret_start_x, scaled_vram_offset_y,
reinterpret_start_x + scaled_display_width, scaled_vram_offset_y + read_height, scaled_display_width,
read_height);
reinterpret_start_x + scaled_display_width, (scaled_vram_offset_y + scaled_display_height) << line_skip,
scaled_display_width, scaled_display_height);
struct ExtractUniforms
{
@ -3943,7 +3941,7 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
static_cast<float>(line_skip ? 2 : 1)};
g_gpu_device->PushUniformBuffer(&uniforms, sizeof(uniforms));
g_gpu_device->SetViewportAndScissor(0, 0, scaled_display_width, read_height);
g_gpu_device->SetViewportAndScissor(0, 0, scaled_display_width, scaled_display_height);
g_gpu_device->Draw(3, 0);
m_vram_extract_texture->MakeReadyForSampling();
@ -3957,19 +3955,19 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
drew_anything = true;
SetDisplayTexture(m_vram_extract_texture.get(), depth_source ? m_vram_extract_depth_texture.get() : nullptr, 0, 0,
scaled_display_width, read_height);
scaled_display_width, scaled_display_height);
if (g_settings.display_24bit_chroma_smoothing)
{
if (ApplyChromaSmoothing())
{
if (interlaced)
Deinterlace(interlaced_field, 0);
Deinterlace(interlaced_field);
}
}
else
{
if (interlaced)
Deinterlace(interlaced_field, 0);
Deinterlace(interlaced_field);
}
}

View File

@ -1266,7 +1266,9 @@ float3 SampleVRAM24(uint2 icoords)
DeclareFragmentEntryPoint(ss, 0, 1, {}, true, depth_buffer ? 2 : 1);
ss << R"(
{
uint2 icoords = uint2(v_pos.x + u_skip_x, v_pos.y * u_line_skip);
// Have to floor because SV_Position is at the pixel center.
float2 v_pos_floored = floor(v_pos.xy);
uint2 icoords = uint2(v_pos_floored.x + u_skip_x, v_pos_floored.y * u_line_skip);
int2 wrapped_coords = int2((icoords + u_vram_offset) % VRAM_SIZE);
#if COLOR_24BIT

View File

@ -102,29 +102,11 @@ std::string GPUShaderGen::GenerateDisplaySharpBilinearFragmentShader() const
return ss.str();
}
std::string GPUShaderGen::GenerateInterleavedFieldExtractFragmentShader() const
{
std::stringstream ss;
WriteHeader(ss);
DeclareUniformBuffer(ss, {"uint2 u_src_offset", "uint u_line_skip"}, true);
DeclareTexture(ss, "samp0", 0, false);
DeclareFragmentEntryPoint(ss, 0, 1, {}, true);
ss << R"(
{
uint2 tcoord = u_src_offset + uint2(uint(v_pos.x), uint(v_pos.y) << u_line_skip);
o_col0 = LOAD_TEXTURE(samp0, int2(tcoord), 0);
}
)";
return ss.str();
}
std::string GPUShaderGen::GenerateDeinterlaceWeaveFragmentShader() const
{
std::stringstream ss;
WriteHeader(ss);
DeclareUniformBuffer(ss, {"uint2 u_src_offset", "uint u_render_field", "uint u_line_skip"}, true);
DeclareUniformBuffer(ss, {"uint2 u_src_offset", "uint u_render_field"}, true);
DeclareTexture(ss, "samp0", 0, false);
DeclareFragmentEntryPoint(ss, 0, 1, {}, true);
@ -134,7 +116,7 @@ std::string GPUShaderGen::GenerateDeinterlaceWeaveFragmentShader() const
if ((fcoord.y & 1) != u_render_field)
discard;
uint2 tcoord = u_src_offset + uint2(fcoord.x, (fcoord.y / 2u) << u_line_skip);
uint2 tcoord = u_src_offset + uint2(fcoord.x, (fcoord.y / 2u));
o_col0 = LOAD_TEXTURE(samp0, int2(tcoord), 0);
})";

View File

@ -15,7 +15,6 @@ public:
std::string GenerateDisplayFragmentShader(bool clamp_uv, bool nearest) const;
std::string GenerateDisplaySharpBilinearFragmentShader() const;
std::string GenerateInterleavedFieldExtractFragmentShader() const;
std::string GenerateDeinterlaceWeaveFragmentShader() const;
std::string GenerateDeinterlaceBlendFragmentShader() const;
std::string GenerateFastMADReconstructFragmentShader() const;

View File

@ -393,36 +393,37 @@ void GPU_SW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
}
const bool is_24bit = cmd->display_24bit;
const bool interlaced = cmd->interlaced_display_enabled;
const u32 field = BoolToUInt32(cmd->interlaced_display_field);
const u32 vram_offset_x = is_24bit ? cmd->X : cmd->display_vram_left;
const u32 vram_offset_y = cmd->display_vram_top + ((interlaced && cmd->interlaced_display_interleaved) ? field : 0);
const u32 line_skip = BoolToUInt32(cmd->interlaced_display_interleaved);
const u32 src_x = is_24bit ? cmd->X : cmd->display_vram_left;
const u32 skip_x = is_24bit ? (cmd->display_vram_left - cmd->X) : 0;
const u32 read_width = cmd->display_vram_width;
const u32 read_height = interlaced ? (cmd->display_vram_height / 2) : cmd->display_vram_height;
const u32 src_y = cmd->display_vram_top;
const u32 width = cmd->display_vram_width;
const u32 height = cmd->display_vram_height;
GL_INS_FMT("Software scanout {}x{} from {},{} line_skip={}", width, height, src_x, src_y, line_skip);
if (cmd->interlaced_display_enabled)
{
const u32 line_skip = cmd->interlaced_display_interleaved;
if (CopyOut(vram_offset_x, vram_offset_y, skip_x, read_width, read_height, line_skip, is_24bit))
if (CopyOut(src_x, src_y, skip_x, width, height, line_skip, is_24bit))
{
SetDisplayTexture(m_upload_texture.get(), nullptr, 0, 0, read_width, read_height);
SetDisplayTexture(m_upload_texture.get(), nullptr, 0, 0, width, height);
if (is_24bit && g_settings.display_24bit_chroma_smoothing)
{
if (ApplyChromaSmoothing())
Deinterlace(field, 0);
Deinterlace(field);
}
else
{
Deinterlace(field, 0);
Deinterlace(field);
}
}
}
else
{
if (CopyOut(vram_offset_x, vram_offset_y, skip_x, read_width, read_height, 0, is_24bit))
if (CopyOut(src_x, src_y, skip_x, width, height, 0, is_24bit))
{
SetDisplayTexture(m_upload_texture.get(), nullptr, 0, 0, read_width, read_height);
SetDisplayTexture(m_upload_texture.get(), nullptr, 0, 0, width, height);
if (is_24bit && g_settings.display_24bit_chroma_smoothing)
ApplyChromaSmoothing();
}

View File

@ -5,4 +5,4 @@
#include "common/types.h"
static constexpr u32 SHADER_CACHE_VERSION = 24;
static constexpr u32 SHADER_CACHE_VERSION = 25;