mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 12:05:52 +00:00
194 lines
6.6 KiB
C++
194 lines
6.6 KiB
C++
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
|
|
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
|
|
|
#pragma once
|
|
|
|
#include "util/gpu_device.h"
|
|
|
|
#include "gpu_thread_commands.h"
|
|
|
|
#include <memory>
|
|
|
|
class Error;
|
|
class SmallStringBase;
|
|
|
|
class GPUFramebuffer;
|
|
class GPUPipeline;
|
|
|
|
struct GPUSettings;
|
|
class StateWrapper;
|
|
|
|
class GPUPresenter;
|
|
|
|
namespace System {
|
|
struct MemorySaveState;
|
|
}
|
|
|
|
// DESIGN NOTE: Only static methods should be called on the CPU thread.
|
|
// You specifically don't have a global pointer available for this reason.
|
|
|
|
class ALIGN_TO_CACHE_LINE GPUBackend
|
|
{
|
|
public:
|
|
static GPUThreadCommand* NewClearVRAMCommand();
|
|
static GPUThreadCommand* NewClearDisplayCommand();
|
|
static GPUBackendUpdateDisplayCommand* NewUpdateDisplayCommand();
|
|
static GPUBackendSubmitFrameCommand* NewSubmitFrameCommand();
|
|
static GPUThreadCommand* NewClearCacheCommand();
|
|
static GPUThreadCommand* NewBufferSwappedCommand();
|
|
static GPUBackendReadVRAMCommand* NewReadVRAMCommand();
|
|
static GPUBackendFillVRAMCommand* NewFillVRAMCommand();
|
|
static GPUBackendUpdateVRAMCommand* NewUpdateVRAMCommand(u32 num_words);
|
|
static GPUBackendCopyVRAMCommand* NewCopyVRAMCommand();
|
|
static GPUBackendSetDrawingAreaCommand* NewSetDrawingAreaCommand();
|
|
static GPUBackendUpdateCLUTCommand* NewUpdateCLUTCommand();
|
|
static GPUBackendDrawPolygonCommand* NewDrawPolygonCommand(u32 num_vertices);
|
|
static GPUBackendDrawPrecisePolygonCommand* NewDrawPrecisePolygonCommand(u32 num_vertices);
|
|
static GPUBackendDrawRectangleCommand* NewDrawRectangleCommand();
|
|
static GPUBackendDrawLineCommand* NewDrawLineCommand(u32 num_vertices);
|
|
static GPUBackendDrawPreciseLineCommand* NewDrawPreciseLineCommand(u32 num_vertices);
|
|
static void PushCommand(GPUThreadCommand* cmd);
|
|
static void PushCommandAndWakeThread(GPUThreadCommand* cmd);
|
|
static void PushCommandAndSync(GPUThreadCommand* cmd, bool spin);
|
|
static void SyncGPUThread(bool spin);
|
|
|
|
static bool IsUsingHardwareBackend();
|
|
|
|
static std::unique_ptr<GPUBackend> CreateHardwareBackend(GPUPresenter& presenter);
|
|
static std::unique_ptr<GPUBackend> CreateSoftwareBackend(GPUPresenter& presenter);
|
|
static std::unique_ptr<GPUBackend> CreateNullBackend(GPUPresenter& presenter);
|
|
|
|
static bool RenderScreenshotToBuffer(u32 width, u32 height, bool postfx, bool apply_aspect_ratio, Image* out_image,
|
|
Error* error);
|
|
static void RenderScreenshotToFile(const std::string_view path, DisplayScreenshotMode mode, u8 quality,
|
|
bool show_osd_message);
|
|
|
|
static bool BeginQueueFrame();
|
|
static void WaitForOneQueuedFrame();
|
|
static u32 GetQueuedFrameCount();
|
|
|
|
static bool AllocateMemorySaveStates(std::span<System::MemorySaveState> states, Error* error);
|
|
|
|
public:
|
|
GPUBackend(GPUPresenter& presenter);
|
|
virtual ~GPUBackend();
|
|
|
|
ALWAYS_INLINE const GPUPresenter& GetPresenter() const { return m_presenter; }
|
|
ALWAYS_INLINE GPUPresenter& GetPresenter() { return m_presenter; }
|
|
|
|
virtual bool Initialize(bool upload_vram, Error* error);
|
|
|
|
virtual bool UpdateSettings(const GPUSettings& old_settings, Error* error);
|
|
virtual void UpdatePostProcessingSettings(bool force_reload);
|
|
|
|
/// Returns the current resolution scale.
|
|
virtual u32 GetResolutionScale() const = 0;
|
|
|
|
// Graphics API state reset/restore - call when drawing the UI etc.
|
|
// TODO: replace with "invalidate cached state"
|
|
virtual void RestoreDeviceContext() = 0;
|
|
|
|
/// Ensures all pending draws are flushed to the host GPU.
|
|
virtual void FlushRender() = 0;
|
|
|
|
/// Main command handler for GPU thread.
|
|
void HandleCommand(const GPUThreadCommand* cmd);
|
|
|
|
void GetStatsString(SmallStringBase& str) const;
|
|
void GetMemoryStatsString(SmallStringBase& str) const;
|
|
|
|
void ResetStatistics();
|
|
void UpdateStatistics(u32 frame_count);
|
|
|
|
/// Screen-aligned vertex type for various draw types.
|
|
struct ScreenVertex
|
|
{
|
|
float x;
|
|
float y;
|
|
float u;
|
|
float v;
|
|
|
|
ALWAYS_INLINE void Set(const GSVector2& xy, const GSVector2& uv)
|
|
{
|
|
GSVector4::store<false>(this, GSVector4::xyxy(xy, uv));
|
|
}
|
|
};
|
|
|
|
static void SetScreenQuadInputLayout(GPUPipeline::GraphicsConfig& config);
|
|
static GSVector4 GetScreenQuadClipSpaceCoordinates(const GSVector4i bounds, const GSVector2i rt_size);
|
|
|
|
static void DrawScreenQuad(const GSVector4i bounds, const GSVector2i rt_size,
|
|
const GSVector4 uv_bounds = GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f));
|
|
|
|
protected:
|
|
enum : u32
|
|
{
|
|
DEINTERLACE_BUFFER_COUNT = 4,
|
|
};
|
|
|
|
struct Counters
|
|
{
|
|
u32 num_reads;
|
|
u32 num_writes;
|
|
u32 num_copies;
|
|
u32 num_vertices;
|
|
u32 num_primitives;
|
|
u32 num_depth_buffer_clears;
|
|
};
|
|
|
|
struct Stats : Counters
|
|
{
|
|
size_t host_buffer_streamed;
|
|
u32 host_num_draws;
|
|
u32 host_num_barriers;
|
|
u32 host_num_render_passes;
|
|
u32 host_num_copies;
|
|
u32 host_num_downloads;
|
|
u32 host_num_uploads;
|
|
};
|
|
|
|
virtual void ReadVRAM(u32 x, u32 y, u32 width, u32 height) = 0;
|
|
virtual void FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color, bool interlaced_rendering,
|
|
u8 interlaced_display_field) = 0;
|
|
virtual void UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask) = 0;
|
|
virtual void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height, bool set_mask,
|
|
bool check_mask) = 0;
|
|
|
|
virtual void DrawPolygon(const GPUBackendDrawPolygonCommand* cmd) = 0;
|
|
virtual void DrawPrecisePolygon(const GPUBackendDrawPrecisePolygonCommand* cmd) = 0;
|
|
virtual void DrawSprite(const GPUBackendDrawRectangleCommand* cmd) = 0;
|
|
virtual void DrawLine(const GPUBackendDrawLineCommand* cmd) = 0;
|
|
virtual void DrawPreciseLine(const GPUBackendDrawPreciseLineCommand* cmd) = 0;
|
|
|
|
virtual void DrawingAreaChanged() = 0;
|
|
virtual void ClearCache() = 0;
|
|
virtual void OnBufferSwapped() = 0;
|
|
virtual void ClearVRAM() = 0;
|
|
|
|
virtual void UpdateDisplay(const GPUBackendUpdateDisplayCommand* cmd) = 0;
|
|
|
|
virtual void LoadState(const GPUBackendLoadStateCommand* cmd) = 0;
|
|
|
|
virtual bool AllocateMemorySaveState(System::MemorySaveState& mss, Error* error) = 0;
|
|
virtual void DoMemoryState(StateWrapper& sw, System::MemorySaveState& mss) = 0;
|
|
|
|
void HandleUpdateDisplayCommand(const GPUBackendUpdateDisplayCommand* cmd);
|
|
void HandleSubmitFrameCommand(const GPUBackendFramePresentationParameters* cmd);
|
|
|
|
GPUPresenter& m_presenter;
|
|
GSVector4i m_clamped_drawing_area = {};
|
|
|
|
static Counters s_counters;
|
|
static Stats s_stats;
|
|
|
|
private:
|
|
static void ReleaseQueuedFrame();
|
|
};
|
|
|
|
namespace Host {
|
|
|
|
/// Called at the end of the frame, before presentation.
|
|
void FrameDoneOnGPUThread(GPUBackend* gpu_backend, u32 frame_number);
|
|
|
|
} // namespace Host
|