GPU: Refactor and simplify deinterlacing
Both HW and SW deal with half-height buffers coming in now.
This commit is contained in:
parent
9cd9042563
commit
c5bd4101b3
|
@ -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();
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
})";
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
|
||||
#include "common/types.h"
|
||||
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 24;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 25;
|
||||
|
|
Loading…
Reference in New Issue