mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-06 19:45:33 +00:00

Means that the renderer can be changed without reloading shaders, and speeds up config change detection.
179 lines
7.0 KiB
C++
179 lines
7.0 KiB
C++
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
|
|
|
#pragma once
|
|
|
|
#include "types.h"
|
|
|
|
#include "util/gpu_device.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class Error;
|
|
class Image;
|
|
class MediaCapture;
|
|
class SettingsInterface;
|
|
|
|
enum class DisplayScreenshotMode : u8;
|
|
|
|
class GPUBackend;
|
|
|
|
struct GPUSettings;
|
|
struct GPUBackendUpdateDisplayCommand;
|
|
struct GPUBackendFramePresentationParameters;
|
|
|
|
namespace PostProcessing {
|
|
class Chain;
|
|
}
|
|
|
|
class ALIGN_TO_CACHE_LINE GPUPresenter final
|
|
{
|
|
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 GPUTexture* GetDisplayTexture() const { return m_display_texture; }
|
|
ALWAYS_INLINE bool HasDisplayTexture() const { return m_display_texture; }
|
|
|
|
bool Initialize(Error* error);
|
|
|
|
bool UpdateSettings(const GPUSettings& old_settings, Error* error);
|
|
|
|
bool IsDisplayPostProcessingActive() const;
|
|
bool UpdatePostProcessingSettings(bool force_reload, Error* error);
|
|
|
|
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);
|
|
void SetDisplayTexture(GPUTexture* texture, s32 view_x, s32 view_y, s32 view_width, s32 view_height);
|
|
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_rotation, bool apply_aspect_ratio,
|
|
GSVector4i* display_rect, GSVector4i* draw_rect) const;
|
|
|
|
/// Helper function for computing screenshot bounds.
|
|
void CalculateScreenshotSize(DisplayScreenshotMode mode, u32* width, u32* height, GSVector4i* display_rect,
|
|
GSVector4i* draw_rect) const;
|
|
|
|
/// Renders the display, optionally with postprocessing to the specified image.
|
|
bool RenderScreenshotToBuffer(u32 width, u32 height, const GSVector4i display_rect, const GSVector4i draw_rect,
|
|
bool postfx, Image* out_image);
|
|
|
|
/// Sends the current frame to media capture.
|
|
void SendDisplayToMediaCapture(MediaCapture* cap);
|
|
|
|
/// Main frame presenter - used both when a game is and is not running.
|
|
static bool PresentFrame(GPUPresenter* presenter, GPUBackend* backend, bool allow_skip_present, u64 present_time);
|
|
|
|
/// Returns a list of border overlay presets.
|
|
static std::vector<std::string> EnumerateBorderOverlayPresets();
|
|
|
|
/// Returns the settings interface to use for loading post-processing shader configuration.
|
|
/// Assumes the settings lock is being held.
|
|
static SettingsInterface& GetPostProcessingSettingsInterface(const char* section);
|
|
|
|
/// Toggles post-processing. Only callable from the CPU thread.
|
|
static void TogglePostProcessing();
|
|
|
|
/// Reloads post-processing settings. Only callable from the CPU thread.
|
|
static void ReloadPostProcessingSettings(bool display, bool internal, bool reload_shaders);
|
|
|
|
private:
|
|
enum : u32
|
|
{
|
|
DEINTERLACE_BUFFER_COUNT = 4,
|
|
MAX_SKIPPED_PRESENT_COUNT = 50,
|
|
};
|
|
|
|
static void SleepUntilPresentTime(u64 present_time);
|
|
|
|
/// Draws the current display texture, with any post-processing.
|
|
GPUDevice::PresentResult PresentDisplay();
|
|
|
|
bool CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_smoothing, Error* error);
|
|
|
|
GPUDevice::PresentResult RenderDisplay(GPUTexture* target, const GSVector4i overlay_rect,
|
|
const GSVector4i display_rect, const GSVector4i draw_rect, bool postfx);
|
|
|
|
void DrawDisplay(const GSVector2i target_size, const GSVector4i display_rect, bool dst_alpha_blend,
|
|
DisplayRotation rotation, WindowInfo::PreRotation prerotation);
|
|
GPUDevice::PresentResult ApplyDisplayPostProcess(GPUTexture* target, GPUTexture* input,
|
|
const GSVector4i display_rect);
|
|
void DrawTextureCopy(const GSVector2i target_size, const GSVector4i draw_rect, GPUTexture* input,
|
|
bool dst_alpha_blend, bool linear, WindowInfo::PreRotation prerotation);
|
|
void DrawScreenQuad(const GSVector4i rect, const GSVector4 uv_rect, const GSVector2i target_size,
|
|
DisplayRotation uv_rotation, WindowInfo::PreRotation prerotation);
|
|
|
|
bool DeinterlaceSetTargetSize(u32 width, u32 height, bool preserve);
|
|
void DestroyDeinterlaceTextures();
|
|
|
|
void LoadPostProcessingSettings(bool force_load);
|
|
|
|
/// Returns true if the image path or alpha blend option has changed.
|
|
bool LoadOverlaySettings();
|
|
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;
|
|
float m_display_pixel_aspect_ratio = 1.0f;
|
|
|
|
u32 m_current_deinterlace_buffer = 0;
|
|
std::unique_ptr<GPUPipeline> m_deinterlace_pipeline;
|
|
std::array<std::unique_ptr<GPUTexture>, DEINTERLACE_BUFFER_COUNT> m_deinterlace_buffers;
|
|
std::unique_ptr<GPUTexture> m_deinterlace_texture;
|
|
|
|
std::unique_ptr<GPUPipeline> m_chroma_smoothing_pipeline;
|
|
std::unique_ptr<GPUTexture> m_chroma_smoothing_texture;
|
|
|
|
std::unique_ptr<GPUPipeline> m_display_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;
|
|
|
|
u32 m_skipped_present_count = 0;
|
|
GPUTexture::Format m_present_format = GPUTexture::Format::Unknown;
|
|
bool m_border_overlay_alpha_blend = false;
|
|
|
|
std::unique_ptr<GPUPipeline> m_present_copy_pipeline;
|
|
|
|
std::unique_ptr<PostProcessing::Chain> m_display_postfx;
|
|
|
|
// blended variants of pipelines, used when overlays are enabled
|
|
std::unique_ptr<GPUPipeline> m_display_blend_pipeline;
|
|
std::unique_ptr<GPUPipeline> m_present_copy_blend_pipeline;
|
|
|
|
std::unique_ptr<GPUTexture> m_border_overlay_texture;
|
|
GSVector4i m_border_overlay_display_rect = GSVector4i::zero();
|
|
|
|
// Low-traffic variables down here.
|
|
std::string m_border_overlay_image_path;
|
|
};
|
|
|
|
namespace Host {
|
|
|
|
/// Called at the end of the frame, before presentation.
|
|
void FrameDoneOnGPUThread(GPUPresenter* gpu_presenter, u32 frame_number);
|
|
|
|
} // namespace Host
|