/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_RENDERER #define INCLUDED_RENDERER #include "graphics/Camera.h" #include "graphics/ShaderDefines.h" #include "graphics/ShaderProgramPtr.h" #include "ps/containers/Span.h" #include "ps/Singleton.h" #include "renderer/backend/IDeviceCommandContext.h" #include "renderer/backend/IShaderProgram.h" #include "renderer/RenderingOptions.h" #include "renderer/Scene.h" #include class CDebugRenderer; class CFontManager; class CPostprocManager; class CSceneRenderer; class CShaderManager; class CTextureManager; class CTimeManager; #define g_Renderer CRenderer::GetSingleton() /** * Higher level interface on top of the whole frame rendering. It does know * what should be rendered and via which renderer but shouldn't know how to * render a particular area, like UI or scene. */ class CRenderer : public Singleton { public: // stats class - per frame counts of number of draw calls, poly counts etc struct Stats { // set all stats to zero void Reset() { memset(this, 0, sizeof(*this)); } // number of draw calls per frame - total DrawElements + Begin/End immediate mode loops size_t m_DrawCalls; // number of terrain triangles drawn size_t m_TerrainTris; // number of water triangles drawn size_t m_WaterTris; // number of (non-transparent) model triangles drawn size_t m_ModelTris; // number of overlay triangles drawn size_t m_OverlayTris; // number of splat passes for alphamapping size_t m_BlendSplats; // number of particles size_t m_Particles; }; enum class ScreenShotType { NONE, DEFAULT, BIG }; public: CRenderer(Renderer::Backend::IDevice* device); ~CRenderer(); // open up the renderer: performs any necessary initialisation bool Open(int width, int height); // resize renderer view void Resize(int width, int height); // return view width int GetWidth() const { return m_Width; } // return view height int GetHeight() const { return m_Height; } void RenderFrame(bool needsPresent); // signal frame start void BeginFrame(); // signal frame end void EndFrame(); // trigger a reload of shaders (when parameters they depend on have changed) void MakeShadersDirty(); // return stats accumulated for current frame Stats& GetStats() { return m_Stats; } CTextureManager& GetTextureManager(); CShaderManager& GetShaderManager(); CFontManager& GetFontManager(); CTimeManager& GetTimeManager(); CPostprocManager& GetPostprocManager(); CSceneRenderer& GetSceneRenderer(); CDebugRenderer& GetDebugRenderer(); /** * Performs a complete frame without presenting to force loading all needed * resources. It's used for the first frame on a game start. * TODO: It might be better to preload resources without a complete frame * rendering. */ void PreloadResourcesBeforeNextFrame(); /** * Makes a screenshot on the next RenderFrame according of the given * screenshot type. */ void MakeScreenShotOnNextFrame(ScreenShotType screenShotType); Renderer::Backend::IDeviceCommandContext* GetDeviceCommandContext(); /** * Returns a cached vertex input layout. The renderer owns the layout to be * able to share it between different clients. As backend should have * as few different layouts as possible. * The function isn't cheap so it should be called as rarely as possible. * TODO: we need to make VertexArray less error prone by passing layout. */ Renderer::Backend::IVertexInputLayout* GetVertexInputLayout( const PS::span attributes); protected: friend class CPatchRData; friend class CDecalRData; friend class HWLightingModelRenderer; friend class ShaderModelVertexRenderer; friend class InstancingModelRenderer; friend class CRenderingOptions; bool ShouldRender() const; void RenderFrameImpl(const bool renderGUI, const bool renderLogger); void RenderFrame2D(const bool renderGUI, const bool renderLogger); void RenderScreenShot(const bool needsPresent); void RenderBigScreenShot(const bool needsPresent); // SetRenderPath: Select the preferred render path. // This may only be called before Open(), because the layout of vertex arrays and other // data may depend on the chosen render path. void SetRenderPath(RenderPath rp); void ReloadShaders(); // Private data that is not needed by inline functions. class Internals; std::unique_ptr m; // view width int m_Width = 0; // view height int m_Height = 0; // per-frame renderer stats Stats m_Stats; bool m_ShouldPreloadResourcesBeforeNextFrame = false; ScreenShotType m_ScreenShotType = ScreenShotType::NONE; }; #endif // INCLUDED_RENDERER