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.
This commit is contained in:
Tamás Bálint Misius
2024-08-21 18:04:53 +02:00
parent eb29d5a9dd
commit 79459bcff3
6 changed files with 30 additions and 21 deletions

View File

@@ -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<VideoBuffer> DecorationTool::GetIcon(int ToolID, Vec2<int> 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;

View File

@@ -5,18 +5,19 @@
#include "graphics/RendererFrame.h"
class Renderer;
class GameView;
class DecorationTool: public Tool
{
public:
RGBA<uint8_t> Colour;
RendererFrame &rendererFrame;
GameView *gameView;
std::unique_ptr<VideoBuffer> GetIcon(int toolID, Vec2<int> size);
DecorationTool(RendererFrame &newRendererFrame, int decoMode, String name, String description, RGB<uint8_t> colour, ByteString identifier):
DecorationTool(GameView *newGameView, int decoMode, String name, String description, RGB<uint8_t> colour, ByteString identifier):
Tool(decoMode, name, description, colour, identifier),
Colour(0x000000_rgb .WithAlpha(0x00)),
rendererFrame(newRendererFrame)
gameView(newGameView)
{}
virtual ~DecorationTool()

View File

@@ -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");

View File

@@ -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<VideoBuffer> screenshot;
if (captureUI)
{
screenshot = std::make_unique<VideoBuffer>(rendererFrame);
screenshot = std::make_unique<VideoBuffer>(*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<char> data = VideoBuffer(rendererFrame).ToPPM();
std::vector<char> 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<FindingElement> 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<RenderableSimulation>();
rendererThreadResult = std::make_unique<RendererFrame>();
rendererThreadState = rendererThreadRunning;
start = true;
}

View File

@@ -171,6 +171,8 @@ private:
void WaitForRendererThread();
void DispatchRendererThread();
std::unique_ptr<RenderableSimulation> rendererThreadSim;
std::unique_ptr<RendererFrame> 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

View File

@@ -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<uint8_t>::Unpack(rendererFrame[{ x, y }]);
lsi->sim->ApplyDecorationFill(rendererFrame, x, y, r, g, b, a, loc.Red, loc.Green, loc.Blue);
return 0;