From 79459bcff36779cc81084c37cfff387eda55882d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Wed, 21 Aug 2024 18:04:53 +0200 Subject: [PATCH] Copy the result of rendering only if needed That is, only if the Renderer needs to immediately blast off to render another frame. If we run it on the main thread, we can just use its video buffer directly. --- src/gui/game/DecorationTool.cpp | 4 ++-- src/gui/game/DecorationTool.h | 7 ++++--- src/gui/game/GameModel.cpp | 14 +++++++------- src/gui/game/GameView.cpp | 17 ++++++++++------- src/gui/game/GameView.h | 7 ++++++- src/lua/LuaSimulation.cpp | 2 +- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/gui/game/DecorationTool.cpp b/src/gui/game/DecorationTool.cpp index d726e4afe..666a81397 100644 --- a/src/gui/game/DecorationTool.cpp +++ b/src/gui/game/DecorationTool.cpp @@ -1,9 +1,8 @@ #include "DecorationTool.h" - #include "graphics/Renderer.h" - #include "simulation/SimulationData.h" #include "simulation/Simulation.h" +#include "GameView.h" std::unique_ptr DecorationTool::GetIcon(int ToolID, Vec2 size) { @@ -54,6 +53,7 @@ void DecorationTool::DrawRect(Simulation * sim, Brush const &brush, ui::Point po void DecorationTool::DrawFill(Simulation * sim, Brush const &brush, ui::Point position) { + auto &rendererFrame = gameView->GetRendererFrame(); if (!rendererFrame.Size().OriginRect().Contains(position)) { return; diff --git a/src/gui/game/DecorationTool.h b/src/gui/game/DecorationTool.h index de61ca937..067100925 100644 --- a/src/gui/game/DecorationTool.h +++ b/src/gui/game/DecorationTool.h @@ -5,18 +5,19 @@ #include "graphics/RendererFrame.h" class Renderer; +class GameView; class DecorationTool: public Tool { public: RGBA Colour; - RendererFrame &rendererFrame; + GameView *gameView; std::unique_ptr GetIcon(int toolID, Vec2 size); - DecorationTool(RendererFrame &newRendererFrame, int decoMode, String name, String description, RGB colour, ByteString identifier): + DecorationTool(GameView *newGameView, int decoMode, String name, String description, RGB colour, ByteString identifier): Tool(decoMode, name, description, colour, identifier), Colour(0x000000_rgb .WithAlpha(0x00)), - rendererFrame(newRendererFrame) + gameView(newGameView) {} virtual ~DecorationTool() diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 130dcfcb2..8648932c5 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -396,13 +396,13 @@ void GameModel::BuildMenus() menuList[SC_LIFE]->AddTool(new GOLTool(*this)); //Add decoration tools to menu - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_ADD, "ADD", "Colour blending: Add.", 0x000000_rgb, "DEFAULT_DECOR_ADD")); - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_SUBTRACT, "SUB", "Colour blending: Subtract.", 0x000000_rgb, "DEFAULT_DECOR_SUB")); - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_MULTIPLY, "MUL", "Colour blending: Multiply.", 0x000000_rgb, "DEFAULT_DECOR_MUL")); - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_DIVIDE, "DIV", "Colour blending: Divide." , 0x000000_rgb, "DEFAULT_DECOR_DIV")); - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_SMUDGE, "SMDG", "Smudge tool, blends surrounding deco together.", 0x000000_rgb, "DEFAULT_DECOR_SMDG")); - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_CLEAR, "CLR", "Erase any set decoration.", 0x000000_rgb, "DEFAULT_DECOR_CLR")); - menuList[SC_DECO]->AddTool(new DecorationTool(view->rendererFrame, DECO_DRAW, "SET", "Draw decoration (No blending).", 0x000000_rgb, "DEFAULT_DECOR_SET")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_ADD, "ADD", "Colour blending: Add.", 0x000000_rgb, "DEFAULT_DECOR_ADD")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_SUBTRACT, "SUB", "Colour blending: Subtract.", 0x000000_rgb, "DEFAULT_DECOR_SUB")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_MULTIPLY, "MUL", "Colour blending: Multiply.", 0x000000_rgb, "DEFAULT_DECOR_MUL")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_DIVIDE, "DIV", "Colour blending: Divide." , 0x000000_rgb, "DEFAULT_DECOR_DIV")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_SMUDGE, "SMDG", "Smudge tool, blends surrounding deco together.", 0x000000_rgb, "DEFAULT_DECOR_SMDG")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_CLEAR, "CLR", "Erase any set decoration.", 0x000000_rgb, "DEFAULT_DECOR_CLR")); + menuList[SC_DECO]->AddTool(new DecorationTool(view, DECO_DRAW, "SET", "Draw decoration (No blending).", 0x000000_rgb, "DEFAULT_DECOR_SET")); SetColourSelectorColour(colour); // update tool colors decoToolset[0] = GetToolFromIdentifier("DEFAULT_DECOR_SET"); decoToolset[1] = GetToolFromIdentifier("DEFAULT_DECOR_CLR"); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index b25a77094..259f85985 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -734,6 +734,7 @@ void GameView::NotifyColourSelectorColourChanged(GameModel * sender) void GameView::NotifyRendererChanged(GameModel * sender) { ren = sender->GetRenderer(); + rendererFrame = &ren->GetVideo(); rendererSettings = &sender->GetRendererSettings(); } @@ -916,7 +917,7 @@ ByteString GameView::TakeScreenshot(int captureUI, int fileType) std::unique_ptr screenshot; if (captureUI) { - screenshot = std::make_unique(rendererFrame); + screenshot = std::make_unique(*rendererFrame); } else { @@ -2158,7 +2159,8 @@ void GameView::OnDraw() { StartRendererThread(); WaitForRendererThread(); - rendererFrame = ren->GetVideo(); + *rendererThreadResult = ren->GetVideo(); + rendererFrame = rendererThreadResult.get(); DispatchRendererThread(); } else @@ -2166,10 +2168,10 @@ void GameView::OnDraw() PauseRendererThread(); ren->ApplySettings(*rendererSettings); RenderSimulation(*sim, true); - rendererFrame = ren->GetVideo(); + rendererFrame = &ren->GetVideo(); } - std::copy_n(rendererFrame.data(), rendererFrame.Size().X * rendererFrame.Size().Y, g->Data()); + std::copy_n(rendererFrame->data(), rendererFrame->Size().X * rendererFrame->Size().Y, g->Data()); if (showBrush && selectMode == SelectNone && (!zoomEnabled || zoomCursorFixed) && activeBrush && (isMouseDown || (currentMouse.X >= 0 && currentMouse.X < XRES && currentMouse.Y >= 0 && currentMouse.Y < YRES))) { @@ -2284,7 +2286,7 @@ void GameView::OnDraw() if(recording) { - std::vector data = VideoBuffer(rendererFrame).ToPPM(); + std::vector data = VideoBuffer(*rendererFrame).ToPPM(); ByteString filename = ByteString::Build("recordings", PATH_SEP_CHAR, recordingFolder, PATH_SEP_CHAR, "frame_", Format::Width(recordingIndex++, 6), ".ppm"); @@ -2609,11 +2611,11 @@ std::optional GameView::FindingElementCandidate() const pixel GameView::GetPixelUnderMouse() const { auto point = c->PointTranslate(currentMouse); - if (!rendererFrame.Size().OriginRect().Contains(point)) + if (!rendererFrame->Size().OriginRect().Contains(point)) { return 0; } - return rendererFrame[point]; + return (*rendererFrame)[point]; } void GameView::RendererThread() @@ -2645,6 +2647,7 @@ void GameView::StartRendererThread() if (rendererThreadState == rendererThreadAbsent) { rendererThreadSim = std::make_unique(); + rendererThreadResult = std::make_unique(); rendererThreadState = rendererThreadRunning; start = true; } diff --git a/src/gui/game/GameView.h b/src/gui/game/GameView.h index 3fe832a54..096ce3754 100644 --- a/src/gui/game/GameView.h +++ b/src/gui/game/GameView.h @@ -171,6 +171,8 @@ private: void WaitForRendererThread(); void DispatchRendererThread(); std::unique_ptr rendererThreadSim; + std::unique_ptr rendererThreadResult; + const RendererFrame *rendererFrame = nullptr; public: GameView(); @@ -261,7 +263,10 @@ public: void SkipIntroText(); pixel GetPixelUnderMouse() const; - RendererFrame rendererFrame; + const RendererFrame &GetRendererFrame() const + { + return *rendererFrame; + } // Call this before accessing Renderer "out of turn", e.g. from RenderView. This *does not* // include OptionsModel or Lua setting functions because they only access the RendererSettings // in GameModel, or Lua drawing functions because they only access Renderer in eventTraitSimGraphics diff --git a/src/lua/LuaSimulation.cpp b/src/lua/LuaSimulation.cpp index 7ab9fdaff..a90cab363 100644 --- a/src/lua/LuaSimulation.cpp +++ b/src/lua/LuaSimulation.cpp @@ -834,7 +834,7 @@ static int floodDeco(lua_State *L) auto *lsi = GetLSI(); // hilariously broken, intersects with console and all Lua graphics - auto &rendererFrame = lsi->gameModel->view->rendererFrame; + auto &rendererFrame = lsi->gameModel->view->GetRendererFrame(); auto loc = RGB::Unpack(rendererFrame[{ x, y }]); lsi->sim->ApplyDecorationFill(rendererFrame, x, y, r, g, b, a, loc.Red, loc.Green, loc.Blue); return 0;