// Copyright 2010 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include "Common/CommonTypes.h" #include "Common/EnumFormatter.h" #include "VideoCommon/AbstractFramebuffer.h" #include "VideoCommon/AbstractPipeline.h" #include "VideoCommon/AbstractStagingTexture.h" #include "VideoCommon/AbstractTexture.h" #include "VideoCommon/RenderState.h" #include "VideoCommon/TextureConfig.h" class NativeVertexFormat; class PointerWrap; enum class EFBReinterpretType { RGB8ToRGB565 = 0, RGB8ToRGBA6 = 1, RGBA6ToRGB8 = 2, RGBA6ToRGB565 = 3, RGB565ToRGB8 = 4, RGB565ToRGBA6 = 5 }; constexpr u32 NUM_EFB_REINTERPRET_TYPES = 6; template <> struct fmt::formatter : EnumFormatter { static constexpr array_type names = {"RGB8 to RGB565", "RGB8 to RGBA6", "RGBA6 to RGB8", "RGB6 to RGB565", "RGB565 to RGB8", "RGB565 to RGBA6"}; constexpr formatter() : EnumFormatter(names) {} }; inline bool AddressRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) { return !((aLower >= bUpper) || (bLower >= aUpper)); } class FramebufferManager final { public: FramebufferManager(); virtual ~FramebufferManager(); // Does not require the framebuffer to be created. Slower than direct queries. static AbstractTextureFormat GetEFBColorFormat(); static AbstractTextureFormat GetEFBDepthFormat(); static AbstractTextureFormat GetEFBDepthCopyFormat(); static TextureConfig GetEFBColorTextureConfig(); static TextureConfig GetEFBDepthTextureConfig(); // Accessors. AbstractTexture* GetEFBColorTexture() const { return m_efb_color_texture.get(); } AbstractTexture* GetEFBDepthTexture() const { return m_efb_depth_texture.get(); } AbstractFramebuffer* GetEFBFramebuffer() const { return m_efb_framebuffer.get(); } u32 GetEFBWidth() const { return m_efb_color_texture->GetWidth(); } u32 GetEFBHeight() const { return m_efb_color_texture->GetHeight(); } u32 GetEFBLayers() const { return m_efb_color_texture->GetLayers(); } u32 GetEFBSamples() const { return m_efb_color_texture->GetSamples(); } bool IsEFBMultisampled() const { return m_efb_color_texture->IsMultisampled(); } bool IsEFBStereo() const { return m_efb_color_texture->GetLayers() > 1; } FramebufferState GetEFBFramebufferState() const; // First-time setup. bool Initialize(); // Recreate EFB framebuffers, call when the EFB size (IR) changes. void RecreateEFBFramebuffer(); // Recompile shaders, use when MSAA mode changes. void RecompileShaders(); // This is virtual, because D3D has both normalized and integer framebuffers. void BindEFBFramebuffer(); // Resolve color/depth textures to a non-msaa texture, and return it. AbstractTexture* ResolveEFBColorTexture(const MathUtil::Rectangle& region); AbstractTexture* ResolveEFBDepthTexture(const MathUtil::Rectangle& region, bool force_r32f = false); // Reinterpret pixel format of EFB color texture. // Assumes no render pass is currently in progress. // Swaps EFB framebuffers, so re-bind afterwards. bool ReinterpretPixelData(EFBReinterpretType convtype); // Clears the EFB using shaders. void ClearEFB(const MathUtil::Rectangle& rc, bool clear_color, bool clear_alpha, bool clear_z, u32 color, u32 z); // Reads a framebuffer value back from the GPU. This may block if the cache is not current. u32 PeekEFBColor(u32 x, u32 y); float PeekEFBDepth(u32 x, u32 y); void SetEFBCacheTileSize(u32 size); void InvalidatePeekCache(bool forced = true); void FlagPeekCacheAsOutOfDate(); // Writes a value to the framebuffer. This will never block, and writes will be batched. void PokeEFBColor(u32 x, u32 y, u32 color); void PokeEFBDepth(u32 x, u32 y, float depth); void FlushEFBPokes(); // Save state load/save. void DoState(PointerWrap& p); protected: struct EFBPokeVertex { float position[4]; u32 color; }; static_assert(std::is_standard_layout::value, "EFBPokeVertex is standard-layout"); // EFB cache - for CPU EFB access // Tiles are ordered left-to-right, then top-to-bottom struct EFBCacheData { std::unique_ptr texture; std::unique_ptr framebuffer; std::unique_ptr readback_texture; std::unique_ptr copy_pipeline; std::vector tiles; bool out_of_date; bool valid; }; bool CreateEFBFramebuffer(); void DestroyEFBFramebuffer(); bool CompileConversionPipelines(); void DestroyConversionPipelines(); bool CompileReadbackPipelines(); void DestroyReadbackPipelines(); bool CreateReadbackFramebuffer(); void DestroyReadbackFramebuffer(); bool CompileClearPipelines(); void DestroyClearPipelines(); bool CompilePokePipelines(); void DestroyPokePipelines(); bool IsUsingTiledEFBCache() const; bool IsEFBCacheTilePresent(bool depth, u32 x, u32 y, u32* tile_index) const; MathUtil::Rectangle GetEFBCacheTileRect(u32 tile_index) const; void PopulateEFBCache(bool depth, u32 tile_index); void CreatePokeVertices(std::vector* destination_list, u32 x, u32 y, float z, u32 color); void DrawPokeVertices(const EFBPokeVertex* vertices, u32 vertex_count, const AbstractPipeline* pipeline); void DoLoadState(PointerWrap& p); void DoSaveState(PointerWrap& p); std::unique_ptr m_efb_color_texture; std::unique_ptr m_efb_convert_color_texture; std::unique_ptr m_efb_depth_texture; std::unique_ptr m_efb_resolve_color_texture; std::unique_ptr m_efb_depth_resolve_texture; std::unique_ptr m_efb_framebuffer; std::unique_ptr m_efb_convert_framebuffer; std::unique_ptr m_efb_depth_resolve_framebuffer; std::unique_ptr m_efb_depth_resolve_pipeline; // Pipeline for restoring the contents of the EFB from a save state std::unique_ptr m_efb_restore_pipeline; // Format conversion shaders std::array, 6> m_format_conversion_pipelines; // EFB cache - for CPU EFB access u32 m_efb_cache_tile_size = 0; u32 m_efb_cache_tiles_wide = 0; EFBCacheData m_efb_color_cache = {}; EFBCacheData m_efb_depth_cache = {}; // EFB clear pipelines // Indexed by [color_write_enabled][alpha_write_enabled][depth_write_enabled] std::array, 2>, 2>, 2> m_efb_clear_pipelines; // EFB poke drawing setup std::unique_ptr m_poke_vertex_format; std::unique_ptr m_color_poke_pipeline; std::unique_ptr m_depth_poke_pipeline; std::vector m_color_poke_vertices; std::vector m_depth_poke_vertices; }; extern std::unique_ptr g_framebuffer_manager;