1 /* Copyright (C) 2023 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
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"
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"
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"
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"
53 #include "ps/VideoMode.h"
54 #include "renderer/backend/IDevice.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"
70 size_t g_NextScreenShotNumber
= 0;
72 ///////////////////////////////////////////////////////////////////////////////////
73 // CRendererStatsTable - Profile display of rendering stats
76 * Class CRendererStatsTable: Implementation of AbstractProfileTable to
77 * display the renderer stats in-game.
79 * Accesses CRenderer::m_Stats by keeping the reference passed to the
82 class CRendererStatsTable
: public AbstractProfileTable
84 NONCOPYABLE(CRendererStatsTable
);
86 CRendererStatsTable(const CRenderer::Stats
& st
);
88 // Implementation of AbstractProfileTable interface
89 CStr
GetName() override
;
90 CStr
GetTitle() override
;
91 size_t GetNumberRows() override
;
92 const std::vector
<ProfileColumn
>& GetColumns() override
;
93 CStr
GetCellText(size_t row
, size_t col
) override
;
94 AbstractProfileTable
* GetChild(size_t row
) override
;
97 /// Reference to the renderer singleton's stats
98 const CRenderer::Stats
& Stats
;
100 /// Column descriptions
101 std::vector
<ProfileColumn
> columnDescriptions
;
117 // Must be last to count number of rows
123 CRendererStatsTable::CRendererStatsTable(const CRenderer::Stats
& st
)
126 columnDescriptions
.push_back(ProfileColumn("Name", 230));
127 columnDescriptions
.push_back(ProfileColumn("Value", 100));
130 // Implementation of AbstractProfileTable interface
131 CStr
CRendererStatsTable::GetName()
136 CStr
CRendererStatsTable::GetTitle()
138 return "Renderer statistics";
141 size_t CRendererStatsTable::GetNumberRows()
146 const std::vector
<ProfileColumn
>& CRendererStatsTable::GetColumns()
148 return columnDescriptions
;
151 CStr
CRendererStatsTable::GetCellText(size_t row
, size_t col
)
159 return "# draw calls";
160 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_DrawCalls
);
163 case Row_TerrainTris
:
165 return "# terrain tris";
166 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_TerrainTris
);
171 return "# water tris";
172 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_WaterTris
);
177 return "# model tris";
178 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_ModelTris
);
181 case Row_OverlayTris
:
183 return "# overlay tris";
184 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_OverlayTris
);
187 case Row_BlendSplats
:
189 return "# blend splats";
190 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_BlendSplats
);
195 return "# particles";
196 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)Stats
.m_Particles
);
201 return "VB reserved";
202 sprintf_s(buf
, sizeof(buf
), "%lu kB", (unsigned long)g_VBMan
.GetBytesReserved() / 1024);
205 case Row_VBAllocated
:
207 return "VB allocated";
208 sprintf_s(buf
, sizeof(buf
), "%lu kB", (unsigned long)g_VBMan
.GetBytesAllocated() / 1024);
211 case Row_TextureMemory
:
213 return "textures uploaded";
214 sprintf_s(buf
, sizeof(buf
), "%lu kB", (unsigned long)g_Renderer
.GetTextureManager().GetBytesUploaded() / 1024);
217 case Row_ShadersLoaded
:
219 return "shader effects loaded";
220 sprintf_s(buf
, sizeof(buf
), "%lu", (unsigned long)g_Renderer
.GetShaderManager().GetNumEffectsLoaded());
228 AbstractProfileTable
* CRendererStatsTable::GetChild(size_t UNUSED(row
))
233 } // anonymous namespace
235 ///////////////////////////////////////////////////////////////////////////////////
236 // CRenderer implementation
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.
242 class CRenderer::Internals
244 NONCOPYABLE(Internals
);
246 std::unique_ptr
<Renderer::Backend::IDeviceCommandContext
> deviceCommandContext
;
248 /// true if CRenderer::Open has been called
251 /// true if shaders need to be reloaded
254 /// Table to display renderer stats in-game via profile system
255 CRendererStatsTable profileTable
;
258 CShaderManager shaderManager
;
261 CTextureManager textureManager
;
264 CTimeManager timeManager
;
266 /// Postprocessing effect manager
267 CPostprocManager postprocManager
;
269 CSceneRenderer sceneRenderer
;
271 CDebugRenderer debugRenderer
;
273 CFontManager fontManager
;
275 struct VertexAttributesHash
277 size_t operator()(const std::vector
<Renderer::Backend::SVertexAttributeFormat
>& attributes
) const;
281 std::vector
<Renderer::Backend::SVertexAttributeFormat
>,
282 std::unique_ptr
<Renderer::Backend::IVertexInputLayout
>, VertexAttributesHash
> vertexInputLayouts
;
285 IsOpen(false), ShadersDirty(true), profileTable(g_Renderer
.m_Stats
),
286 deviceCommandContext(g_VideoMode
.GetBackendDevice()->CreateCommandContext()),
287 textureManager(g_VFS
, false, g_VideoMode
.GetBackendDevice())
292 size_t CRenderer::Internals::VertexAttributesHash::operator()(
293 const std::vector
<Renderer::Backend::SVertexAttributeFormat
>& attributes
) const
296 hash_combine(seed
, attributes
.size());
297 for (const Renderer::Backend::SVertexAttributeFormat
& attribute
: attributes
)
299 hash_combine(seed
, attribute
.stream
);
300 hash_combine(seed
, attribute
.format
);
301 hash_combine(seed
, attribute
.offset
);
302 hash_combine(seed
, attribute
.stride
);
303 hash_combine(seed
, attribute
.rate
);
304 hash_combine(seed
, attribute
.bindingSlot
);
309 CRenderer::CRenderer()
311 TIMER(L
"InitRenderer");
313 m
= std::make_unique
<Internals
>();
315 g_ProfileViewer
.AddRootTable(&m
->profileTable
);
322 // Create terrain related stuff.
323 new CTerrainTextureManager
;
325 Open(g_xres
, g_yres
);
327 // Setup lighting environment. Since the Renderer accesses the
328 // lighting environment through a pointer, this has to be done before
330 GetSceneRenderer().SetLightEnv(&g_LightEnv
);
332 ModelDefActivateFastImpl();
333 ColorActivateFastImpl();
334 ModelRenderer::Init();
337 CRenderer::~CRenderer()
341 // We no longer UnloadWaterTextures here -
342 // that is the responsibility of the module that asked for
343 // them to be loaded (i.e. CGameView).
347 void CRenderer::ReloadShaders()
351 m
->sceneRenderer
.ReloadShaders();
352 m
->ShadersDirty
= false;
355 bool CRenderer::Open(int width
, int height
)
363 // Validate the currently selected render path
364 SetRenderPath(g_RenderingOptions
.GetRenderPath());
366 m
->debugRenderer
.Initialize();
368 if (m
->postprocManager
.IsEnabled())
369 m
->postprocManager
.Initialize();
371 m
->sceneRenderer
.Initialize();
376 void CRenderer::Resize(int width
, int height
)
381 m
->postprocManager
.Resize();
383 m
->sceneRenderer
.Resize(width
, height
);
386 void CRenderer::SetRenderPath(RenderPath rp
)
390 // Delay until Open() is called.
394 // Renderer has been opened, so validate the selected renderpath
395 const bool hasShadersSupport
=
396 g_VideoMode
.GetBackendDevice()->GetCapabilities().ARBShaders
||
397 g_VideoMode
.GetBackendDevice()->GetBackend() != Renderer::Backend::Backend::GL_ARB
;
398 if (rp
== RenderPath::DEFAULT
)
400 if (hasShadersSupport
)
401 rp
= RenderPath::SHADER
;
403 rp
= RenderPath::FIXED
;
406 if (rp
== RenderPath::SHADER
)
408 if (!hasShadersSupport
)
410 LOGWARNING("Falling back to fixed function\n");
411 rp
= RenderPath::FIXED
;
415 // TODO: remove this once capabilities have been properly extracted and the above checks have been moved elsewhere.
416 g_RenderingOptions
.m_RenderPath
= rp
;
421 bool CRenderer::ShouldRender() const
423 return !g_app_minimized
&& (g_app_has_focus
|| !g_VideoMode
.IsInFullscreen());
426 void CRenderer::RenderFrame(const bool needsPresent
)
428 // Do not render if not focused while in fullscreen or minimised,
429 // as that triggers a difficult-to-reproduce crash on some graphic cards.
433 if (m_ScreenShotType
== ScreenShotType::BIG
)
435 RenderBigScreenShot(needsPresent
);
437 else if (m_ScreenShotType
== ScreenShotType::DEFAULT
)
439 RenderScreenShot(needsPresent
);
445 // In case of no acquired backbuffer we have nothing render to.
446 if (!g_VideoMode
.GetBackendDevice()->AcquireNextBackbuffer())
450 if (m_ShouldPreloadResourcesBeforeNextFrame
)
452 m_ShouldPreloadResourcesBeforeNextFrame
= false;
453 // We don't need to render logger for the preload.
454 RenderFrameImpl(true, false);
457 RenderFrameImpl(true, true);
459 m
->deviceCommandContext
->Flush();
461 g_VideoMode
.GetBackendDevice()->Present();
465 void CRenderer::RenderFrameImpl(const bool renderGUI
, const bool renderLogger
)
469 g_Profiler2
.RecordGPUFrameStart();
471 g_TexMan
.UploadResourcesIfNeeded(m
->deviceCommandContext
.get());
473 m
->textureManager
.MakeUploadProgress(m
->deviceCommandContext
.get());
475 // prepare before starting the renderer frame
476 if (g_Game
&& g_Game
->IsGameStarted())
477 g_Game
->GetView()->BeginFrame();
480 m
->sceneRenderer
.SetSimulation(g_Game
->GetSimulation2());
485 if (g_Game
&& g_Game
->IsGameStarted())
487 g_Game
->GetView()->Prepare(m
->deviceCommandContext
.get());
489 Renderer::Backend::IFramebuffer
* framebuffer
= nullptr;
491 CPostprocManager
& postprocManager
= g_Renderer
.GetPostprocManager();
492 if (postprocManager
.IsEnabled())
494 // We have to update the post process manager with real near/far planes
495 // that we use for the scene rendering.
496 postprocManager
.SetDepthBufferClipPlanes(
497 m
->sceneRenderer
.GetViewCamera().GetNearPlane(),
498 m
->sceneRenderer
.GetViewCamera().GetFarPlane()
500 postprocManager
.Initialize();
501 framebuffer
= postprocManager
.PrepareAndGetOutputFramebuffer();
505 // We don't need to clear the color attachment of the framebuffer as the sky
506 // is going to be rendered anyway.
508 m
->deviceCommandContext
->GetDevice()->GetCurrentBackbuffer(
509 Renderer::Backend::AttachmentLoadOp::DONT_CARE
,
510 Renderer::Backend::AttachmentStoreOp::STORE
,
511 Renderer::Backend::AttachmentLoadOp::CLEAR
,
512 Renderer::Backend::AttachmentStoreOp::DONT_CARE
);
515 m
->deviceCommandContext
->BeginFramebufferPass(framebuffer
);
517 Renderer::Backend::IDeviceCommandContext::Rect viewportRect
{};
518 viewportRect
.width
= framebuffer
->GetWidth();
519 viewportRect
.height
= framebuffer
->GetHeight();
520 m
->deviceCommandContext
->SetViewports(1, &viewportRect
);
522 g_Game
->GetView()->Render(m
->deviceCommandContext
.get());
524 if (postprocManager
.IsEnabled())
526 m
->deviceCommandContext
->EndFramebufferPass();
528 if (postprocManager
.IsMultisampleEnabled())
529 postprocManager
.ResolveMultisampleFramebuffer(m
->deviceCommandContext
.get());
531 postprocManager
.ApplyPostproc(m
->deviceCommandContext
.get());
533 Renderer::Backend::IFramebuffer
* backbuffer
=
534 m
->deviceCommandContext
->GetDevice()->GetCurrentBackbuffer(
535 Renderer::Backend::AttachmentLoadOp::LOAD
,
536 Renderer::Backend::AttachmentStoreOp::STORE
,
537 Renderer::Backend::AttachmentLoadOp::LOAD
,
538 Renderer::Backend::AttachmentStoreOp::DONT_CARE
);
539 postprocManager
.BlitOutputFramebuffer(
540 m
->deviceCommandContext
.get(), backbuffer
);
542 m
->deviceCommandContext
->BeginFramebufferPass(backbuffer
);
544 Renderer::Backend::IDeviceCommandContext::Rect viewportRect
{};
545 viewportRect
.width
= backbuffer
->GetWidth();
546 viewportRect
.height
= backbuffer
->GetHeight();
547 m
->deviceCommandContext
->SetViewports(1, &viewportRect
);
550 g_Game
->GetView()->RenderOverlays(m
->deviceCommandContext
.get());
552 g_Game
->GetView()->GetCinema()->Render();
556 // We have a fullscreen background in our UI so we don't need
557 // to clear the color attachment.
558 // We don't need a depth test to render so we don't care about the
559 // depth-stencil attachment content.
560 // In case of Atlas we don't have g_Game, so we still need to clear depth.
561 const Renderer::Backend::AttachmentLoadOp depthStencilLoadOp
=
562 g_AtlasGameLoop
&& g_AtlasGameLoop
->view
563 ? Renderer::Backend::AttachmentLoadOp::CLEAR
564 : Renderer::Backend::AttachmentLoadOp::DONT_CARE
;
565 Renderer::Backend::IFramebuffer
* backbuffer
=
566 m
->deviceCommandContext
->GetDevice()->GetCurrentBackbuffer(
567 Renderer::Backend::AttachmentLoadOp::DONT_CARE
,
568 Renderer::Backend::AttachmentStoreOp::STORE
,
570 Renderer::Backend::AttachmentStoreOp::DONT_CARE
);
571 m
->deviceCommandContext
->BeginFramebufferPass(backbuffer
);
573 Renderer::Backend::IDeviceCommandContext::Rect viewportRect
{};
574 viewportRect
.width
= backbuffer
->GetWidth();
575 viewportRect
.height
= backbuffer
->GetHeight();
576 m
->deviceCommandContext
->SetViewports(1, &viewportRect
);
579 // If we're in Atlas game view, render special tools
580 if (g_AtlasGameLoop
&& g_AtlasGameLoop
->view
)
582 g_AtlasGameLoop
->view
->DrawCinemaPathTool();
585 RenderFrame2D(renderGUI
, renderLogger
);
587 m
->deviceCommandContext
->EndFramebufferPass();
591 const Stats
& stats
= GetStats();
592 PROFILE2_ATTR("draw calls: %zu", stats
.m_DrawCalls
);
593 PROFILE2_ATTR("terrain tris: %zu", stats
.m_TerrainTris
);
594 PROFILE2_ATTR("water tris: %zu", stats
.m_WaterTris
);
595 PROFILE2_ATTR("model tris: %zu", stats
.m_ModelTris
);
596 PROFILE2_ATTR("overlay tris: %zu", stats
.m_OverlayTris
);
597 PROFILE2_ATTR("blend splats: %zu", stats
.m_BlendSplats
);
598 PROFILE2_ATTR("particles: %zu", stats
.m_Particles
);
600 g_Profiler2
.RecordGPUFrameEnd();
603 void CRenderer::RenderFrame2D(const bool renderGUI
, const bool renderLogger
)
605 CCanvas2D
canvas(g_xres
, g_yres
, g_VideoMode
.GetScale(), m
->deviceCommandContext
.get());
607 m
->sceneRenderer
.RenderTextOverlays(canvas
);
611 GPU_SCOPED_LABEL(m
->deviceCommandContext
.get(), "Render GUI");
612 // All GUI elements are drawn in Z order to render semi-transparent
613 // objects correctly.
617 // If we're in Atlas game view, render special overlays (e.g. editor bandbox).
618 if (g_AtlasGameLoop
&& g_AtlasGameLoop
->view
)
620 g_AtlasGameLoop
->view
->DrawOverlays(canvas
);
624 GPU_SCOPED_LABEL(m
->deviceCommandContext
.get(), "Render console");
625 g_Console
->Render(canvas
);
630 GPU_SCOPED_LABEL(m
->deviceCommandContext
.get(), "Render logger");
631 g_Logger
->Render(canvas
);
635 GPU_SCOPED_LABEL(m
->deviceCommandContext
.get(), "Render profiler");
636 // Profile information
637 g_ProfileViewer
.RenderProfile(canvas
);
641 void CRenderer::RenderScreenShot(const bool needsPresent
)
643 m_ScreenShotType
= ScreenShotType::NONE
;
645 // get next available numbered filename
646 // note: %04d -> always 4 digits, so sorting by filename works correctly.
647 const VfsPath
filenameFormat(L
"screenshots/screenshot%04d.png");
649 vfs::NextNumberedFilename(g_VFS
, filenameFormat
, g_NextScreenShotNumber
, filename
);
651 const size_t width
= static_cast<size_t>(g_xres
), height
= static_cast<size_t>(g_yres
);
652 const size_t bpp
= 24;
654 if (needsPresent
&& !g_VideoMode
.GetBackendDevice()->AcquireNextBackbuffer())
657 // Hide log messages and re-render
658 RenderFrameImpl(true, false);
660 const size_t img_size
= width
* height
* bpp
/ 8;
661 const size_t hdr_size
= tex_hdr_size(filename
);
662 std::shared_ptr
<u8
> buf
;
663 AllocateAligned(buf
, hdr_size
+ img_size
, maxSectorSize
);
664 void* img
= buf
.get() + hdr_size
;
666 if (t
.wrap(width
, height
, bpp
, TEX_BOTTOM_UP
, buf
, hdr_size
) < 0)
669 m
->deviceCommandContext
->ReadbackFramebufferSync(0, 0, width
, height
, img
);
670 m
->deviceCommandContext
->Flush();
672 g_VideoMode
.GetBackendDevice()->Present();
674 if (tex_write(&t
, filename
) == INFO::OK
)
677 g_VFS
->GetRealPath(filename
, realPath
);
679 LOGMESSAGERENDER(g_L10n
.Translate("Screenshot written to '%s'"), realPath
.string8());
682 CStr(g_L10n
.Translate("Screenshot written to '%s'") + "\n").c_str(),
683 realPath
.string8().c_str());
686 LOGERROR("Error writing screenshot to '%s'", filename
.string8());
689 void CRenderer::RenderBigScreenShot(const bool needsPresent
)
691 m_ScreenShotType
= ScreenShotType::NONE
;
693 // If the game hasn't started yet then use WriteScreenshot to generate the image.
695 return RenderScreenShot(needsPresent
);
697 int tiles
= 4, tileWidth
= 256, tileHeight
= 256;
698 CFG_GET_VAL("screenshot.tiles", tiles
);
699 CFG_GET_VAL("screenshot.tilewidth", tileWidth
);
700 CFG_GET_VAL("screenshot.tileheight", tileHeight
);
701 if (tiles
<= 0 || tileWidth
<= 0 || tileHeight
<= 0 || tileWidth
* tiles
% 4 != 0 || tileHeight
* tiles
% 4 != 0)
703 LOGWARNING("Invalid big screenshot size: tiles=%d tileWidth=%d tileHeight=%d", tiles
, tileWidth
, tileHeight
);
707 // get next available numbered filename
708 // note: %04d -> always 4 digits, so sorting by filename works correctly.
709 const VfsPath
filenameFormat(L
"screenshots/screenshot%04d.bmp");
711 vfs::NextNumberedFilename(g_VFS
, filenameFormat
, g_NextScreenShotNumber
, filename
);
713 // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and
714 // hope the screen is actually large enough for that.
715 ENSURE(g_xres
>= tileWidth
&& g_yres
>= tileHeight
);
717 const int imageWidth
= tileWidth
* tiles
, imageHeight
= tileHeight
* tiles
;
720 const size_t imageSize
= imageWidth
* imageHeight
* bpp
/ 8;
721 const size_t tileSize
= tileWidth
* tileHeight
* bpp
/ 8;
722 const size_t headerSize
= tex_hdr_size(filename
);
723 void* tileData
= malloc(tileSize
);
726 WARN_IF_ERR(ERR::NO_MEM
);
729 std::shared_ptr
<u8
> imageBuffer
;
730 AllocateAligned(imageBuffer
, headerSize
+ imageSize
, maxSectorSize
);
733 void* img
= imageBuffer
.get() + headerSize
;
734 if (t
.wrap(imageWidth
, imageHeight
, bpp
, TEX_BOTTOM_UP
, imageBuffer
, headerSize
) < 0)
740 CCamera oldCamera
= *g_Game
->GetView()->GetCamera();
742 // Resize various things so that the sizes and aspect ratios are correct
744 g_Renderer
.Resize(tileWidth
, tileHeight
);
745 SViewPort vp
= { 0, 0, tileWidth
, tileHeight
};
746 g_Game
->GetView()->SetViewport(vp
);
750 CMatrix3D projection
;
751 projection
.SetIdentity();
752 const float aspectRatio
= 1.0f
* tileWidth
/ tileHeight
;
753 for (int tileY
= 0; tileY
< tiles
; ++tileY
)
755 for (int tileX
= 0; tileX
< tiles
; ++tileX
)
757 // Adjust the camera to render the appropriate region
758 if (oldCamera
.GetProjectionType() == CCamera::ProjectionType::PERSPECTIVE
)
760 projection
.SetPerspectiveTile(oldCamera
.GetFOV(), aspectRatio
, oldCamera
.GetNearPlane(), oldCamera
.GetFarPlane(), tiles
, tileX
, tileY
);
762 g_Game
->GetView()->GetCamera()->SetProjection(projection
);
764 if (!needsPresent
|| g_VideoMode
.GetBackendDevice()->AcquireNextBackbuffer())
766 RenderFrameImpl(false, false);
768 m
->deviceCommandContext
->ReadbackFramebufferSync(0, 0, tileWidth
, tileHeight
, tileData
);
769 m
->deviceCommandContext
->Flush();
772 g_VideoMode
.GetBackendDevice()->Present();
775 // Copy the tile pixels into the main image
776 for (int y
= 0; y
< tileHeight
; ++y
)
778 void* dest
= static_cast<char*>(img
) + ((tileY
* tileHeight
+ y
) * imageWidth
+ (tileX
* tileWidth
)) * bpp
/ 8;
779 void* src
= static_cast<char*>(tileData
) + y
* tileWidth
* bpp
/ 8;
780 memcpy(dest
, src
, tileWidth
* bpp
/ 8);
785 // Restore the viewport settings
787 g_Renderer
.Resize(g_xres
, g_yres
);
788 SViewPort vp
= { 0, 0, g_xres
, g_yres
};
789 g_Game
->GetView()->SetViewport(vp
);
790 g_Game
->GetView()->GetCamera()->SetProjectionFromCamera(oldCamera
);
793 if (tex_write(&t
, filename
) == INFO::OK
)
796 g_VFS
->GetRealPath(filename
, realPath
);
798 LOGMESSAGERENDER(g_L10n
.Translate("Screenshot written to '%s'"), realPath
.string8());
801 CStr(g_L10n
.Translate("Screenshot written to '%s'") + "\n").c_str(),
802 realPath
.string8().c_str());
805 LOGERROR("Error writing screenshot to '%s'", filename
.string8());
810 void CRenderer::BeginFrame()
812 PROFILE("begin frame");
814 // Zero out all the per-frame stats.
820 m
->sceneRenderer
.BeginFrame();
823 void CRenderer::EndFrame()
825 PROFILE3("end frame");
827 m
->sceneRenderer
.EndFrame();
830 void CRenderer::MakeShadersDirty()
832 m
->ShadersDirty
= true;
833 m
->sceneRenderer
.MakeShadersDirty();
836 CTextureManager
& CRenderer::GetTextureManager()
838 return m
->textureManager
;
841 CShaderManager
& CRenderer::GetShaderManager()
843 return m
->shaderManager
;
846 CTimeManager
& CRenderer::GetTimeManager()
848 return m
->timeManager
;
851 CPostprocManager
& CRenderer::GetPostprocManager()
853 return m
->postprocManager
;
856 CSceneRenderer
& CRenderer::GetSceneRenderer()
858 return m
->sceneRenderer
;
861 CDebugRenderer
& CRenderer::GetDebugRenderer()
863 return m
->debugRenderer
;
866 CFontManager
& CRenderer::GetFontManager()
868 return m
->fontManager
;
871 void CRenderer::PreloadResourcesBeforeNextFrame()
873 m_ShouldPreloadResourcesBeforeNextFrame
= true;
876 void CRenderer::MakeScreenShotOnNextFrame(ScreenShotType screenShotType
)
878 m_ScreenShotType
= screenShotType
;
881 Renderer::Backend::IDeviceCommandContext
* CRenderer::GetDeviceCommandContext()
883 return m
->deviceCommandContext
.get();
886 Renderer::Backend::IVertexInputLayout
* CRenderer::GetVertexInputLayout(
887 const PS::span
<const Renderer::Backend::SVertexAttributeFormat
> attributes
)
889 const auto [it
, inserted
] = m
->vertexInputLayouts
.emplace(
890 std::vector
<Renderer::Backend::SVertexAttributeFormat
>{attributes
.begin(), attributes
.end()}, nullptr);
892 it
->second
= g_VideoMode
.GetBackendDevice()->CreateVertexInputLayout(attributes
);
893 return it
->second
.get();