1 // Copyright 2010 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 // --------------------------------------------------------------------------------------------- 6 // GC graphics pipeline 7 // --------------------------------------------------------------------------------------------- 8 // 3d commands are issued through the fifo. The GPU draws to the 2MB EFB. 9 // The efb can be copied back into ram in two forms: as textures or as XFB. 10 // The XFB is the region in RAM that the VI chip scans out to the television. 11 // So, after all rendering to EFB is done, the image is copied into one of two XFBs in RAM. 12 // Next frame, that one is scanned out and the other one gets the copy. = double buffering. 13 // --------------------------------------------------------------------------------------------- 14 15 #pragma once 16 17 #include <array> 18 #include <memory> 19 #include <mutex> 20 #include <string> 21 #include <string_view> 22 #include <thread> 23 #include <tuple> 24 #include <vector> 25 26 #include "Common/CommonTypes.h" 27 #include "Common/Event.h" 28 #include "Common/Flag.h" 29 #include "Common/MathUtil.h" 30 #include "VideoCommon/AsyncShaderCompiler.h" 31 #include "VideoCommon/BPMemory.h" 32 #include "VideoCommon/FPSCounter.h" 33 #include "VideoCommon/FrameDump.h" 34 #include "VideoCommon/RenderState.h" 35 #include "VideoCommon/TextureConfig.h" 36 37 class AbstractFramebuffer; 38 class AbstractPipeline; 39 class AbstractShader; 40 class AbstractTexture; 41 class AbstractStagingTexture; 42 class NativeVertexFormat; 43 class NetPlayChatUI; 44 class PointerWrap; 45 struct TextureConfig; 46 struct ComputePipelineConfig; 47 struct AbstractPipelineConfig; 48 struct PortableVertexDeclaration; 49 enum class ShaderStage; 50 enum class EFBAccessType; 51 enum class EFBReinterpretType; 52 enum class StagingTextureType; 53 enum class AspectMode; 54 55 namespace VideoCommon 56 { 57 class PostProcessing; 58 } // namespace VideoCommon 59 60 struct EfbPokeData 61 { 62 u16 x, y; 63 u32 data; 64 }; 65 66 // Renderer really isn't a very good name for this class - it's more like "Misc". 67 // The long term goal is to get rid of this class and replace it with others that make 68 // more sense. 69 class Renderer 70 { 71 public: 72 Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale, 73 AbstractTextureFormat backbuffer_format); 74 virtual ~Renderer(); 75 76 using ClearColor = std::array<float, 4>; 77 78 virtual bool IsHeadless() const = 0; 79 80 virtual bool Initialize(); 81 virtual void Shutdown(); 82 SetPipeline(const AbstractPipeline * pipeline)83 virtual void SetPipeline(const AbstractPipeline* pipeline) {} SetScissorRect(const MathUtil::Rectangle<int> & rc)84 virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {} SetTexture(u32 index,const AbstractTexture * texture)85 virtual void SetTexture(u32 index, const AbstractTexture* texture) {} SetSamplerState(u32 index,const SamplerState & state)86 virtual void SetSamplerState(u32 index, const SamplerState& state) {} SetComputeImageTexture(AbstractTexture * texture,bool read,bool write)87 virtual void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) {} UnbindTexture(const AbstractTexture * texture)88 virtual void UnbindTexture(const AbstractTexture* texture) {} SetViewport(float x,float y,float width,float height,float near_depth,float far_depth)89 virtual void SetViewport(float x, float y, float width, float height, float near_depth, 90 float far_depth) 91 { 92 } SetFullscreen(bool enable_fullscreen)93 virtual void SetFullscreen(bool enable_fullscreen) {} IsFullscreen()94 virtual bool IsFullscreen() const { return false; } 95 virtual void BeginUtilityDrawing(); 96 virtual void EndUtilityDrawing(); 97 virtual std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) = 0; 98 virtual std::unique_ptr<AbstractStagingTexture> 99 CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0; 100 virtual std::unique_ptr<AbstractFramebuffer> 101 CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0; 102 103 // Framebuffer operations. 104 virtual void SetFramebuffer(AbstractFramebuffer* framebuffer); 105 virtual void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer); 106 virtual void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, 107 const ClearColor& color_value = {}, float depth_value = 0.0f); 108 109 // Drawing with currently-bound pipeline state. Draw(u32 base_vertex,u32 num_vertices)110 virtual void Draw(u32 base_vertex, u32 num_vertices) {} DrawIndexed(u32 base_index,u32 num_indices,u32 base_vertex)111 virtual void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) {} 112 113 // Dispatching compute shaders with currently-bound state. DispatchComputeShader(const AbstractShader * shader,u32 groups_x,u32 groups_y,u32 groups_z)114 virtual void DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y, 115 u32 groups_z) 116 { 117 } 118 119 // Binds the backbuffer for rendering. The buffer will be cleared immediately after binding. 120 // This is where any window size changes are detected, therefore m_backbuffer_width and/or 121 // m_backbuffer_height may change after this function returns. 122 virtual void BindBackbuffer(const ClearColor& clear_color = {}) {} 123 124 // Presents the backbuffer to the window system, or "swaps buffers". PresentBackbuffer()125 virtual void PresentBackbuffer() {} 126 127 // Shader modules/objects. 128 virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, 129 std::string_view source) = 0; 130 virtual std::unique_ptr<AbstractShader> 131 CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) = 0; 132 virtual std::unique_ptr<NativeVertexFormat> 133 CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0; 134 virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config, 135 const void* cache_data = nullptr, 136 size_t cache_data_length = 0) = 0; 137 GetCurrentFramebuffer()138 AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; } 139 140 // Ideal internal resolution - multiple of the native EFB resolution GetTargetWidth()141 int GetTargetWidth() const { return m_target_width; } GetTargetHeight()142 int GetTargetHeight() const { return m_target_height; } 143 // Display resolution GetBackbufferWidth()144 int GetBackbufferWidth() const { return m_backbuffer_width; } GetBackbufferHeight()145 int GetBackbufferHeight() const { return m_backbuffer_height; } GetBackbufferScale()146 float GetBackbufferScale() const { return m_backbuffer_scale; } 147 void SetWindowSize(int width, int height); 148 149 // Sets viewport and scissor to the specified rectangle. rect is assumed to be in framebuffer 150 // coordinates, i.e. lower-left origin in OpenGL. 151 void SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth = 0.0f, 152 float max_depth = 1.0f); 153 154 // Scales a GPU texture using a copy shader. 155 virtual void ScaleTexture(AbstractFramebuffer* dst_framebuffer, 156 const MathUtil::Rectangle<int>& dst_rect, 157 const AbstractTexture* src_texture, 158 const MathUtil::Rectangle<int>& src_rect); 159 160 // Converts an upper-left to lower-left if required by the backend, optionally 161 // clamping to the framebuffer size. 162 MathUtil::Rectangle<int> ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect, 163 u32 fb_width, u32 fb_height) const; 164 MathUtil::Rectangle<int> 165 ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect, 166 const AbstractFramebuffer* framebuffer) const; 167 168 // EFB coordinate conversion functions 169 // Use this to convert a whole native EFB rect to backbuffer coordinates 170 MathUtil::Rectangle<int> ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const; 171 GetTargetRectangle()172 const MathUtil::Rectangle<int>& GetTargetRectangle() const { return m_target_rectangle; } 173 float CalculateDrawAspectRatio() const; 174 175 // Crops the target rectangle to the framebuffer dimensions, reducing the size of the source 176 // rectangle if it is greater. Works even if the source and target rectangles don't have a 177 // 1:1 pixel mapping, scaling as appropriate. 178 void AdjustRectanglesToFitBounds(MathUtil::Rectangle<int>* target_rect, 179 MathUtil::Rectangle<int>* source_rect, int fb_width, 180 int fb_height); 181 182 std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height) const; 183 void UpdateDrawRectangle(); 184 185 std::tuple<float, float> ApplyStandardAspectCrop(float width, float height) const; 186 187 // Use this to convert a single target rectangle to two stereo rectangles 188 std::tuple<MathUtil::Rectangle<int>, MathUtil::Rectangle<int>> 189 ConvertStereoRectangle(const MathUtil::Rectangle<int>& rc) const; 190 191 unsigned int GetEFBScale() const; 192 193 // Use this to upscale native EFB coordinates to IDEAL internal resolution 194 int EFBToScaledX(int x) const; 195 int EFBToScaledY(int y) const; 196 197 // Floating point versions of the above - only use them if really necessary 198 float EFBToScaledXf(float x) const; 199 float EFBToScaledYf(float y) const; 200 201 // Random utilities 202 void SaveScreenshot(std::string filename); 203 void DrawDebugText(); 204 205 virtual void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable, 206 bool zEnable, u32 color, u32 z); 207 virtual void ReinterpretPixelData(EFBReinterpretType convtype); 208 void RenderToXFB(u32 xfbAddr, const MathUtil::Rectangle<int>& sourceRc, u32 fbStride, 209 u32 fbHeight, float Gamma = 1.0f); 210 211 virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data); 212 virtual void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points); 213 214 virtual u16 BBoxRead(int index) = 0; 215 virtual void BBoxWrite(int index, u16 value) = 0; BBoxFlush()216 virtual void BBoxFlush() {} 217 Flush()218 virtual void Flush() {} WaitForGPUIdle()219 virtual void WaitForGPUIdle() {} 220 221 // Finish up the current frame, print some stats 222 void Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks); 223 224 void UpdateWidescreenHeuristic(); 225 226 // Draws the specified XFB buffer to the screen, performing any post-processing. 227 // Assumes that the backbuffer has already been bound and cleared. 228 virtual void RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc, 229 const AbstractTexture* source_texture, 230 const MathUtil::Rectangle<int>& source_rc); 231 232 // Called when the configuration changes, and backend structures need to be updated. OnConfigChanged(u32 bits)233 virtual void OnConfigChanged(u32 bits) {} 234 GetPrevPixelFormat()235 PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } StorePixelFormat(PEControl::PixelFormat new_format)236 void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; } 237 bool EFBHasAlphaChannel() const; GetPostProcessor()238 VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); } 239 // Final surface changing 240 // This is called when the surface is resized (WX) or the window changes (Android). 241 void ChangeSurface(void* new_surface_handle); 242 void ResizeSurface(); 243 bool UseVertexDepthRange() const; 244 void DoState(PointerWrap& p); 245 246 virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler(); 247 248 // Returns true if a layer-expanding geometry shader should be used when rendering the user 249 // interface and final XFB. 250 bool UseGeometryShaderForUI() const; 251 252 // Returns a lock for the ImGui mutex, enabling data structures to be modified from outside. 253 // Use with care, only non-drawing functions should be called from outside the video thread, 254 // as the drawing is tied to a "frame". 255 std::unique_lock<std::mutex> GetImGuiLock(); 256 257 // Begins/presents a "UI frame". UI frames do not draw any of the console XFB, but this could 258 // change in the future. 259 void BeginUIFrame(); 260 void EndUIFrame(); 261 262 protected: 263 // Bitmask containing information about which configuration has changed for the backend. 264 enum ConfigChangeBits : u32 265 { 266 CONFIG_CHANGE_BIT_HOST_CONFIG = (1 << 0), 267 CONFIG_CHANGE_BIT_MULTISAMPLES = (1 << 1), 268 CONFIG_CHANGE_BIT_STEREO_MODE = (1 << 2), 269 CONFIG_CHANGE_BIT_TARGET_SIZE = (1 << 3), 270 CONFIG_CHANGE_BIT_ANISOTROPY = (1 << 4), 271 CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING = (1 << 5), 272 CONFIG_CHANGE_BIT_VSYNC = (1 << 6), 273 CONFIG_CHANGE_BIT_BBOX = (1 << 7) 274 }; 275 276 std::tuple<int, int> CalculateTargetScale(int x, int y) const; 277 bool CalculateTargetSize(); 278 279 void CheckForConfigChanges(); 280 281 void CheckFifoRecording(); 282 void RecordVideoMemory(); 283 284 // ImGui initialization depends on being able to create textures and pipelines, so do it last. 285 bool InitializeImGui(); 286 287 // Recompiles ImGui pipeline - call when stereo mode changes. 288 bool RecompileImGuiPipeline(); 289 290 // Sets up ImGui state for the next frame. 291 // This function itself acquires the ImGui lock, so it should not be held. 292 void BeginImGuiFrame(); 293 294 // Destroys all ImGui GPU resources, must do before shutdown. 295 void ShutdownImGui(); 296 297 // Renders ImGui windows to the currently-bound framebuffer. 298 // Should be called with the ImGui lock held. 299 void DrawImGui(); 300 301 AbstractFramebuffer* m_current_framebuffer = nullptr; 302 const AbstractPipeline* m_current_pipeline = nullptr; 303 304 Common::Flag m_screenshot_request; 305 Common::Event m_screenshot_completed; 306 std::mutex m_screenshot_lock; 307 std::string m_screenshot_name; 308 309 bool m_is_game_widescreen = false; 310 bool m_was_orthographically_anamorphic = false; 311 312 // The framebuffer size 313 int m_target_width = 1; 314 int m_target_height = 1; 315 316 // Backbuffer (window) size and render area 317 int m_backbuffer_width = 0; 318 int m_backbuffer_height = 0; 319 float m_backbuffer_scale = 1.0f; 320 AbstractTextureFormat m_backbuffer_format = AbstractTextureFormat::Undefined; 321 MathUtil::Rectangle<int> m_target_rectangle = {}; 322 int m_frame_count = 0; 323 324 FPSCounter m_fps_counter; 325 326 std::unique_ptr<VideoCommon::PostProcessing> m_post_processor; 327 328 void* m_new_surface_handle = nullptr; 329 Common::Flag m_surface_changed; 330 Common::Flag m_surface_resized; 331 std::mutex m_swap_mutex; 332 333 // ImGui resources. 334 std::unique_ptr<NativeVertexFormat> m_imgui_vertex_format; 335 std::vector<std::unique_ptr<AbstractTexture>> m_imgui_textures; 336 std::unique_ptr<AbstractPipeline> m_imgui_pipeline; 337 std::mutex m_imgui_mutex; 338 u64 m_imgui_last_frame_time; 339 340 private: 341 void RunFrameDumps(); 342 std::tuple<int, int> CalculateOutputDimensions(int width, int height) const; 343 344 PEControl::PixelFormat m_prev_efb_format = PEControl::INVALID_FMT; 345 unsigned int m_efb_scale = 1; 346 347 // These will be set on the first call to SetWindowSize. 348 int m_last_window_request_width = 0; 349 int m_last_window_request_height = 0; 350 351 // frame dumping 352 std::thread m_frame_dump_thread; 353 Common::Event m_frame_dump_start; 354 Common::Event m_frame_dump_done; 355 Common::Flag m_frame_dump_thread_running; 356 u32 m_frame_dump_image_counter = 0; 357 bool m_frame_dump_frame_running = false; 358 struct FrameDumpConfig 359 { 360 const u8* data; 361 int width; 362 int height; 363 int stride; 364 FrameDump::Frame state; 365 } m_frame_dump_config; 366 367 // Texture used for screenshot/frame dumping 368 std::unique_ptr<AbstractTexture> m_frame_dump_render_texture; 369 std::unique_ptr<AbstractFramebuffer> m_frame_dump_render_framebuffer; 370 std::array<std::unique_ptr<AbstractStagingTexture>, 2> m_frame_dump_readback_textures; 371 FrameDump::Frame m_last_frame_state; 372 bool m_last_frame_exported = false; 373 374 // Tracking of XFB textures so we don't render duplicate frames. 375 u64 m_last_xfb_id = std::numeric_limits<u64>::max(); 376 u64 m_last_xfb_ticks = 0; 377 u32 m_last_xfb_addr = 0; 378 u32 m_last_xfb_width = 0; 379 u32 m_last_xfb_stride = 0; 380 u32 m_last_xfb_height = 0; 381 382 // NOTE: The methods below are called on the framedumping thread. 383 bool StartFrameDumpToFFMPEG(const FrameDumpConfig& config); 384 void DumpFrameToFFMPEG(const FrameDumpConfig& config); 385 void StopFrameDumpToFFMPEG(); 386 std::string GetFrameDumpNextImageFileName() const; 387 bool StartFrameDumpToImage(const FrameDumpConfig& config); 388 void DumpFrameToImage(const FrameDumpConfig& config); 389 void ShutdownFrameDumping(); 390 391 bool IsFrameDumping() const; 392 393 // Checks that the frame dump render texture exists and is the correct size. 394 bool CheckFrameDumpRenderTexture(u32 target_width, u32 target_height); 395 396 // Checks that the frame dump readback texture exists and is the correct size. 397 bool CheckFrameDumpReadbackTexture(u32 target_width, u32 target_height); 398 399 // Fills the frame dump staging texture with the current XFB texture. 400 void DumpCurrentFrame(const AbstractTexture* src_texture, 401 const MathUtil::Rectangle<int>& src_rect, u64 ticks); 402 403 // Asynchronously encodes the specified pointer of frame data to the frame dump. 404 void DumpFrameData(const u8* data, int w, int h, int stride, const FrameDump::Frame& state); 405 406 // Ensures all rendered frames are queued for encoding. 407 void FlushFrameDump(); 408 409 // Ensures all encoded frames have been written to the output file. 410 void FinishFrameData(); 411 412 std::unique_ptr<NetPlayChatUI> m_netplay_chat_ui; 413 }; 414 415 extern std::unique_ptr<Renderer> g_renderer; 416