GPU: Use vectors/rects for presentation

This commit is contained in:
Stenzek
2025-12-13 17:16:53 +10:00
parent 69784d10a3
commit 97582bcfec
10 changed files with 266 additions and 256 deletions

View File

@@ -735,18 +735,19 @@ float GPU::ComputeAspectRatioCorrection() const
return (relative_width / relative_height);
}
void GPU::ApplyPixelAspectRatioToSize(float par, float* width, float* height)
GSVector2 GPU::ApplyPixelAspectRatioToSize(float par, GSVector2 size)
{
if (par < 1.0f)
{
// stretch height, preserve width
*height = std::ceil(*height / par);
size.y = std::ceil(size.y / par);
}
else
{
// stretch width, preserve height
*width = std::ceil(*width * par);
size.x = std::ceil(size.x * par);
}
return size;
}
void GPU::UpdateCRTCConfig()
@@ -1016,6 +1017,32 @@ void GPU::UpdateCRTCDisplayParameters()
}
}
GSVector2i GPU::GetCRTCVideoSize() const
{
// Verify assumptions about struct layout.
static_assert(offsetof(CRTCState, display_width) + sizeof(u16) == offsetof(CRTCState, display_height));
return GSVector2i::load32(&m_crtc_state.display_width).u16to32();
}
GSVector4i GPU::GetCRTCVideoActiveRect() const
{
static_assert(offsetof(CRTCState, display_origin_left) + sizeof(u16) == offsetof(CRTCState, display_origin_top) &&
offsetof(CRTCState, display_vram_width) + sizeof(u16) == offsetof(CRTCState, display_vram_height));
const GSVector2i origin = GSVector2i::load32(&m_crtc_state.display_origin_left).u16to32();
const GSVector2i size = GSVector2i::load32(&m_crtc_state.display_vram_width).u16to32();
return GSVector4i::xyxy(origin, origin.add32(size));
}
GSVector4i GPU::GetCRTCVRAMSourceRect() const
{
static_assert(offsetof(CRTCState, display_vram_left) + sizeof(u16) == offsetof(CRTCState, display_vram_top) &&
offsetof(CRTCState, display_vram_top) + sizeof(u16) == offsetof(CRTCState, display_vram_width) &&
offsetof(CRTCState, display_vram_width) + sizeof(u16) == offsetof(CRTCState, display_vram_height));
const GSVector4i rc = GSVector4i::loadl<false>(&m_crtc_state.display_vram_left).u16to32();
const GSVector2i origin = rc.xy();
return GSVector4i::xyxy(origin, origin.add32(rc.zw()));
}
TickCount GPU::GetPendingCRTCTicks() const
{
const TickCount pending_sysclk_ticks = s_crtc_tick_event.GetTicksSinceLastExecution();
@@ -1325,14 +1352,13 @@ void GPU::ConvertScreenCoordinatesToDisplayCoordinates(float window_x, float win
return;
}
GSVector4i display_rc, draw_rc;
CalculateDrawRect(wi.surface_width, wi.surface_height, m_crtc_state.display_width, m_crtc_state.display_height,
m_crtc_state.display_origin_left, m_crtc_state.display_origin_top, m_crtc_state.display_vram_width,
m_crtc_state.display_vram_height, g_settings.display_rotation, g_settings.display_alignment,
GSVector4i source_rc, display_rc, draw_rc;
CalculateDrawRect(GSVector2i(wi.surface_width, wi.surface_height), GetCRTCVideoSize(), GetCRTCVideoActiveRect(),
GetCRTCVRAMSourceRect(), g_settings.display_rotation, g_settings.display_alignment,
ComputePixelAspectRatio(),
(g_settings.display_scaling == DisplayScalingMode::NearestInteger ||
g_settings.display_scaling == DisplayScalingMode::BilinearInteger),
&display_rc, &draw_rc);
&source_rc, &display_rc, &draw_rc);
// convert coordinates to active display region, then to full display region
const float scaled_display_x =
@@ -1774,20 +1800,20 @@ static bool IntegerScalePreferWidth(float display_width, float display_height, f
return (scale_width >= scale_height);
}
void GPU::CalculateDrawRect(u32 window_width, u32 window_height, u32 crtc_display_width, u32 crtc_display_height,
s32 display_origin_left, s32 display_origin_top, u32 display_vram_width,
u32 display_vram_height, DisplayRotation rotation, DisplayAlignment alignment,
float pixel_aspect_ratio, bool integer_scale, GSVector4i* display_rect,
GSVector4i* draw_rect)
void GPU::CalculateDrawRect(const GSVector2i& window_size, const GSVector2i& video_size,
const GSVector4i& video_active_rect, const GSVector4i& source_rect,
DisplayRotation rotation, DisplayAlignment alignment, float pixel_aspect_ratio,
bool integer_scale, GSVector4i* out_source_rect, GSVector4i* out_display_rect,
GSVector4i* out_draw_rect)
{
const float fwindow_width = static_cast<float>(window_width);
const float fwindow_height = static_cast<float>(window_height);
float display_width = static_cast<float>(crtc_display_width);
float display_height = static_cast<float>(crtc_display_height);
float active_left = static_cast<float>(display_origin_left);
float active_top = static_cast<float>(display_origin_top);
float active_width = static_cast<float>(display_vram_width);
float active_height = static_cast<float>(display_vram_height);
const float fwindow_width = static_cast<float>(window_size.x);
const float fwindow_height = static_cast<float>(window_size.y);
float display_width = static_cast<float>(video_size.x);
float display_height = static_cast<float>(video_size.y);
float active_left = static_cast<float>(video_active_rect.x);
float active_top = static_cast<float>(video_active_rect.y);
float active_width = static_cast<float>(video_active_rect.width());
float active_height = static_cast<float>(video_active_rect.height());
// for integer scale, use whichever gets us a greater effective display size
// this is needed for games like crash where the framebuffer is wide to not lose detail
@@ -1851,7 +1877,7 @@ void GPU::CalculateDrawRect(u32 window_width, u32 window_height, u32 crtc_displa
else
{
// align in middle horizontally
scale = static_cast<float>(window_height) / display_height;
scale = fwindow_height / display_height;
if (integer_scale)
{
// skip integer scaling if we cannot fit in the window at all
@@ -1885,8 +1911,9 @@ void GPU::CalculateDrawRect(u32 window_width, u32 window_height, u32 crtc_displa
const s32 top = static_cast<s32>(active_top * scale + top_padding);
const s32 right = left + static_cast<s32>(active_width * scale);
const s32 bottom = top + static_cast<s32>(active_height * scale);
*draw_rect = GSVector4i(left, top, right, bottom);
*display_rect = GSVector4i(
*out_source_rect = source_rect;
*out_draw_rect = GSVector4i(left, top, right, bottom);
*out_display_rect = GSVector4i(
GSVector4(left_padding, top_padding, left_padding + display_width * scale, top_padding + display_height * scale));
}
@@ -1939,23 +1966,46 @@ void GPU::UpdateDisplay(bool submit_frame)
submit_frame = (submit_frame && System::GetFramePresentationParameters(&frame));
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_width = m_crtc_state.display_vram_width;
cmd->display_vram_height = m_crtc_state.display_vram_height >> BoolToUInt8(interlaced);
cmd->X = m_crtc_state.regs.X;
cmd->gpu_busy_pct = g_settings.display_show_gpu_stats ? UpdateOrGetGPUBusyPct() : 0;
cmd->interlaced_display_enabled = interlaced;
cmd->interlaced_display_field = ConvertToBoolUnchecked(interlaced_field);
cmd->interlaced_display_interleaved = line_skip;
cmd->interleaved_480i_mode = m_GPUSTAT.InInterleaved480iMode();
cmd->display_24bit = m_GPUSTAT.display_area_color_depth_24;
cmd->display_disabled = IsDisplayDisabled();
cmd->display_pixel_aspect_ratio = ComputePixelAspectRatio();
if (!g_settings.gpu_show_vram) [[likely]]
{
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_width = m_crtc_state.display_vram_width;
cmd->display_vram_height = m_crtc_state.display_vram_height >> BoolToUInt8(interlaced);
cmd->X = m_crtc_state.regs.X;
cmd->interlaced_display_enabled = interlaced;
cmd->interlaced_display_field = ConvertToBoolUnchecked(interlaced_field);
cmd->interlaced_display_interleaved = line_skip;
cmd->interleaved_480i_mode = m_GPUSTAT.InInterleaved480iMode();
cmd->display_24bit = m_GPUSTAT.display_area_color_depth_24;
cmd->display_disabled = IsDisplayDisabled();
cmd->display_pixel_aspect_ratio = ComputePixelAspectRatio();
}
else
{
cmd->display_width = VRAM_WIDTH;
cmd->display_height = VRAM_HEIGHT;
cmd->display_origin_left = 0;
cmd->display_origin_top = 0;
cmd->display_vram_left = 0;
cmd->display_vram_top = 0;
cmd->display_vram_width = VRAM_WIDTH;
cmd->display_vram_height = VRAM_HEIGHT;
cmd->X = 0;
cmd->interlaced_display_enabled = false;
cmd->interlaced_display_field = false;
cmd->interlaced_display_interleaved = false;
cmd->interleaved_480i_mode = false;
cmd->display_24bit = false;
cmd->display_disabled = false;
cmd->display_pixel_aspect_ratio = 1.0f;
}
if ((cmd->submit_frame = submit_frame))
{
std::memcpy(&cmd->frame, &frame, sizeof(frame));
@@ -2001,12 +2051,11 @@ u8 GPU::CalculateAutomaticResolutionScale() const
!main_window_info.IsSurfaceless() && m_crtc_state.display_width > 0 && m_crtc_state.display_height > 0 &&
m_crtc_state.display_vram_width > 0 && m_crtc_state.display_vram_height > 0)
{
GSVector4i display_rect, draw_rect;
CalculateDrawRect(main_window_info.surface_width, main_window_info.surface_height, m_crtc_state.display_width,
m_crtc_state.display_height, m_crtc_state.display_origin_left, m_crtc_state.display_origin_top,
m_crtc_state.display_vram_width, m_crtc_state.display_vram_height, g_settings.display_rotation,
GSVector4i source_rect, display_rect, draw_rect;
CalculateDrawRect(GSVector2i(main_window_info.surface_width, main_window_info.surface_height), GetCRTCVideoSize(),
GetCRTCVideoActiveRect(), GetCRTCVRAMSourceRect(), g_settings.display_rotation,
g_settings.display_alignment, g_settings.gpu_show_vram ? 1.0f : ComputePixelAspectRatio(),
g_settings.IsUsingIntegerDisplayScaling(false), &display_rect, &draw_rect);
g_settings.IsUsingIntegerDisplayScaling(false), &source_rect, &display_rect, &draw_rect);
// We use the draw rect to determine scaling. This way we match the resolution as best we can, regardless of the
// anamorphic aspect ratio.

View File

@@ -12,6 +12,7 @@
#include "common/bitfield.h"
#include "common/fifo_queue.h"
#include "common/gsvector.h"
#include "common/types.h"
#include <algorithm>
@@ -196,7 +197,7 @@ public:
float ComputeAspectRatioCorrection() const;
/// Applies the pixel aspect ratio to a given size, preserving the larger dimension.
static void ApplyPixelAspectRatioToSize(float par, float* width, float* height);
static GSVector2 ApplyPixelAspectRatioToSize(float par, GSVector2 size);
// Converts window coordinates into horizontal ticks and scanlines. Returns false if out of range. Used for lightguns.
void ConvertScreenCoordinatesToDisplayCoordinates(float window_x, float window_y, float* display_x,
@@ -216,9 +217,11 @@ public:
// Returns the video clock frequency.
TickCount GetCRTCFrequency() const;
ALWAYS_INLINE u16 GetCRTCDotClockDivider() const { return m_crtc_state.dot_clock_divider; }
ALWAYS_INLINE s32 GetCRTCDisplayWidth() const { return m_crtc_state.display_width; }
ALWAYS_INLINE s32 GetCRTCDisplayHeight() const { return m_crtc_state.display_height; }
// Video output access.
GSVector2i GetCRTCVideoSize() const;
GSVector4i GetCRTCVideoActiveRect() const;
GSVector4i GetCRTCVRAMSourceRect() const;
// Ticks for hblank/vblank.
void CRTCTickEvent(TickCount ticks);
@@ -238,11 +241,11 @@ public:
u8 CalculateAutomaticResolutionScale() const;
/// Helper function for computing the draw rectangle in a larger window.
static void CalculateDrawRect(u32 window_width, u32 window_height, u32 crtc_display_width, u32 crtc_display_height,
s32 display_origin_left, s32 display_origin_top, u32 display_vram_width,
u32 display_vram_height, DisplayRotation rotation, DisplayAlignment alignment,
float pixel_aspect_ratio, bool integer_scale, GSVector4i* display_rect,
GSVector4i* draw_rect);
static void CalculateDrawRect(const GSVector2i& window_size, const GSVector2i& video_size,
const GSVector4i& video_active_rect, const GSVector4i& source_rect,
DisplayRotation rotation, DisplayAlignment alignment, float pixel_aspect_ratio,
bool integer_scale, GSVector4i* out_source_rect, GSVector4i* out_display_rect,
GSVector4i* out_draw_rect);
private:
TickCount CRTCTicksToSystemTicks(TickCount crtc_ticks, TickCount fractional_ticks) const;
@@ -274,7 +277,7 @@ private:
void UpdateDMARequest();
void UpdateGPUIdle();
/// Updates drawing area that's suitablef or clamping.
/// Updates drawing area that's suitable for clamping.
void SetClampedDrawingArea();
/// Sets/decodes GP0(E1h) (set draw mode).

View File

@@ -549,11 +549,19 @@ void GPUBackend::HandleUpdateDisplayCommand(const GPUBackendUpdateDisplayCommand
{
s_stats.gpu_busy_pct = cmd->gpu_busy_pct;
// Assumptions about struct layout.
static_assert(offsetof(GPUBackendUpdateDisplayCommand, display_width) + sizeof(u16) ==
offsetof(GPUBackendUpdateDisplayCommand, display_height));
static_assert(offsetof(GPUBackendUpdateDisplayCommand, display_origin_left) + sizeof(u16) ==
offsetof(GPUBackendUpdateDisplayCommand, display_origin_top));
// Height has to be doubled because we halved it on the GPU side.
m_presenter.SetDisplayParameters(cmd->display_width, cmd->display_height, cmd->display_origin_left,
cmd->display_origin_top, cmd->display_vram_width,
cmd->display_vram_height << BoolToUInt32(cmd->interlaced_display_enabled),
cmd->display_pixel_aspect_ratio, cmd->display_24bit);
const GSVector2i display_size = GSVector2i::load32(&cmd->display_width).u16to32();
const GSVector2i active_origin = GSVector2i::load32(&cmd->display_origin_left).u16to32();
const GSVector2i active_size =
GSVector2i(cmd->display_vram_width, cmd->display_vram_height << BoolToUInt32(cmd->interlaced_display_enabled));
const GSVector4i active_rect = GSVector4i::xyxy(active_origin, active_origin.add32(active_size));
m_presenter.SetDisplayParameters(display_size, active_rect, cmd->display_pixel_aspect_ratio, cmd->display_24bit);
UpdateDisplay(cmd);
if (cmd->submit_frame)
@@ -693,9 +701,10 @@ bool GPUBackend::RenderScreenshotToBuffer(u32 width, u32 height, bool postfx, bo
else
{
// Crop it if border overlay isn't enabled.
GSVector4i draw_rect, display_rect;
backend->GetPresenter().CalculateDrawRect(static_cast<s32>(width), static_cast<s32>(height), apply_aspect_ratio,
false, false, &display_rect, &draw_rect);
GSVector4i source_rect, draw_rect, display_rect;
backend->GetPresenter().CalculateDrawRect(GSVector2i(static_cast<s32>(width), static_cast<s32>(height)),
apply_aspect_ratio, false, false, &source_rect, &display_rect,
&draw_rect);
image_width = static_cast<u32>(display_rect.width());
image_height = static_cast<u32>(display_rect.height());
}

View File

@@ -547,8 +547,8 @@ bool GPU_HW::UpdateSettings(const GPUSettings& old_settings, Error* error)
{
Host::AddIconOSDMessage(OSDMessageType::Info, "ResolutionScaleChanged", ICON_FA_PAINTBRUSH,
fmt::format(TRANSLATE_FS("GPU_HW", "Internal resolution set to {0}x ({1}x{2})."),
resolution_scale, m_presenter.GetDisplayWidth() * resolution_scale,
m_presenter.GetDisplayHeight() * resolution_scale));
resolution_scale, m_presenter.GetVideoSize().x * resolution_scale,
m_presenter.GetVideoSize().y * resolution_scale));
}
if (m_multisamples != multisamples || g_gpu_settings.gpu_per_sample_shading != old_settings.gpu_per_sample_shading)
@@ -3982,13 +3982,11 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
if (IsUsingMultisampling())
{
UpdateVRAMReadTexture(!m_vram_dirty_draw_rect.eq(INVALID_RECT), !m_vram_dirty_write_rect.eq(INVALID_RECT));
m_presenter.SetDisplayTexture(m_vram_read_texture.get(), 0, 0, m_vram_read_texture->GetWidth(),
m_vram_read_texture->GetHeight());
m_presenter.SetDisplayTexture(m_vram_read_texture.get(), m_vram_read_texture->GetRect());
}
else
{
m_presenter.SetDisplayTexture(m_vram_texture.get(), 0, 0, m_vram_texture->GetWidth(),
m_vram_texture->GetHeight());
m_presenter.SetDisplayTexture(m_vram_texture.get(), m_vram_texture->GetRect());
}
return;
@@ -4019,8 +4017,9 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
(scaled_vram_offset_y + scaled_display_height) <= m_vram_texture->GetHeight() &&
(!m_internal_postfx || !m_internal_postfx->IsActive()))
{
m_presenter.SetDisplayTexture(m_vram_texture.get(), scaled_vram_offset_x, scaled_vram_offset_y,
scaled_display_width, scaled_display_height);
m_presenter.SetDisplayTexture(m_vram_texture.get(), GSVector4i(scaled_vram_offset_x, scaled_vram_offset_y,
scaled_vram_offset_x + scaled_display_width,
scaled_vram_offset_y + scaled_display_height));
// Fast path if no copies are needed.
if (interlaced)
@@ -4104,7 +4103,8 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
drew_anything = true;
m_presenter.SetDisplayTexture(m_vram_extract_texture.get(), 0, 0, scaled_display_width, scaled_display_height);
m_presenter.SetDisplayTexture(m_vram_extract_texture.get(),
GSVector4i(0, 0, scaled_display_width, scaled_display_height));
// Apply internal postfx if enabled.
if (m_internal_postfx && m_internal_postfx->IsActive() &&
@@ -4116,9 +4116,8 @@ void GPU_HW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
m_internal_postfx->Apply(
m_vram_extract_texture.get(), depth_source ? m_vram_extract_depth_texture.get() : nullptr,
m_internal_postfx->GetOutputTexture(), GSVector4i(0, 0, scaled_display_width, scaled_display_height),
m_presenter.GetDisplayWidth(), m_presenter.GetDisplayHeight(), cmd->display_vram_width,
cmd->display_vram_height);
m_presenter.SetDisplayTexture(postfx_output, 0, 0, postfx_output->GetWidth(), postfx_output->GetHeight());
m_presenter.GetVideoSize().x, m_presenter.GetVideoSize().y, cmd->display_vram_width, cmd->display_vram_height);
m_presenter.SetDisplayTexture(postfx_output, postfx_output->GetRect());
}
if (g_gpu_settings.display_24bit_chroma_smoothing)
@@ -4180,20 +4179,17 @@ void GPU_HW::OnBufferSwapped()
void GPU_HW::DownsampleFramebuffer()
{
GPUTexture* source = m_presenter.GetDisplayTexture();
const u32 left = m_presenter.GetDisplayTextureViewX();
const u32 top = m_presenter.GetDisplayTextureViewY();
const u32 width = m_presenter.GetDisplayTextureViewWidth();
const u32 height = m_presenter.GetDisplayTextureViewHeight();
const GSVector4i& source_rect = m_presenter.GetDisplayTextureRect();
if (m_downsample_mode == GPUDownsampleMode::Adaptive)
DownsampleFramebufferAdaptive(source, left, top, width, height);
DownsampleFramebufferAdaptive(source, source_rect);
else
DownsampleFramebufferBoxFilter(source, left, top, width, height);
DownsampleFramebufferBoxFilter(source, source_rect);
}
void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, const GSVector4i& source_rect)
{
GL_SCOPE_FMT("DownsampleFramebufferAdaptive ({},{} => {},{})", left, top, left + width, left + height);
GL_SCOPE_FMT("DownsampleFramebufferAdaptive({})", source_rect);
struct SmoothingUBOData
{
@@ -4203,6 +4199,10 @@ void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top
float lod;
};
const u32 left = static_cast<u32>(source_rect.x);
const u32 top = static_cast<u32>(source_rect.y);
const u32 width = static_cast<u32>(source_rect.width());
const u32 height = static_cast<u32>(source_rect.height());
if (!m_downsample_texture || m_downsample_texture->GetWidth() != width || m_downsample_texture->GetHeight() != height)
{
g_gpu_device->RecycleTexture(std::move(m_downsample_texture));
@@ -4302,14 +4302,17 @@ void GPU_HW::DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top
RestoreDeviceContext();
m_presenter.SetDisplayTexture(m_downsample_texture.get(), 0, 0, width, height);
m_presenter.SetDisplayTexture(m_downsample_texture.get(), GSVector4i(0, 0, width, height));
}
void GPU_HW::DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 top, u32 width, u32 height)
void GPU_HW::DownsampleFramebufferBoxFilter(GPUTexture* source, const GSVector4i& source_rect)
{
GL_SCOPE_FMT("DownsampleFramebufferBoxFilter({},{} => {},{} ({}x{})", left, top, left + width, top + height, width,
height);
GL_SCOPE_FMT("DownsampleFramebufferBoxFilter({})", source_rect);
const u32 left = static_cast<u32>(source_rect.x);
const u32 top = static_cast<u32>(source_rect.y);
const u32 width = static_cast<u32>(source_rect.width());
const u32 height = static_cast<u32>(source_rect.height());
const u32 ds_width = width / m_downsample_scale_or_levels;
const u32 ds_height = height / m_downsample_scale_or_levels;
@@ -4333,7 +4336,7 @@ void GPU_HW::DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 to
RestoreDeviceContext();
m_presenter.SetDisplayTexture(m_downsample_texture.get(), 0, 0, ds_width, ds_height);
m_presenter.SetDisplayTexture(m_downsample_texture.get(), GSVector4i(0, 0, ds_width, ds_height));
}
void GPU_HW::LoadInternalPostProcessing()

View File

@@ -263,8 +263,8 @@ private:
void UpdateDownsamplingLevels();
void DownsampleFramebuffer();
void DownsampleFramebufferAdaptive(GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebufferBoxFilter(GPUTexture* source, u32 left, u32 top, u32 width, u32 height);
void DownsampleFramebufferAdaptive(GPUTexture* source, const GSVector4i& source_rect);
void DownsampleFramebufferBoxFilter(GPUTexture* source, const GSVector4i& source_rect);
void LoadInternalPostProcessing();

View File

@@ -390,41 +390,27 @@ void GPUPresenter::ClearDisplay()
void GPUPresenter::ClearDisplayTexture()
{
m_display_texture = nullptr;
m_display_texture_view_x = 0;
m_display_texture_view_y = 0;
m_display_texture_view_width = 0;
m_display_texture_view_height = 0;
m_display_texture_rect = GSVector4i::zero();
}
void GPUPresenter::SetDisplayParameters(u16 display_width, u16 display_height, u16 display_origin_left,
u16 display_origin_top, u16 display_vram_width, u16 display_vram_height,
void GPUPresenter::SetDisplayParameters(const GSVector2i& video_size, const GSVector4i& video_active_rect,
float display_pixel_aspect_ratio, bool display_24bit)
{
m_display_width = display_width;
m_display_height = display_height;
m_display_origin_left = display_origin_left;
m_display_origin_top = display_origin_top;
m_display_vram_width = display_vram_width;
m_display_vram_height = display_vram_height;
m_video_size = video_size;
m_video_active_rect = video_active_rect;
m_display_pixel_aspect_ratio = display_pixel_aspect_ratio;
m_display_texture_24bit = display_24bit;
}
void GPUPresenter::SetDisplayTexture(GPUTexture* texture, s32 view_x, s32 view_y, s32 view_width, s32 view_height)
void GPUPresenter::SetDisplayTexture(GPUTexture* texture, const GSVector4i& source_rect)
{
DebugAssert(texture);
if (g_gpu_settings.display_auto_resize_window &&
(view_width != m_display_texture_view_width || view_height != m_display_texture_view_height))
{
if (g_gpu_settings.display_auto_resize_window && !m_display_texture_rect.rsize().eq(source_rect.rsize()))
Host::RunOnCPUThread([]() { System::RequestDisplaySize(); });
}
m_display_texture = texture;
m_display_texture_view_x = view_x;
m_display_texture_view_y = view_y;
m_display_texture_view_width = view_width;
m_display_texture_view_height = view_height;
m_display_texture_rect = source_rect;
}
GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const GSVector2i target_size, bool postfx,
@@ -450,6 +436,7 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
GL_INS_FMT("Final target size: {}x{}", target_size.x, target_size.y);
// Compute draw area.
GSVector4i source_rect;
GSVector4i display_rect, display_rect_without_overlay;
GSVector4i draw_rect, draw_rect_without_overlay;
GSVector4i overlay_display_rect = GSVector4i::zero();
@@ -470,8 +457,8 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
GSVector4i(GSVector4(m_border_overlay_display_rect) * GSVector4::xyxy(scale)).add32(overlay_rect.xyxy());
// Draw to the overlay area instead of the whole screen. Always align in center, we align the overlay instead.
CalculateDrawRect(overlay_display_rect.width(), overlay_display_rect.height(), apply_aspect_ratio, integer_scale,
false, &display_rect_without_overlay, &draw_rect_without_overlay);
CalculateDrawRect(overlay_display_rect.rsize(), apply_aspect_ratio, integer_scale, false, &source_rect,
&display_rect_without_overlay, &draw_rect_without_overlay);
// Apply overlay area offset.
display_rect = display_rect_without_overlay.add32(overlay_display_rect.xyxy());
@@ -479,8 +466,8 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
}
else
{
CalculateDrawRect(target_size.x, target_size.y, apply_aspect_ratio, integer_scale, true,
&display_rect_without_overlay, &draw_rect_without_overlay);
CalculateDrawRect(target_size, apply_aspect_ratio, integer_scale, true, &source_rect, &display_rect_without_overlay,
&draw_rect_without_overlay);
display_rect = display_rect_without_overlay;
draw_rect = draw_rect_without_overlay;
}
@@ -547,7 +534,8 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
{
// Display is always drawn to the postfx input.
GPUTexture* postfx_input = GetDisplayPostProcessInputTexture(
draw_rect_without_overlay, postfx_delayed_rotation ? DisplayRotation::Normal : g_gpu_settings.display_rotation);
source_rect, draw_rect_without_overlay,
postfx_delayed_rotation ? DisplayRotation::Normal : g_gpu_settings.display_rotation);
postfx_input->MakeReadyForSampling();
// Apply postprocessing to an intermediate texture if we're prerotating or have an overlay.
@@ -627,8 +615,9 @@ GPUDevice::PresentResult GPUPresenter::RenderDisplay(GPUTexture* target, const G
if (m_display_texture)
{
DrawDisplay(target_size, final_target_size, draw_rect, have_overlay && m_border_overlay_destination_alpha_blend,
g_gpu_settings.display_rotation, prerotation);
DrawDisplay(target_size, final_target_size, source_rect, draw_rect,
have_overlay && m_border_overlay_destination_alpha_blend, g_gpu_settings.display_rotation,
prerotation);
}
return GPUDevice::PresentResult::OK;
@@ -708,8 +697,8 @@ void GPUPresenter::DrawOverlayBorders(const GSVector2i target_size, const GSVect
}
void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector2i final_target_size,
const GSVector4i display_rect, bool dst_alpha_blend, DisplayRotation rotation,
WindowInfo::PreRotation prerotation) const
const GSVector4i source_rect, const GSVector4i display_rect, bool dst_alpha_blend,
DisplayRotation rotation, WindowInfo::PreRotation prerotation) const
{
bool texture_filter_linear = false;
@@ -722,6 +711,7 @@ void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector2i fi
std::memset(uniforms.params, 0, sizeof(uniforms.params));
const GSVector2 display_texture_size = GSVector2(m_display_texture->GetSizeVec());
const GSVector2i display_source_rect = source_rect.rsize();
switch (m_display_texture_24bit ? g_gpu_settings.display_scaling_24bit : g_gpu_settings.display_scaling)
{
@@ -745,14 +735,11 @@ void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector2i fi
case DisplayScalingMode::BilinearHybrid:
case DisplayScalingMode::BilinearSharp:
{
const GSVector2 region_range =
(GSVector2(display_rect.rsize()) / GSVector2(display_source_rect)).floor().max(GSVector2::cxpr(1.0f));
GSVector2::store<true>(&uniforms.params[0], region_range);
GSVector2::store<true>(&uniforms.params[1], GSVector2::cxpr(0.5f) - (GSVector2::cxpr(0.5f) / region_range));
texture_filter_linear = true;
uniforms.params[0] = std::max(
std::floor(static_cast<float>(display_rect.width()) / static_cast<float>(m_display_texture_view_width)), 1.0f);
uniforms.params[1] = std::max(
std::floor(static_cast<float>(display_rect.height()) / static_cast<float>(m_display_texture_view_height)),
1.0f);
uniforms.params[2] = 0.5f - 0.5f / uniforms.params[0];
uniforms.params[3] = 0.5f - 0.5f / uniforms.params[1];
}
break;
@@ -771,16 +758,10 @@ void GPUPresenter::DrawDisplay(const GSVector2i target_size, const GSVector2i fi
// For bilinear, clamp to 0.5/SIZE-0.5 to avoid bleeding from the adjacent texels in VRAM. This is because
// 1.0 in UV space is not the bottom-right texel, but a mix of the bottom-right and wrapped/next texel.
const GSVector4 display_texture_size4 = GSVector4::xyxy(display_texture_size);
const GSVector4 uv_rect = GSVector4(GSVector4i(m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_x + m_display_texture_view_width,
m_display_texture_view_y + m_display_texture_view_height)) /
display_texture_size4;
GSVector4::store<true>(
uniforms.clamp_rect,
GSVector4(static_cast<float>(m_display_texture_view_x) + 0.5f, static_cast<float>(m_display_texture_view_y) + 0.5f,
static_cast<float>(m_display_texture_view_x + m_display_texture_view_width) - 0.5f,
static_cast<float>(m_display_texture_view_y + m_display_texture_view_height) - 0.5f) /
display_texture_size4);
const GSVector4 fsource_rect = GSVector4(source_rect);
const GSVector4 uv_rect = fsource_rect / display_texture_size4;
GSVector4::store<true>(uniforms.clamp_rect,
(fsource_rect + GSVector4::cxpr(0.5f, 0.5f, -0.5f, -0.5f)) / display_texture_size4);
GSVector4::store<true>(uniforms.src_size,
GSVector4::xyxy(display_texture_size, GSVector2::cxpr(1.0f) / display_texture_size));
@@ -852,24 +833,24 @@ GSVector2i GPUPresenter::CalculateDisplayPostProcessSourceSize() const
DebugAssert(m_display_postfx);
// Unscaled is easy.
const GSVector2i input_size = m_display_texture_rect.rsize();
if (!m_display_postfx->WantsUnscaledInput())
{
// Render to an input texture that's viewport sized. Source is the "real" input texture.
return GSVector2i(m_display_texture_view_width, m_display_texture_view_height);
return input_size;
}
else
{
// Need to include the borders in the size. This is very janky, since we need to correct upscaling.
// Source and input is the full display texture size (including padding).
const GSVector2i input_size = GSVector2i(m_display_texture_view_width, m_display_texture_view_height);
const GSVector2i native_size = GSVector2i(m_display_vram_width, m_display_vram_height);
const GSVector2i native_display_size = GSVector2i(m_display_width, m_display_height);
const GSVector2i native_size = m_video_active_rect.rsize();
const GSVector2 scale = GSVector2(input_size) / GSVector2(native_size);
return GSVector2i((GSVector2(native_display_size) * scale).ceil());
return GSVector2i((GSVector2(m_video_size) * scale).ceil());
}
}
GPUTexture* GPUPresenter::GetDisplayPostProcessInputTexture(const GSVector4i draw_rect_without_overlay,
GPUTexture* GPUPresenter::GetDisplayPostProcessInputTexture(const GSVector4i source_rect,
const GSVector4i draw_rect_without_overlay,
DisplayRotation rotation) const
{
DebugAssert(m_display_postfx);
@@ -886,7 +867,7 @@ GPUTexture* GPUPresenter::GetDisplayPostProcessInputTexture(const GSVector4i dra
g_gpu_device->SetRenderTarget(postfx_input);
g_gpu_device->SetViewport(GSVector4i::loadh(postfx_input_size));
DrawDisplay(postfx_input_size, postfx_input_size, draw_rect_without_overlay, false, rotation,
DrawDisplay(postfx_input_size, postfx_input_size, source_rect, draw_rect_without_overlay, false, rotation,
WindowInfo::PreRotation::Identity);
}
}
@@ -896,25 +877,19 @@ GPUTexture* GPUPresenter::GetDisplayPostProcessInputTexture(const GSVector4i dra
// OpenGL needs to flip the correct way around. If the source is exactly the same size without any correction we can
// pass it through to the chain directly. Except if the swap chain isn't using BGRA8, then we need to blit too.
if (g_gpu_device->UsesLowerLeftOrigin() || rotation != DisplayRotation::Normal || m_display_origin_left != 0 ||
m_display_origin_top != 0 || m_display_vram_width != m_display_width ||
m_display_vram_height != m_display_height || m_display_texture->GetFormat() != m_present_format)
if (g_gpu_device->UsesLowerLeftOrigin() || rotation != DisplayRotation::Normal ||
!m_video_active_rect.eq(GSVector4i::loadh(m_video_size)) || m_display_texture->GetFormat() != m_present_format)
{
GL_SCOPE_FMT("Pre-process postfx source");
const GSVector2i input_size = GSVector2i(m_display_texture_view_width, m_display_texture_view_height);
const GSVector2i native_size = GSVector2i(m_display_vram_width, m_display_vram_height);
const GSVector2i input_size = m_display_texture_rect.rsize();
const GSVector2i native_size = m_video_active_rect.rsize();
const GSVector2 input_scale = GSVector2(input_size) / GSVector2(native_size);
const GSVector4i input_draw_rect = GSVector4i(
(GSVector4(GSVector4i(m_display_origin_left, m_display_origin_top, m_display_origin_left + m_display_vram_width,
m_display_origin_top + m_display_vram_height)) *
GSVector4::xyxy(input_scale))
.floor());
const GSVector4i input_draw_rect =
GSVector4i((GSVector4(m_video_active_rect) * GSVector4::xyxy(input_scale)).floor());
const GSVector4 src_uv_rect = GSVector4(GSVector4i(m_display_texture_view_x, m_display_texture_view_y,
m_display_texture_view_x + m_display_texture_view_width,
m_display_texture_view_y + m_display_texture_view_height)) /
GSVector4::xyxy(GSVector2(m_display_texture->GetSizeVec()));
const GSVector4 src_uv_rect =
GSVector4(GSVector4i(m_display_texture_rect)) / GSVector4::xyxy(GSVector2(m_display_texture->GetSizeVec()));
postfx_input = m_display_postfx->GetInputTexture();
m_display_texture->MakeReadyForSampling();
@@ -928,16 +903,15 @@ GPUTexture* GPUPresenter::GetDisplayPostProcessInputTexture(const GSVector4i dra
DrawScreenQuad(input_draw_rect, src_uv_rect, postfx_input_size, postfx_input_size, rotation,
WindowInfo::PreRotation::Identity, nullptr, 0);
}
else if (m_display_texture_view_x != 0 || m_display_texture_view_y != 0 ||
m_display_texture->GetWidth() != static_cast<u32>(m_display_texture_view_width) ||
m_display_texture->GetHeight() != static_cast<u32>(m_display_texture_view_height))
else if (!m_display_texture_rect.eq(m_display_texture->GetRect()))
{
GL_SCOPE_FMT("Copy postfx source");
postfx_input = m_display_postfx->GetInputTexture();
g_gpu_device->CopyTextureRegion(postfx_input, 0, 0, 0, 0, m_display_texture, m_display_texture_view_x,
m_display_texture_view_y, 0, 0, m_display_texture_view_width,
m_display_texture_view_height);
g_gpu_device->CopyTextureRegion(
postfx_input, 0, 0, 0, 0, m_display_texture, static_cast<u32>(m_display_texture_rect.x),
static_cast<u32>(m_display_texture_rect.y), 0, 0, static_cast<u32>(m_display_texture_rect.width()),
static_cast<u32>(m_display_texture_rect.height()));
}
}
@@ -958,13 +932,9 @@ GPUDevice::PresentResult GPUPresenter::ApplyDisplayPostProcess(GPUTexture* targe
}
// "original size" in postfx includes padding.
const float upscale_x = static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_vram_width);
const float upscale_y = static_cast<float>(m_display_texture_view_height) / static_cast<float>(m_display_vram_height);
const s32 orig_width = static_cast<s32>(std::ceil(static_cast<float>(m_display_width) * upscale_x));
const s32 orig_height = static_cast<s32>(std::ceil(static_cast<float>(m_display_height) * upscale_y));
return m_display_postfx->Apply(input, nullptr, target, display_rect, orig_width, orig_height, m_display_width,
m_display_height);
const GSVector2 upscale = GSVector2(m_display_texture_rect.rsize()) / GSVector2(m_video_active_rect.rsize());
const GSVector2i orig = GSVector2i((GSVector2(m_video_size) * upscale).ceil());
return m_display_postfx->Apply(input, nullptr, target, display_rect, orig.x, orig.y, m_video_size.x, m_video_size.y);
}
void GPUPresenter::SendDisplayToMediaCapture(MediaCapture* cap)
@@ -1003,10 +973,10 @@ void GPUPresenter::DestroyDeinterlaceTextures()
bool GPUPresenter::Deinterlace(u32 field)
{
GPUTexture* const src = m_display_texture;
const u32 x = m_display_texture_view_x;
const u32 y = m_display_texture_view_y;
const u32 width = m_display_texture_view_width;
const u32 height = m_display_texture_view_height;
const u32 x = static_cast<u32>(m_display_texture_rect.x);
const u32 y = static_cast<u32>(m_display_texture_rect.y);
const u32 width = static_cast<u32>(m_display_texture_rect.width());
const u32 height = static_cast<u32>(m_display_texture_rect.height());
const auto copy_to_field_buffer = [this, &src, &x, &y, &width, &height](u32 buffer) {
if (!g_gpu_device->ResizeTexture(&m_deinterlace_buffers[buffer], width, height, GPUTexture::Type::Texture,
@@ -1053,7 +1023,7 @@ bool GPUPresenter::Deinterlace(u32 field)
g_gpu_device->DrawWithPushConstants(3, 0, uniforms, sizeof(uniforms));
m_deinterlace_texture->MakeReadyForSampling();
SetDisplayTexture(m_deinterlace_texture.get(), 0, 0, width, full_height);
SetDisplayTexture(m_deinterlace_texture.get(), GSVector4i::loadh(GSVector2i(width, full_height)));
return true;
}
@@ -1100,7 +1070,7 @@ bool GPUPresenter::Deinterlace(u32 field)
g_gpu_device->Draw(3, 0);
m_deinterlace_texture->MakeReadyForSampling();
SetDisplayTexture(m_deinterlace_texture.get(), 0, 0, width, height);
SetDisplayTexture(m_deinterlace_texture.get(), GSVector4i::loadh(GSVector2i(width, height)));
return true;
}
@@ -1151,7 +1121,7 @@ bool GPUPresenter::Deinterlace(u32 field)
g_gpu_device->DrawWithPushConstants(3, 0, uniforms, sizeof(uniforms));
m_deinterlace_texture->MakeReadyForSampling();
SetDisplayTexture(m_deinterlace_texture.get(), 0, 0, width, full_height);
SetDisplayTexture(m_deinterlace_texture.get(), GSVector4i::loadh(GSVector2i(width, full_height)));
return true;
}
@@ -1174,10 +1144,10 @@ bool GPUPresenter::DeinterlaceSetTargetSize(u32 width, u32 height, bool preserve
bool GPUPresenter::ApplyChromaSmoothing()
{
const u32 x = m_display_texture_view_x;
const u32 y = m_display_texture_view_y;
const u32 width = m_display_texture_view_width;
const u32 height = m_display_texture_view_height;
const u32 x = static_cast<u32>(m_display_texture_rect.x);
const u32 y = static_cast<u32>(m_display_texture_rect.y);
const u32 width = static_cast<u32>(m_display_texture_rect.width());
const u32 height = static_cast<u32>(m_display_texture_rect.height());
if (!g_gpu_device->ResizeTexture(&m_chroma_smoothing_texture, width, height, GPUTexture::Type::RenderTarget,
GPUTexture::Format::RGBA8, GPUTexture::Flags::None, false))
{
@@ -1200,27 +1170,18 @@ bool GPUPresenter::ApplyChromaSmoothing()
g_gpu_device->DrawWithPushConstants(3, 0, uniforms, sizeof(uniforms));
m_chroma_smoothing_texture->MakeReadyForSampling();
SetDisplayTexture(m_chroma_smoothing_texture.get(), 0, 0, width, height);
SetDisplayTexture(m_chroma_smoothing_texture.get(), GSVector4i::loadh(GSVector2i(width, height)));
return true;
}
void GPUPresenter::CalculateDrawRect(s32 window_width, s32 window_height, bool apply_aspect_ratio, bool integer_scale,
bool apply_alignment, GSVector4i* display_rect, GSVector4i* draw_rect) const
void GPUPresenter::CalculateDrawRect(const GSVector2i& window_size, bool apply_aspect_ratio, bool integer_scale,
bool apply_alignment, GSVector4i* source_rect, GSVector4i* display_rect,
GSVector4i* draw_rect) const
{
const bool show_vram = g_gpu_settings.gpu_show_vram;
const u32 display_width = show_vram ? VRAM_WIDTH : m_display_width;
const u32 display_height = show_vram ? VRAM_HEIGHT : m_display_height;
const s32 display_origin_left = show_vram ? 0 : m_display_origin_left;
const s32 display_origin_top = show_vram ? 0 : m_display_origin_top;
const u32 display_vram_width = show_vram ? VRAM_WIDTH : m_display_vram_width;
const u32 display_vram_height = show_vram ? VRAM_HEIGHT : m_display_vram_height;
const float display_pixel_aspect_ratio = (show_vram || !apply_aspect_ratio) ? 1.0f : m_display_pixel_aspect_ratio;
const DisplayRotation display_rotation = show_vram ? DisplayRotation::Normal : g_gpu_settings.display_rotation;
const DisplayAlignment display_alignment =
apply_alignment ? g_gpu_settings.display_alignment : DisplayAlignment::Center;
GPU::CalculateDrawRect(window_width, window_height, display_width, display_height, display_origin_left,
display_origin_top, display_vram_width, display_vram_height, display_rotation,
display_alignment, display_pixel_aspect_ratio, integer_scale, display_rect, draw_rect);
GPU::CalculateDrawRect(
window_size, m_video_size, m_video_active_rect, m_display_texture_rect, g_gpu_settings.display_rotation,
apply_alignment ? g_gpu_settings.display_alignment : DisplayAlignment::Center,
apply_aspect_ratio ? m_display_pixel_aspect_ratio : 1.0f, integer_scale, source_rect, display_rect, draw_rect);
}
bool GPUPresenter::PresentFrame(GPUPresenter* presenter, GPUBackend* backend, bool allow_skip_present, u64 present_time)
@@ -1401,35 +1362,33 @@ bool GPUPresenter::RenderScreenshotToBuffer(u32 width, u32 height, bool postfx,
GSVector2i GPUPresenter::CalculateScreenshotSize(DisplayScreenshotMode mode) const
{
if (m_display_texture_view_width != 0 && m_display_texture_view_height != 0)
if (m_display_texture)
{
if (g_gpu_settings.gpu_show_vram)
{
return GSVector2i(m_display_texture_view_width, m_display_texture_view_height);
return m_display_texture->GetSizeVec();
}
else if (mode != DisplayScreenshotMode::ScreenResolution)
{
float f_width =
m_display_width * (static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_vram_width));
float f_height = m_display_height *
(static_cast<float>(m_display_texture_view_height) / static_cast<float>(m_display_vram_height));
GSVector2 f_size =
GSVector2(m_video_size) * (GSVector2(m_display_texture_rect.rsize()) / GSVector2(m_video_active_rect.rsize()));
if (mode != DisplayScreenshotMode::UncorrectedInternalResolution)
GPU::ApplyPixelAspectRatioToSize(m_display_pixel_aspect_ratio, &f_width, &f_height);
f_size = GPU::ApplyPixelAspectRatioToSize(m_display_pixel_aspect_ratio, f_size);
// DX11 won't go past 16K texture size.
const float max_texture_size = static_cast<float>(g_gpu_device->GetMaxTextureSize());
if (f_width > max_texture_size)
if (f_size.x > max_texture_size)
{
f_height = f_height / (f_width / max_texture_size);
f_width = max_texture_size;
f_size.y = f_size.y / (f_size.x / max_texture_size);
f_size.x = max_texture_size;
}
if (f_height > max_texture_size)
if (f_size.y > max_texture_size)
{
f_height = max_texture_size;
f_width = f_width / (f_height / max_texture_size);
f_size.y = max_texture_size;
f_size.x = f_size.x / (f_size.y / max_texture_size);
}
return GSVector2i(static_cast<s32>(std::ceil(f_width)), static_cast<s32>(std::ceil(f_height)));
return GSVector2i(f_size.ceil());
}
}

View File

@@ -34,15 +34,9 @@ public:
GPUPresenter();
virtual ~GPUPresenter();
ALWAYS_INLINE s32 GetDisplayWidth() const { return m_display_width; }
ALWAYS_INLINE s32 GetDisplayHeight() const { return m_display_height; }
ALWAYS_INLINE s32 GetDisplayVRAMWidth() const { return m_display_vram_width; }
ALWAYS_INLINE s32 GetDisplayVRAMHeight() const { return m_display_vram_height; }
ALWAYS_INLINE s32 GetDisplayTextureViewX() const { return m_display_texture_view_x; }
ALWAYS_INLINE s32 GetDisplayTextureViewY() const { return m_display_texture_view_y; }
ALWAYS_INLINE s32 GetDisplayTextureViewWidth() const { return m_display_texture_view_width; }
ALWAYS_INLINE s32 GetDisplayTextureViewHeight() const { return m_display_texture_view_height; }
ALWAYS_INLINE const GSVector2i& GetVideoSize() const { return m_video_size; }
ALWAYS_INLINE GPUTexture* GetDisplayTexture() const { return m_display_texture; }
ALWAYS_INLINE const GSVector4i& GetDisplayTextureRect() const { return m_display_texture_rect; }
ALWAYS_INLINE bool HasDisplayTexture() const { return m_display_texture; }
ALWAYS_INLINE bool HasBorderOverlay() const { return static_cast<bool>(m_border_overlay_texture); }
@@ -53,16 +47,16 @@ public:
void ClearDisplay();
void ClearDisplayTexture();
void SetDisplayParameters(u16 display_width, u16 display_height, u16 display_origin_left, u16 display_origin_top,
u16 display_vram_width, u16 display_vram_height, float display_pixel_aspect_ratio,
bool display_24bit);
void SetDisplayTexture(GPUTexture* texture, s32 view_x, s32 view_y, s32 view_width, s32 view_height);
void SetDisplayParameters(const GSVector2i& video_size, const GSVector4i& video_active_rect,
float display_pixel_aspect_ratio, bool display_24bit);
void SetDisplayTexture(GPUTexture* texture, const GSVector4i& source_rect);
bool Deinterlace(u32 field);
bool ApplyChromaSmoothing();
/// Helper function for computing the draw rectangle in a larger window.
void CalculateDrawRect(s32 window_width, s32 window_height, bool apply_aspect_ratio, bool integer_scale,
bool apply_alignment, GSVector4i* display_rect, GSVector4i* draw_rect) const;
void CalculateDrawRect(const GSVector2i& window_size, bool apply_aspect_ratio, bool integer_scale,
bool apply_alignment, GSVector4i* source_rect, GSVector4i* display_rect,
GSVector4i* draw_rect) const;
/// Helper function for computing screenshot bounds.
GSVector2i CalculateScreenshotSize(DisplayScreenshotMode mode) const;
@@ -111,11 +105,13 @@ private:
void DrawOverlayBorders(const GSVector2i target_size, const GSVector2i final_target_size,
const GSVector4i overlay_display_rect, const GSVector4i draw_rect,
const WindowInfo::PreRotation prerotation) const;
void DrawDisplay(const GSVector2i target_size, const GSVector2i final_target_size, const GSVector4i display_rect,
bool dst_alpha_blend, DisplayRotation rotation, WindowInfo::PreRotation prerotation) const;
void DrawDisplay(const GSVector2i target_size, const GSVector2i final_target_size, const GSVector4i source_rect,
const GSVector4i display_rect, bool dst_alpha_blend, DisplayRotation rotation,
WindowInfo::PreRotation prerotation) const;
GSVector2i CalculateDisplayPostProcessSourceSize() const;
GPUTexture* GetDisplayPostProcessInputTexture(const GSVector4i draw_rect_without_overlay,
GPUTexture* GetDisplayPostProcessInputTexture(const GSVector4i source_rect,
const GSVector4i draw_rect_without_overlay,
DisplayRotation rotation) const;
GPUDevice::PresentResult ApplyDisplayPostProcess(GPUTexture* target, GPUTexture* input, const GSVector4i display_rect,
const GSVector2i postfx_size) const;
@@ -130,13 +126,8 @@ private:
bool LoadOverlayTexture();
bool LoadOverlayPreset(Error* error, Image* image);
s32 m_display_width = 0;
s32 m_display_height = 0;
s32 m_display_origin_left = 0;
s32 m_display_origin_top = 0;
s32 m_display_vram_width = 0;
s32 m_display_vram_height = 0;
GSVector2i m_video_size = GSVector2i::cxpr(0);
GSVector4i m_video_active_rect = GSVector4i::cxpr(0);
float m_display_pixel_aspect_ratio = 1.0f;
u32 m_current_deinterlace_buffer = 0;
@@ -150,10 +141,7 @@ private:
std::unique_ptr<GPUPipeline> m_display_pipeline;
std::unique_ptr<GPUPipeline> m_display_24bit_pipeline;
GPUTexture* m_display_texture = nullptr;
s32 m_display_texture_view_x = 0;
s32 m_display_texture_view_y = 0;
s32 m_display_texture_view_width = 0;
s32 m_display_texture_view_height = 0;
GSVector4i m_display_texture_rect = GSVector4i::cxpr(0);
u32 m_skipped_present_count = 0;
GPUTexture::Format m_present_format = GPUTexture::Format::Unknown;

View File

@@ -411,7 +411,7 @@ void GPU_SW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
{
if (CopyOut(src_x, src_y, skip_x, width, height, line_skip, is_24bit))
{
m_presenter.SetDisplayTexture(m_upload_texture.get(), 0, 0, width, height);
m_presenter.SetDisplayTexture(m_upload_texture.get(), GSVector4i::loadh(GSVector2i(width, height)));
if (is_24bit && g_gpu_settings.display_24bit_chroma_smoothing)
{
if (m_presenter.ApplyChromaSmoothing())
@@ -427,7 +427,7 @@ void GPU_SW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
{
if (CopyOut(src_x, src_y, skip_x, width, height, 0, is_24bit))
{
m_presenter.SetDisplayTexture(m_upload_texture.get(), 0, 0, width, height);
m_presenter.SetDisplayTexture(m_upload_texture.get(), GSVector4i::loadh(GSVector2i(width, height)));
if (is_24bit && g_gpu_settings.display_24bit_chroma_smoothing)
m_presenter.ApplyChromaSmoothing();
}
@@ -436,7 +436,7 @@ void GPU_SW::UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd)
else
{
if (CopyOut(0, 0, 0, VRAM_WIDTH, VRAM_HEIGHT, 0, false))
m_presenter.SetDisplayTexture(m_upload_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
m_presenter.SetDisplayTexture(m_upload_texture.get(), GSVector4i::cxpr(0, 0, VRAM_WIDTH, VRAM_HEIGHT));
}
}

View File

@@ -6067,27 +6067,25 @@ void System::RequestDisplaySize(float scale /*= 0.0f*/)
if (scale == 0.0f)
scale = GPUBackend::IsUsingHardwareBackend() ? static_cast<float>(g_settings.gpu_resolution_scale) : 1.0f;
float requested_width, requested_height;
GSVector2 requested_size;
if (g_settings.gpu_show_vram)
{
requested_width = static_cast<float>(VRAM_WIDTH) * scale;
requested_height = static_cast<float>(VRAM_HEIGHT) * scale;
requested_size = GSVector2::cxpr(static_cast<s32>(VRAM_WIDTH), static_cast<s32>(VRAM_HEIGHT)) * scale;
}
else
{
requested_width = static_cast<float>(g_gpu.GetCRTCDisplayWidth()) * scale;
requested_height = static_cast<float>(g_gpu.GetCRTCDisplayHeight()) * scale;
g_gpu.ApplyPixelAspectRatioToSize(g_gpu.ComputePixelAspectRatio(), &requested_width, &requested_height);
requested_size =
g_gpu.ApplyPixelAspectRatioToSize(g_gpu.ComputePixelAspectRatio(), GSVector2(g_gpu.GetCRTCVideoSize()) * scale);
}
if (g_settings.display_rotation == DisplayRotation::Rotate90 ||
g_settings.display_rotation == DisplayRotation::Rotate270)
{
std::swap(requested_width, requested_height);
requested_size = requested_size.yx();
}
Host::RequestResizeHostDisplay(static_cast<s32>(std::ceil(requested_width)),
static_cast<s32>(std::ceil(requested_height)));
const GSVector2i requested_sizei = GSVector2i(requested_size.ceil());
Host::RequestResizeHostDisplay(requested_sizei.x, requested_sizei.y);
}
void System::DisplayWindowResized()

View File

@@ -464,10 +464,11 @@ void Host::FrameDoneOnGPUThread(GPUBackend* gpu_backend, u32 frame_number)
// Need to take a copy of the display texture.
GPUTexture* const read_texture = presenter.GetDisplayTexture();
const u32 read_x = static_cast<u32>(presenter.GetDisplayTextureViewX());
const u32 read_y = static_cast<u32>(presenter.GetDisplayTextureViewY());
const u32 read_width = static_cast<u32>(presenter.GetDisplayTextureViewWidth());
const u32 read_height = static_cast<u32>(presenter.GetDisplayTextureViewHeight());
const GSVector4i read_rect = presenter.GetDisplayTextureRect();
const u32 read_x = static_cast<u32>(read_rect.x);
const u32 read_y = static_cast<u32>(read_rect.y);
const u32 read_width = static_cast<u32>(read_rect.width());
const u32 read_height = static_cast<u32>(read_rect.height());
const ImageFormat read_format = GPUTexture::GetImageFormatForTextureFormat(read_texture->GetFormat());
if (read_format == ImageFormat::None)
return;