From 97582bcfec65e8af5366d374b5686bb3fde07522 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 13 Dec 2025 17:16:53 +1000 Subject: [PATCH] GPU: Use vectors/rects for presentation --- src/core/gpu.cpp | 139 ++++++++++----- src/core/gpu.h | 23 +-- src/core/gpu_backend.cpp | 23 ++- src/core/gpu_hw.cpp | 53 +++--- src/core/gpu_hw.h | 4 +- src/core/gpu_presenter.cpp | 205 +++++++++-------------- src/core/gpu_presenter.h | 44 ++--- src/core/gpu_sw.cpp | 6 +- src/core/system.cpp | 16 +- src/duckstation-regtest/regtest_host.cpp | 9 +- 10 files changed, 266 insertions(+), 256 deletions(-) diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 34823c3ae..9ae5d9555 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -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(&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(window_width); - const float fwindow_height = static_cast(window_height); - float display_width = static_cast(crtc_display_width); - float display_height = static_cast(crtc_display_height); - float active_left = static_cast(display_origin_left); - float active_top = static_cast(display_origin_top); - float active_width = static_cast(display_vram_width); - float active_height = static_cast(display_vram_height); + const float fwindow_width = static_cast(window_size.x); + const float fwindow_height = static_cast(window_size.y); + float display_width = static_cast(video_size.x); + float display_height = static_cast(video_size.y); + float active_left = static_cast(video_active_rect.x); + float active_top = static_cast(video_active_rect.y); + float active_width = static_cast(video_active_rect.width()); + float active_height = static_cast(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(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(active_top * scale + top_padding); const s32 right = left + static_cast(active_width * scale); const s32 bottom = top + static_cast(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. diff --git a/src/core/gpu.h b/src/core/gpu.h index 2d41f32d9..ada6a71e1 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -12,6 +12,7 @@ #include "common/bitfield.h" #include "common/fifo_queue.h" +#include "common/gsvector.h" #include "common/types.h" #include @@ -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). diff --git a/src/core/gpu_backend.cpp b/src/core/gpu_backend.cpp index d9ddb17e3..fb7ccf43f 100644 --- a/src/core/gpu_backend.cpp +++ b/src/core/gpu_backend.cpp @@ -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(width), static_cast(height), apply_aspect_ratio, - false, false, &display_rect, &draw_rect); + GSVector4i source_rect, draw_rect, display_rect; + backend->GetPresenter().CalculateDrawRect(GSVector2i(static_cast(width), static_cast(height)), + apply_aspect_ratio, false, false, &source_rect, &display_rect, + &draw_rect); image_width = static_cast(display_rect.width()); image_height = static_cast(display_rect.height()); } diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 2370ead8b..9fea6fbcf 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -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(source_rect.x); + const u32 top = static_cast(source_rect.y); + const u32 width = static_cast(source_rect.width()); + const u32 height = static_cast(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(source_rect.x); + const u32 top = static_cast(source_rect.y); + const u32 width = static_cast(source_rect.width()); + const u32 height = static_cast(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() diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 4a9f11f05..69a69e407 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -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(); diff --git a/src/core/gpu_presenter.cpp b/src/core/gpu_presenter.cpp index a72570d60..61bb54b26 100644 --- a/src/core/gpu_presenter.cpp +++ b/src/core/gpu_presenter.cpp @@ -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(&uniforms.params[0], region_range); + GSVector2::store(&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(display_rect.width()) / static_cast(m_display_texture_view_width)), 1.0f); - uniforms.params[1] = std::max( - std::floor(static_cast(display_rect.height()) / static_cast(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( - uniforms.clamp_rect, - GSVector4(static_cast(m_display_texture_view_x) + 0.5f, static_cast(m_display_texture_view_y) + 0.5f, - static_cast(m_display_texture_view_x + m_display_texture_view_width) - 0.5f, - static_cast(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(uniforms.clamp_rect, + (fsource_rect + GSVector4::cxpr(0.5f, 0.5f, -0.5f, -0.5f)) / display_texture_size4); GSVector4::store(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(m_display_texture_view_width) || - m_display_texture->GetHeight() != static_cast(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(m_display_texture_rect.x), + static_cast(m_display_texture_rect.y), 0, 0, static_cast(m_display_texture_rect.width()), + static_cast(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(m_display_texture_view_width) / static_cast(m_display_vram_width); - const float upscale_y = static_cast(m_display_texture_view_height) / static_cast(m_display_vram_height); - const s32 orig_width = static_cast(std::ceil(static_cast(m_display_width) * upscale_x)); - const s32 orig_height = static_cast(std::ceil(static_cast(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(m_display_texture_rect.x); + const u32 y = static_cast(m_display_texture_rect.y); + const u32 width = static_cast(m_display_texture_rect.width()); + const u32 height = static_cast(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(m_display_texture_rect.x); + const u32 y = static_cast(m_display_texture_rect.y); + const u32 width = static_cast(m_display_texture_rect.width()); + const u32 height = static_cast(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(m_display_texture_view_width) / static_cast(m_display_vram_width)); - float f_height = m_display_height * - (static_cast(m_display_texture_view_height) / static_cast(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(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(std::ceil(f_width)), static_cast(std::ceil(f_height))); + return GSVector2i(f_size.ceil()); } } diff --git a/src/core/gpu_presenter.h b/src/core/gpu_presenter.h index eef49b71b..e14945d5b 100644 --- a/src/core/gpu_presenter.h +++ b/src/core/gpu_presenter.h @@ -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(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 m_display_pipeline; std::unique_ptr 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; diff --git a/src/core/gpu_sw.cpp b/src/core/gpu_sw.cpp index 68bff3071..ac5420dbb 100644 --- a/src/core/gpu_sw.cpp +++ b/src/core/gpu_sw.cpp @@ -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)); } } diff --git a/src/core/system.cpp b/src/core/system.cpp index f4d4bb37b..284bdc38a 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -6067,27 +6067,25 @@ void System::RequestDisplaySize(float scale /*= 0.0f*/) if (scale == 0.0f) scale = GPUBackend::IsUsingHardwareBackend() ? static_cast(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(VRAM_WIDTH) * scale; - requested_height = static_cast(VRAM_HEIGHT) * scale; + requested_size = GSVector2::cxpr(static_cast(VRAM_WIDTH), static_cast(VRAM_HEIGHT)) * scale; } else { - requested_width = static_cast(g_gpu.GetCRTCDisplayWidth()) * scale; - requested_height = static_cast(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(std::ceil(requested_width)), - static_cast(std::ceil(requested_height))); + const GSVector2i requested_sizei = GSVector2i(requested_size.ceil()); + Host::RequestResizeHostDisplay(requested_sizei.x, requested_sizei.y); } void System::DisplayWindowResized() diff --git a/src/duckstation-regtest/regtest_host.cpp b/src/duckstation-regtest/regtest_host.cpp index b1576a17b..36ce53062 100644 --- a/src/duckstation-regtest/regtest_host.cpp +++ b/src/duckstation-regtest/regtest_host.cpp @@ -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(presenter.GetDisplayTextureViewX()); - const u32 read_y = static_cast(presenter.GetDisplayTextureViewY()); - const u32 read_width = static_cast(presenter.GetDisplayTextureViewWidth()); - const u32 read_height = static_cast(presenter.GetDisplayTextureViewHeight()); + const GSVector4i read_rect = presenter.GetDisplayTextureRect(); + const u32 read_x = static_cast(read_rect.x); + const u32 read_y = static_cast(read_rect.y); + const u32 read_width = static_cast(read_rect.width()); + const u32 read_height = static_cast(read_rect.height()); const ImageFormat read_format = GPUTexture::GetImageFormatForTextureFormat(read_texture->GetFormat()); if (read_format == ImageFormat::None) return;