LCOV - code coverage report
Current view: top level - source/renderer - Renderer.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 354 0.0 %
Date: 2022-03-08 13:03:03 Functions: 0 35 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "Renderer.h"
      21             : 
      22             : #include "graphics/Canvas2D.h"
      23             : #include "graphics/CinemaManager.h"
      24             : #include "graphics/GameView.h"
      25             : #include "graphics/LightEnv.h"
      26             : #include "graphics/ModelDef.h"
      27             : #include "graphics/TerrainTextureManager.h"
      28             : #include "i18n/L10n.h"
      29             : #include "lib/allocators/shared_ptr.h"
      30             : #include "lib/ogl.h"
      31             : #include "lib/tex/tex.h"
      32             : #include "gui/GUIManager.h"
      33             : #include "ps/CConsole.h"
      34             : #include "ps/CLogger.h"
      35             : #include "ps/ConfigDB.h"
      36             : #include "ps/CStrInternStatic.h"
      37             : #include "ps/Game.h"
      38             : #include "ps/GameSetup/Config.h"
      39             : #include "ps/GameSetup/GameSetup.h"
      40             : #include "ps/Globals.h"
      41             : #include "ps/Loader.h"
      42             : #include "ps/Profile.h"
      43             : #include "ps/Filesystem.h"
      44             : #include "ps/World.h"
      45             : #include "ps/ProfileViewer.h"
      46             : #include "graphics/Camera.h"
      47             : #include "graphics/FontManager.h"
      48             : #include "graphics/ShaderManager.h"
      49             : #include "graphics/Terrain.h"
      50             : #include "graphics/Texture.h"
      51             : #include "graphics/TextureManager.h"
      52             : #include "ps/Util.h"
      53             : #include "ps/VideoMode.h"
      54             : #include "renderer/backend/gl/Device.h"
      55             : #include "renderer/DebugRenderer.h"
      56             : #include "renderer/PostprocManager.h"
      57             : #include "renderer/RenderingOptions.h"
      58             : #include "renderer/RenderModifiers.h"
      59             : #include "renderer/SceneRenderer.h"
      60             : #include "renderer/TimeManager.h"
      61             : #include "renderer/VertexBufferManager.h"
      62             : #include "tools/atlas/GameInterface/GameLoop.h"
      63             : #include "tools/atlas/GameInterface/View.h"
      64             : 
      65             : #include <algorithm>
      66             : 
      67             : namespace
      68             : {
      69             : 
      70             : size_t g_NextScreenShotNumber = 0;
      71             : 
      72             : ///////////////////////////////////////////////////////////////////////////////////
      73             : // CRendererStatsTable - Profile display of rendering stats
      74             : 
      75             : /**
      76             :  * Class CRendererStatsTable: Implementation of AbstractProfileTable to
      77             :  * display the renderer stats in-game.
      78             :  *
      79             :  * Accesses CRenderer::m_Stats by keeping the reference passed to the
      80             :  * constructor.
      81             :  */
      82           0 : class CRendererStatsTable : public AbstractProfileTable
      83             : {
      84             :     NONCOPYABLE(CRendererStatsTable);
      85             : public:
      86             :     CRendererStatsTable(const CRenderer::Stats& st);
      87             : 
      88             :     // Implementation of AbstractProfileTable interface
      89             :     CStr GetName();
      90             :     CStr GetTitle();
      91             :     size_t GetNumberRows();
      92             :     const std::vector<ProfileColumn>& GetColumns();
      93             :     CStr GetCellText(size_t row, size_t col);
      94             :     AbstractProfileTable* GetChild(size_t row);
      95             : 
      96             : private:
      97             :     /// Reference to the renderer singleton's stats
      98             :     const CRenderer::Stats& Stats;
      99             : 
     100             :     /// Column descriptions
     101             :     std::vector<ProfileColumn> columnDescriptions;
     102             : 
     103             :     enum
     104             :     {
     105             :         Row_DrawCalls = 0,
     106             :         Row_TerrainTris,
     107             :         Row_WaterTris,
     108             :         Row_ModelTris,
     109             :         Row_OverlayTris,
     110             :         Row_BlendSplats,
     111             :         Row_Particles,
     112             :         Row_VBReserved,
     113             :         Row_VBAllocated,
     114             :         Row_TextureMemory,
     115             :         Row_ShadersLoaded,
     116             : 
     117             :         // Must be last to count number of rows
     118             :         NumberRows
     119             :     };
     120             : };
     121             : 
     122             : // Construction
     123           0 : CRendererStatsTable::CRendererStatsTable(const CRenderer::Stats& st)
     124           0 :     : Stats(st)
     125             : {
     126           0 :     columnDescriptions.push_back(ProfileColumn("Name", 230));
     127           0 :     columnDescriptions.push_back(ProfileColumn("Value", 100));
     128           0 : }
     129             : 
     130             : // Implementation of AbstractProfileTable interface
     131           0 : CStr CRendererStatsTable::GetName()
     132             : {
     133           0 :     return "renderer";
     134             : }
     135             : 
     136           0 : CStr CRendererStatsTable::GetTitle()
     137             : {
     138           0 :     return "Renderer statistics";
     139             : }
     140             : 
     141           0 : size_t CRendererStatsTable::GetNumberRows()
     142             : {
     143           0 :     return NumberRows;
     144             : }
     145             : 
     146           0 : const std::vector<ProfileColumn>& CRendererStatsTable::GetColumns()
     147             : {
     148           0 :     return columnDescriptions;
     149             : }
     150             : 
     151           0 : CStr CRendererStatsTable::GetCellText(size_t row, size_t col)
     152             : {
     153           0 :     char buf[256];
     154             : 
     155           0 :     switch(row)
     156             :     {
     157           0 :     case Row_DrawCalls:
     158           0 :         if (col == 0)
     159           0 :             return "# draw calls";
     160           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_DrawCalls);
     161           0 :         return buf;
     162             : 
     163           0 :     case Row_TerrainTris:
     164           0 :         if (col == 0)
     165           0 :             return "# terrain tris";
     166           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_TerrainTris);
     167           0 :         return buf;
     168             : 
     169           0 :     case Row_WaterTris:
     170           0 :         if (col == 0)
     171           0 :             return "# water tris";
     172           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_WaterTris);
     173           0 :         return buf;
     174             : 
     175           0 :     case Row_ModelTris:
     176           0 :         if (col == 0)
     177           0 :             return "# model tris";
     178           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_ModelTris);
     179           0 :         return buf;
     180             : 
     181           0 :     case Row_OverlayTris:
     182           0 :         if (col == 0)
     183           0 :             return "# overlay tris";
     184           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_OverlayTris);
     185           0 :         return buf;
     186             : 
     187           0 :     case Row_BlendSplats:
     188           0 :         if (col == 0)
     189           0 :             return "# blend splats";
     190           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_BlendSplats);
     191           0 :         return buf;
     192             : 
     193           0 :     case Row_Particles:
     194           0 :         if (col == 0)
     195           0 :             return "# particles";
     196           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)Stats.m_Particles);
     197           0 :         return buf;
     198             : 
     199           0 :     case Row_VBReserved:
     200           0 :         if (col == 0)
     201           0 :             return "VB reserved";
     202           0 :         sprintf_s(buf, sizeof(buf), "%lu kB", (unsigned long)g_VBMan.GetBytesReserved() / 1024);
     203           0 :         return buf;
     204             : 
     205           0 :     case Row_VBAllocated:
     206           0 :         if (col == 0)
     207           0 :             return "VB allocated";
     208           0 :         sprintf_s(buf, sizeof(buf), "%lu kB", (unsigned long)g_VBMan.GetBytesAllocated() / 1024);
     209           0 :         return buf;
     210             : 
     211           0 :     case Row_TextureMemory:
     212           0 :         if (col == 0)
     213           0 :             return "textures uploaded";
     214           0 :         sprintf_s(buf, sizeof(buf), "%lu kB", (unsigned long)g_Renderer.GetTextureManager().GetBytesUploaded() / 1024);
     215           0 :         return buf;
     216             : 
     217           0 :     case Row_ShadersLoaded:
     218           0 :         if (col == 0)
     219           0 :             return "shader effects loaded";
     220           0 :         sprintf_s(buf, sizeof(buf), "%lu", (unsigned long)g_Renderer.GetShaderManager().GetNumEffectsLoaded());
     221           0 :         return buf;
     222             : 
     223           0 :     default:
     224           0 :         return "???";
     225             :     }
     226             : }
     227             : 
     228           0 : AbstractProfileTable* CRendererStatsTable::GetChild(size_t UNUSED(row))
     229             : {
     230           0 :     return 0;
     231             : }
     232             : 
     233             : } // anonymous namespace
     234             : 
     235             : ///////////////////////////////////////////////////////////////////////////////////
     236             : // CRenderer implementation
     237             : 
     238             : /**
     239             :  * Struct CRendererInternals: Truly hide data that is supposed to be hidden
     240             :  * in this structure so it won't even appear in header files.
     241             :  */
     242             : class CRenderer::Internals
     243             : {
     244             :     NONCOPYABLE(Internals);
     245             : public:
     246             :     std::unique_ptr<Renderer::Backend::GL::CDeviceCommandContext> deviceCommandContext;
     247             : 
     248             :     /// true if CRenderer::Open has been called
     249             :     bool IsOpen;
     250             : 
     251             :     /// true if shaders need to be reloaded
     252             :     bool ShadersDirty;
     253             : 
     254             :     /// Table to display renderer stats in-game via profile system
     255             :     CRendererStatsTable profileTable;
     256             : 
     257             :     /// Shader manager
     258             :     CShaderManager shaderManager;
     259             : 
     260             :     /// Texture manager
     261             :     CTextureManager textureManager;
     262             : 
     263             :     /// Time manager
     264             :     CTimeManager timeManager;
     265             : 
     266             :     /// Postprocessing effect manager
     267             :     CPostprocManager postprocManager;
     268             : 
     269             :     CSceneRenderer sceneRenderer;
     270             : 
     271             :     CDebugRenderer debugRenderer;
     272             : 
     273             :     CFontManager fontManager;
     274             : 
     275           0 :     Internals() :
     276           0 :         IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats),
     277             :         deviceCommandContext(g_VideoMode.GetBackendDevice()->CreateCommandContext()),
     278           0 :         textureManager(g_VFS, false, false)
     279             :     {
     280           0 :     }
     281             : };
     282             : 
     283           0 : CRenderer::CRenderer()
     284             : {
     285           0 :     TIMER(L"InitRenderer");
     286             : 
     287           0 :     m = std::make_unique<Internals>();
     288             : 
     289           0 :     g_ProfileViewer.AddRootTable(&m->profileTable);
     290             : 
     291           0 :     m_Width = 0;
     292           0 :     m_Height = 0;
     293             : 
     294           0 :     m_Stats.Reset();
     295             : 
     296             :     // Create terrain related stuff.
     297           0 :     new CTerrainTextureManager;
     298             : 
     299           0 :     Open(g_xres, g_yres);
     300             : 
     301             :     // Setup lighting environment. Since the Renderer accesses the
     302             :     // lighting environment through a pointer, this has to be done before
     303             :     // the first Frame.
     304           0 :     GetSceneRenderer().SetLightEnv(&g_LightEnv);
     305             : 
     306             :     // I haven't seen the camera affecting GUI rendering and such, but the
     307             :     // viewport has to be updated according to the video mode
     308           0 :     SViewPort vp;
     309           0 :     vp.m_X = 0;
     310           0 :     vp.m_Y = 0;
     311           0 :     vp.m_Width = g_xres;
     312           0 :     vp.m_Height = g_yres;
     313           0 :     SetViewport(vp);
     314           0 :     ModelDefActivateFastImpl();
     315           0 :     ColorActivateFastImpl();
     316           0 :     ModelRenderer::Init();
     317           0 : }
     318             : 
     319           0 : CRenderer::~CRenderer()
     320             : {
     321           0 :     delete &g_TexMan;
     322             : 
     323             :     // We no longer UnloadWaterTextures here -
     324             :     // that is the responsibility of the module that asked for
     325             :     // them to be loaded (i.e. CGameView).
     326           0 :     m.reset();
     327           0 : }
     328             : 
     329           0 : void CRenderer::ReloadShaders()
     330             : {
     331           0 :     ENSURE(m->IsOpen);
     332             : 
     333           0 :     m->sceneRenderer.ReloadShaders();
     334           0 :     m->ShadersDirty = false;
     335           0 : }
     336             : 
     337           0 : bool CRenderer::Open(int width, int height)
     338             : {
     339           0 :     m->IsOpen = true;
     340             : 
     341             :     // Dimensions
     342           0 :     m_Width = width;
     343           0 :     m_Height = height;
     344             : 
     345             :     // Validate the currently selected render path
     346           0 :     SetRenderPath(g_RenderingOptions.GetRenderPath());
     347             : 
     348           0 :     if (m->postprocManager.IsEnabled())
     349           0 :         m->postprocManager.Initialize();
     350             : 
     351           0 :     m->sceneRenderer.Initialize();
     352             : 
     353           0 :     return true;
     354             : }
     355             : 
     356           0 : void CRenderer::Resize(int width, int height)
     357             : {
     358           0 :     m_Width = width;
     359           0 :     m_Height = height;
     360             : 
     361           0 :     m->postprocManager.Resize();
     362             : 
     363           0 :     m->sceneRenderer.Resize(width, height);
     364           0 : }
     365             : 
     366           0 : void CRenderer::SetRenderPath(RenderPath rp)
     367             : {
     368           0 :     if (!m->IsOpen)
     369             :     {
     370             :         // Delay until Open() is called.
     371             :         return;
     372             :     }
     373             : 
     374             :     // Renderer has been opened, so validate the selected renderpath
     375           0 :     const bool hasShadersSupport =
     376           0 :         g_VideoMode.GetBackendDevice()->GetCapabilities().ARBShaders ||
     377           0 :         g_VideoMode.GetBackend() != CVideoMode::Backend::GL_ARB;
     378           0 :     if (rp == RenderPath::DEFAULT)
     379             :     {
     380           0 :         if (hasShadersSupport)
     381             :             rp = RenderPath::SHADER;
     382             :         else
     383             :             rp = RenderPath::FIXED;
     384             :     }
     385             : 
     386           0 :     if (rp == RenderPath::SHADER)
     387             :     {
     388           0 :         if (!hasShadersSupport)
     389             :         {
     390           0 :             LOGWARNING("Falling back to fixed function\n");
     391           0 :             rp = RenderPath::FIXED;
     392             :         }
     393             :     }
     394             : 
     395             :     // TODO: remove this once capabilities have been properly extracted and the above checks have been moved elsewhere.
     396           0 :     g_RenderingOptions.m_RenderPath = rp;
     397             : 
     398           0 :     MakeShadersDirty();
     399             : }
     400             : 
     401           0 : bool CRenderer::ShouldRender() const
     402             : {
     403           0 :     return !g_app_minimized && (g_app_has_focus || !g_VideoMode.IsInFullscreen());
     404             : }
     405             : 
     406           0 : void CRenderer::RenderFrame(const bool needsPresent)
     407             : {
     408             :     // Do not render if not focused while in fullscreen or minimised,
     409             :     // as that triggers a difficult-to-reproduce crash on some graphic cards.
     410           0 :     if (!ShouldRender())
     411             :         return;
     412             : 
     413           0 :     if (m_ShouldPreloadResourcesBeforeNextFrame)
     414             :     {
     415           0 :         m_ShouldPreloadResourcesBeforeNextFrame = false;
     416             :         // We don't meed to render logger for the preload.
     417           0 :         RenderFrameImpl(true, false);
     418             :     }
     419             : 
     420           0 :     if (m_ScreenShotType == ScreenShotType::BIG)
     421             :     {
     422           0 :         RenderBigScreenShot(needsPresent);
     423             :     }
     424             :     else
     425             :     {
     426           0 :         if (m_ScreenShotType == ScreenShotType::DEFAULT)
     427           0 :             RenderScreenShot();
     428             :         else
     429           0 :             RenderFrameImpl(true, true);
     430             : 
     431           0 :         m->deviceCommandContext->Flush();
     432           0 :         if (needsPresent)
     433           0 :             g_VideoMode.GetBackendDevice()->Present();
     434             :     }
     435             : }
     436             : 
     437           0 : void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger)
     438             : {
     439           0 :     PROFILE3("render");
     440             : 
     441           0 :     g_Profiler2.RecordGPUFrameStart();
     442           0 :     ogl_WarnIfError();
     443             : 
     444           0 :     g_TexMan.UploadResourcesIfNeeded(m->deviceCommandContext.get());
     445             : 
     446           0 :     m->textureManager.MakeUploadProgress(m->deviceCommandContext.get());
     447             : 
     448             :     // prepare before starting the renderer frame
     449           0 :     if (g_Game && g_Game->IsGameStarted())
     450           0 :         g_Game->GetView()->BeginFrame();
     451             : 
     452           0 :     if (g_Game)
     453           0 :         m->sceneRenderer.SetSimulation(g_Game->GetSimulation2());
     454             : 
     455             :     // start new frame
     456           0 :     BeginFrame();
     457             : 
     458           0 :     ogl_WarnIfError();
     459             : 
     460           0 :     if (g_Game && g_Game->IsGameStarted())
     461             :     {
     462           0 :         g_Game->GetView()->Render();
     463             :         ogl_WarnIfError();
     464             :     }
     465             : 
     466           0 :     m->deviceCommandContext->SetFramebuffer(
     467           0 :         m->deviceCommandContext->GetDevice()->GetCurrentBackbuffer());
     468             : 
     469             :     // If we're in Atlas game view, render special tools
     470           0 :     if (g_AtlasGameLoop && g_AtlasGameLoop->view)
     471             :     {
     472           0 :         g_AtlasGameLoop->view->DrawCinemaPathTool();
     473             :         ogl_WarnIfError();
     474             :     }
     475             : 
     476           0 :     if (g_Game && g_Game->IsGameStarted())
     477             :     {
     478           0 :         g_Game->GetView()->GetCinema()->Render();
     479             :         ogl_WarnIfError();
     480             :     }
     481             : 
     482           0 :     RenderFrame2D(renderGUI, renderLogger);
     483             : 
     484           0 :     EndFrame();
     485             : 
     486           0 :     const Stats& stats = GetStats();
     487           0 :     PROFILE2_ATTR("draw calls: %zu", stats.m_DrawCalls);
     488           0 :     PROFILE2_ATTR("terrain tris: %zu", stats.m_TerrainTris);
     489           0 :     PROFILE2_ATTR("water tris: %zu", stats.m_WaterTris);
     490           0 :     PROFILE2_ATTR("model tris: %zu", stats.m_ModelTris);
     491           0 :     PROFILE2_ATTR("overlay tris: %zu", stats.m_OverlayTris);
     492           0 :     PROFILE2_ATTR("blend splats: %zu", stats.m_BlendSplats);
     493           0 :     PROFILE2_ATTR("particles: %zu", stats.m_Particles);
     494             : 
     495           0 :     ogl_WarnIfError();
     496             : 
     497           0 :     g_Profiler2.RecordGPUFrameEnd();
     498           0 :     ogl_WarnIfError();
     499           0 : }
     500             : 
     501           0 : void CRenderer::RenderFrame2D(const bool renderGUI, const bool renderLogger)
     502             : {
     503           0 :     CCanvas2D canvas(m->deviceCommandContext.get());
     504             : 
     505           0 :     m->sceneRenderer.RenderTextOverlays(canvas);
     506             : 
     507           0 :     if (renderGUI)
     508             :     {
     509           0 :         GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render GUI");
     510             :         // All GUI elements are drawn in Z order to render semi-transparent
     511             :         // objects correctly.
     512           0 :         g_GUI->Draw(canvas);
     513           0 :         ogl_WarnIfError();
     514             :     }
     515             : 
     516             :     // If we're in Atlas game view, render special overlays (e.g. editor bandbox).
     517           0 :     if (g_AtlasGameLoop && g_AtlasGameLoop->view)
     518             :     {
     519           0 :         g_AtlasGameLoop->view->DrawOverlays(canvas);
     520             :         ogl_WarnIfError();
     521             :     }
     522             : 
     523           0 :     {
     524           0 :         GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render console");
     525           0 :         g_Console->Render(canvas);
     526           0 :         ogl_WarnIfError();
     527             :     }
     528             : 
     529           0 :     if (renderLogger)
     530             :     {
     531           0 :         GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render logger");
     532           0 :         g_Logger->Render(canvas);
     533           0 :         ogl_WarnIfError();
     534             :     }
     535             : 
     536           0 :     {
     537           0 :         GPU_SCOPED_LABEL(m->deviceCommandContext.get(), "Render profiler");
     538             :         // Profile information
     539           0 :         g_ProfileViewer.RenderProfile(canvas);
     540           0 :         ogl_WarnIfError();
     541             :     }
     542           0 : }
     543             : 
     544           0 : void CRenderer::RenderScreenShot()
     545             : {
     546           0 :     m_ScreenShotType = ScreenShotType::NONE;
     547             : 
     548             :     // get next available numbered filename
     549             :     // note: %04d -> always 4 digits, so sorting by filename works correctly.
     550           0 :     const VfsPath filenameFormat(L"screenshots/screenshot%04d.png");
     551           0 :     VfsPath filename;
     552           0 :     vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename);
     553             : 
     554           0 :     const size_t w = (size_t)g_xres, h = (size_t)g_yres;
     555           0 :     const size_t bpp = 24;
     556           0 :     GLenum fmt = GL_RGB;
     557           0 :     int flags = TEX_BOTTOM_UP;
     558             : 
     559             :     // Hide log messages and re-render
     560           0 :     RenderFrameImpl(true, false);
     561             : 
     562           0 :     const size_t img_size = w * h * bpp / 8;
     563           0 :     const size_t hdr_size = tex_hdr_size(filename);
     564           0 :     std::shared_ptr<u8> buf;
     565           0 :     AllocateAligned(buf, hdr_size + img_size, maxSectorSize);
     566           0 :     GLvoid* img = buf.get() + hdr_size;
     567           0 :     Tex t;
     568           0 :     if (t.wrap(w, h, bpp, flags, buf, hdr_size) < 0)
     569           0 :         return;
     570           0 :     glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img);
     571             : 
     572           0 :     if (tex_write(&t, filename) == INFO::OK)
     573             :     {
     574           0 :         OsPath realPath;
     575           0 :         g_VFS->GetRealPath(filename, realPath);
     576             : 
     577           0 :         LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());
     578             : 
     579           0 :         debug_printf(
     580           0 :             CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
     581           0 :             realPath.string8().c_str());
     582             :     }
     583             :     else
     584           0 :         LOGERROR("Error writing screenshot to '%s'", filename.string8());
     585             : }
     586             : 
     587           0 : void CRenderer::RenderBigScreenShot(const bool needsPresent)
     588             : {
     589           0 :     m_ScreenShotType = ScreenShotType::NONE;
     590             : 
     591             :     // If the game hasn't started yet then use WriteScreenshot to generate the image.
     592           0 :     if (!g_Game)
     593           0 :         return RenderScreenShot();
     594             : 
     595           0 :     int tiles = 4, tileWidth = 256, tileHeight = 256;
     596           0 :     CFG_GET_VAL("screenshot.tiles", tiles);
     597           0 :     CFG_GET_VAL("screenshot.tilewidth", tileWidth);
     598           0 :     CFG_GET_VAL("screenshot.tileheight", tileHeight);
     599           0 :     if (tiles <= 0 || tileWidth <= 0 || tileHeight <= 0 || tileWidth * tiles % 4 != 0 || tileHeight * tiles % 4 != 0)
     600             :     {
     601           0 :         LOGWARNING("Invalid big screenshot size: tiles=%d tileWidth=%d tileHeight=%d", tiles, tileWidth, tileHeight);
     602           0 :         return;
     603             :     }
     604             : 
     605             :     // get next available numbered filename
     606             :     // note: %04d -> always 4 digits, so sorting by filename works correctly.
     607           0 :     const VfsPath filenameFormat(L"screenshots/screenshot%04d.bmp");
     608           0 :     VfsPath filename;
     609           0 :     vfs::NextNumberedFilename(g_VFS, filenameFormat, g_NextScreenShotNumber, filename);
     610             : 
     611             :     // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
     612             :     // hope the screen is actually large enough for that.
     613           0 :     ENSURE(g_xres >= tileWidth && g_yres >= tileHeight);
     614             : 
     615           0 :     const int imageWidth = tileWidth * tiles, imageHeight = tileHeight * tiles;
     616           0 :     const int bpp = 24;
     617             :     // we want writing BMP to be as fast as possible,
     618             :     // so read data from OpenGL in BMP format to obviate conversion.
     619             : #if CONFIG2_GLES // GLES doesn't support BGR
     620             :     const GLenum fmt = GL_RGB;
     621             :     const int flags = TEX_BOTTOM_UP;
     622             : #else
     623           0 :     const GLenum fmt = GL_BGR;
     624           0 :     const int flags = TEX_BOTTOM_UP | TEX_BGR;
     625             : #endif
     626             : 
     627           0 :     const size_t imageSize = imageWidth * imageHeight * bpp / 8;
     628           0 :     const size_t tileSize = tileWidth * tileHeight * bpp / 8;
     629           0 :     const size_t headerSize = tex_hdr_size(filename);
     630           0 :     void* tileData = malloc(tileSize);
     631           0 :     if (!tileData)
     632             :     {
     633           0 :         WARN_IF_ERR(ERR::NO_MEM);
     634           0 :         return;
     635             :     }
     636           0 :     std::shared_ptr<u8> imageBuffer;
     637           0 :     AllocateAligned(imageBuffer, headerSize + imageSize, maxSectorSize);
     638             : 
     639           0 :     Tex t;
     640           0 :     GLvoid* img = imageBuffer.get() + headerSize;
     641           0 :     if (t.wrap(imageWidth, imageHeight, bpp, flags, imageBuffer, headerSize) < 0)
     642             :     {
     643           0 :         free(tileData);
     644           0 :         return;
     645             :     }
     646             : 
     647           0 :     ogl_WarnIfError();
     648             : 
     649           0 :     CCamera oldCamera = *g_Game->GetView()->GetCamera();
     650             : 
     651             :     // Resize various things so that the sizes and aspect ratios are correct
     652           0 :     {
     653           0 :         g_Renderer.Resize(tileWidth, tileHeight);
     654           0 :         SViewPort vp = { 0, 0, tileWidth, tileHeight };
     655           0 :         g_Game->GetView()->SetViewport(vp);
     656             :     }
     657             : 
     658             :     // Render each tile
     659           0 :     CMatrix3D projection;
     660           0 :     projection.SetIdentity();
     661           0 :     const float aspectRatio = 1.0f * tileWidth / tileHeight;
     662           0 :     for (int tileY = 0; tileY < tiles; ++tileY)
     663             :     {
     664           0 :         for (int tileX = 0; tileX < tiles; ++tileX)
     665             :         {
     666             :             // Adjust the camera to render the appropriate region
     667           0 :             if (oldCamera.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE)
     668             :             {
     669           0 :                 projection.SetPerspectiveTile(oldCamera.GetFOV(), aspectRatio, oldCamera.GetNearPlane(), oldCamera.GetFarPlane(), tiles, tileX, tileY);
     670             :             }
     671           0 :             g_Game->GetView()->GetCamera()->SetProjection(projection);
     672             : 
     673           0 :             RenderFrameImpl(false, false);
     674             : 
     675             :             // Copy the tile pixels into the main image
     676           0 :             glReadPixels(0, 0, tileWidth, tileHeight, fmt, GL_UNSIGNED_BYTE, tileData);
     677           0 :             for (int y = 0; y < tileHeight; ++y)
     678             :             {
     679           0 :                 void* dest = static_cast<char*>(img) + ((tileY * tileHeight + y) * imageWidth + (tileX * tileWidth)) * bpp / 8;
     680           0 :                 void* src = static_cast<char*>(tileData) + y * tileWidth * bpp / 8;
     681           0 :                 memcpy(dest, src, tileWidth * bpp / 8);
     682             :             }
     683             : 
     684           0 :             m->deviceCommandContext->Flush();
     685           0 :             if (needsPresent)
     686           0 :                 g_VideoMode.GetBackendDevice()->Present();
     687             :         }
     688             :     }
     689             : 
     690             :     // Restore the viewport settings
     691           0 :     {
     692           0 :         g_Renderer.Resize(g_xres, g_yres);
     693           0 :         SViewPort vp = { 0, 0, g_xres, g_yres };
     694           0 :         g_Game->GetView()->SetViewport(vp);
     695           0 :         g_Game->GetView()->GetCamera()->SetProjectionFromCamera(oldCamera);
     696             :     }
     697             : 
     698           0 :     if (tex_write(&t, filename) == INFO::OK)
     699             :     {
     700           0 :         OsPath realPath;
     701           0 :         g_VFS->GetRealPath(filename, realPath);
     702             : 
     703           0 :         LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8());
     704             : 
     705           0 :         debug_printf(
     706           0 :             CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(),
     707           0 :             realPath.string8().c_str());
     708             :     }
     709             :     else
     710           0 :         LOGERROR("Error writing screenshot to '%s'", filename.string8());
     711             : 
     712           0 :     free(tileData);
     713             : }
     714             : 
     715           0 : void CRenderer::BeginFrame()
     716             : {
     717           0 :     PROFILE("begin frame");
     718             : 
     719             :     // Zero out all the per-frame stats.
     720           0 :     m_Stats.Reset();
     721             : 
     722           0 :     if (m->ShadersDirty)
     723           0 :         ReloadShaders();
     724             : 
     725           0 :     m->sceneRenderer.BeginFrame();
     726           0 : }
     727             : 
     728           0 : void CRenderer::EndFrame()
     729             : {
     730           0 :     PROFILE3("end frame");
     731             : 
     732           0 :     m->sceneRenderer.EndFrame();
     733           0 : }
     734             : 
     735           0 : void CRenderer::SetViewport(const SViewPort &vp)
     736             : {
     737           0 :     m_Viewport = vp;
     738           0 :     Renderer::Backend::GL::CDeviceCommandContext::Rect viewportRect;
     739           0 :     viewportRect.x = vp.m_X;
     740           0 :     viewportRect.y = vp.m_Y;
     741           0 :     viewportRect.width = vp.m_Width;
     742           0 :     viewportRect.height = vp.m_Height;
     743           0 :     m->deviceCommandContext->SetViewports(1, &viewportRect);
     744           0 : }
     745             : 
     746           0 : SViewPort CRenderer::GetViewport()
     747             : {
     748           0 :     return m_Viewport;
     749             : }
     750             : 
     751           0 : void CRenderer::MakeShadersDirty()
     752             : {
     753           0 :     m->ShadersDirty = true;
     754           0 :     m->sceneRenderer.MakeShadersDirty();
     755           0 : }
     756             : 
     757           0 : CTextureManager& CRenderer::GetTextureManager()
     758             : {
     759           0 :     return m->textureManager;
     760             : }
     761             : 
     762           0 : CShaderManager& CRenderer::GetShaderManager()
     763             : {
     764           0 :     return m->shaderManager;
     765             : }
     766             : 
     767           0 : CTimeManager& CRenderer::GetTimeManager()
     768             : {
     769           0 :     return m->timeManager;
     770             : }
     771             : 
     772           0 : CPostprocManager& CRenderer::GetPostprocManager()
     773             : {
     774           0 :     return m->postprocManager;
     775             : }
     776             : 
     777           0 : CSceneRenderer& CRenderer::GetSceneRenderer()
     778             : {
     779           0 :     return m->sceneRenderer;
     780             : }
     781             : 
     782           0 : CDebugRenderer& CRenderer::GetDebugRenderer()
     783             : {
     784           0 :     return m->debugRenderer;
     785             : }
     786             : 
     787           0 : CFontManager& CRenderer::GetFontManager()
     788             : {
     789           0 :     return m->fontManager;
     790             : }
     791             : 
     792           0 : void CRenderer::PreloadResourcesBeforeNextFrame()
     793             : {
     794           0 :     m_ShouldPreloadResourcesBeforeNextFrame = true;
     795           0 : }
     796             : 
     797           0 : void CRenderer::MakeScreenShotOnNextFrame(ScreenShotType screenShotType)
     798             : {
     799           0 :     m_ScreenShotType = screenShotType;
     800           0 : }
     801             : 
     802           0 : Renderer::Backend::GL::CDeviceCommandContext* CRenderer::GetDeviceCommandContext()
     803             : {
     804           0 :     return m->deviceCommandContext.get();
     805           0 : }

Generated by: LCOV version 1.13