From 20fdd46b96f08491efc7a32325598c5245c89633 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 13 May 2018 15:52:59 +0100 Subject: [PATCH] Fix #7513: OpenRCT2 freezes on shutdown (#7514) Store drawing engine and painter inside Context so that it is disposed before Context. --- src/openrct2/Context.cpp | 99 +++++++++++++- src/openrct2/Context.h | 9 ++ src/openrct2/drawing/NewDrawing.cpp | 195 ++++++++++++---------------- src/openrct2/drawing/NewDrawing.h | 1 - 4 files changed, 187 insertions(+), 117 deletions(-) diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 098b870f84..f09f37de80 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -35,12 +35,14 @@ #include "core/Path.hpp" #include "core/String.hpp" #include "core/Util.hpp" +#include "drawing/IDrawingEngine.h" #include "FileClassifier.h" #include "HandleParkLoad.h" #include "network/network.h" #include "object/ObjectManager.h" #include "object/ObjectRepository.h" #include "OpenRCT2.h" +#include "paint/Painter.h" #include "ParkImporter.h" #include "platform/Crash.h" #include "PlatformEnvironment.h" @@ -74,7 +76,9 @@ using namespace OpenRCT2; using namespace OpenRCT2::Audio; +using namespace OpenRCT2::Drawing; using namespace OpenRCT2::Localisation; +using namespace OpenRCT2::Paint; using namespace OpenRCT2::Ui; namespace OpenRCT2 @@ -101,6 +105,10 @@ namespace OpenRCT2 // Game states std::unique_ptr _titleScreen; + sint32 _drawingEngineType = DRAWING_ENGINE_SOFTWARE; + std::unique_ptr _drawingEngine; + std::unique_ptr _painter; + bool _initialised = false; bool _isWindowMinimised = false; uint32 _lastTick = 0; @@ -123,9 +131,9 @@ namespace OpenRCT2 const std::shared_ptr& audioContext, const std::shared_ptr& uiContext) : _env(env), - _audioContext(audioContext), - _uiContext(uiContext), - _localisationService(std::make_shared(env)) + _audioContext(audioContext), + _uiContext(uiContext), + _localisationService(std::make_shared(env)) { Instance = this; } @@ -186,6 +194,16 @@ namespace OpenRCT2 return _scenarioRepository.get(); } + sint32 GetDrawingEngineType() override + { + return _drawingEngineType; + } + + IDrawingEngine * GetDrawingEngine() override + { + return _drawingEngine.get(); + } + sint32 RunOpenRCT2(int argc, const char * * argv) override { if (Initialise()) @@ -429,6 +447,73 @@ namespace OpenRCT2 return true; } + void InitialiseDrawingEngine() final override + { + assert(_drawingEngine == nullptr); + assert(_painter == nullptr); + + _drawingEngineType = gConfigGeneral.drawing_engine; + + auto drawingEngineFactory = _uiContext->GetDrawingEngineFactory(); + auto drawingEngine = drawingEngineFactory->Create((DRAWING_ENGINE_TYPE)_drawingEngineType, _uiContext); + + if (drawingEngine == nullptr) + { + if (_drawingEngineType == DRAWING_ENGINE_SOFTWARE) + { + _drawingEngineType = DRAWING_ENGINE_NONE; + log_fatal("Unable to create a drawing engine."); + exit(-1); + } + else + { + log_error("Unable to create drawing engine. Falling back to software."); + + // Fallback to software + gConfigGeneral.drawing_engine = DRAWING_ENGINE_SOFTWARE; + config_save_default(); + drawing_engine_init(); + } + } + else + { + _painter = std::make_unique(_uiContext); + try + { + drawingEngine->Initialise(); + drawingEngine->SetVSync(gConfigGeneral.use_vsync); + _drawingEngine = std::unique_ptr(std::move(drawingEngine)); + } + catch (const std::exception &ex) + { + _painter = nullptr; + if (_drawingEngineType == DRAWING_ENGINE_SOFTWARE) + { + _drawingEngineType = DRAWING_ENGINE_NONE; + log_error(ex.what()); + log_fatal("Unable to initialise a drawing engine."); + exit(-1); + } + else + { + log_error(ex.what()); + log_error("Unable to initialise drawing engine. Falling back to software."); + + // Fallback to software + gConfigGeneral.drawing_engine = DRAWING_ENGINE_SOFTWARE; + config_save_default(); + drawing_engine_init(); + } + } + } + } + + void DisposeDrawingEngine() final override + { + _drawingEngine = nullptr; + _painter = nullptr; + } + bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail) final override { try @@ -767,7 +852,9 @@ namespace OpenRCT2 Update(); if (!_isWindowMinimised && !gOpenRCT2Headless) { - drawing_engine_draw(); + _drawingEngine->BeginDraw(); + _painter->Paint(*_drawingEngine); + _drawingEngine->EndDraw(); } } @@ -810,7 +897,9 @@ namespace OpenRCT2 const float alpha = (float)_accumulator / GAME_UPDATE_TIME_MS; sprite_position_tween_all(alpha); - drawing_engine_draw(); + _drawingEngine->BeginDraw(); + _painter->Paint(*_drawingEngine); + _drawingEngine->EndDraw(); sprite_position_tween_restore(); } diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index 846ff3efd3..15b9a51854 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -77,6 +77,11 @@ namespace OpenRCT2 interface IAudioContext; } + namespace Drawing + { + interface IDrawingEngine; + } + namespace Localisation { class LocalisationService; @@ -102,10 +107,14 @@ namespace OpenRCT2 virtual std::shared_ptr GetObjectRepository() abstract; virtual ITrackDesignRepository * GetTrackDesignRepository() abstract; virtual IScenarioRepository * GetScenarioRepository() abstract; + virtual sint32 GetDrawingEngineType() abstract; + virtual Drawing::IDrawingEngine * GetDrawingEngine() abstract; virtual sint32 RunOpenRCT2(int argc, const char * * argv) abstract; virtual bool Initialise() abstract; + virtual void InitialiseDrawingEngine() abstract; + virtual void DisposeDrawingEngine() abstract; virtual bool LoadParkFromFile(const std::string &path, bool loadTitleScreenOnFail = false) abstract; virtual bool LoadParkFromStream(IStream * stream, const std::string &path, bool loadTitleScreenFirstOnFail = false) abstract; virtual void WriteLine(const std::string &s) abstract; diff --git a/src/openrct2/drawing/NewDrawing.cpp b/src/openrct2/drawing/NewDrawing.cpp index 32a4e71605..d3e5377ba5 100644 --- a/src/openrct2/drawing/NewDrawing.cpp +++ b/src/openrct2/drawing/NewDrawing.cpp @@ -31,11 +31,6 @@ using namespace OpenRCT2::Drawing; using namespace OpenRCT2::Paint; using namespace OpenRCT2::Ui; -static sint32 _drawingEngineType = DRAWING_ENGINE_SOFTWARE; -static std::shared_ptr _drawingEngine; -// TODO move this to Context -static Painter * _painter = nullptr; - rct_string_id DrawingEngineStringIds[] = { STR_DRAWING_ENGINE_SOFTWARE, @@ -45,7 +40,19 @@ rct_string_id DrawingEngineStringIds[] = sint32 drawing_engine_get_type() { - return _drawingEngineType; + auto context = GetContext(); + return context->GetDrawingEngineType(); +} + +static IDrawingEngine * GetDrawingEngine() +{ + IDrawingEngine * result = nullptr; + auto context = GetContext(); + if (context != nullptr) + { + result = context->GetDrawingEngine(); + } + return result; } bool drawing_engine_requires_new_window(sint32 srcEngine, sint32 dstEngine) @@ -64,147 +71,104 @@ bool drawing_engine_requires_new_window(sint32 srcEngine, sint32 dstEngine) void drawing_engine_init() { - assert(_drawingEngine == nullptr); - assert(_painter == nullptr); - - _drawingEngineType = gConfigGeneral.drawing_engine; - auto context = GetContext(); - auto uiContext = context->GetUiContext(); - auto drawingEngineFactory = uiContext->GetDrawingEngineFactory(); - auto drawingEngine = drawingEngineFactory->Create((DRAWING_ENGINE_TYPE)_drawingEngineType, uiContext); - - if (drawingEngine == nullptr) + if (context != nullptr) { - if (_drawingEngineType == DRAWING_ENGINE_SOFTWARE) - { - _drawingEngineType = DRAWING_ENGINE_NONE; - log_fatal("Unable to create a drawing engine."); - exit(-1); - } - else - { - log_error("Unable to create drawing engine. Falling back to software."); - - // Fallback to software - gConfigGeneral.drawing_engine = DRAWING_ENGINE_SOFTWARE; - config_save_default(); - drawing_engine_init(); - } - } - else - { - _painter = new Painter(uiContext); - try - { - drawingEngine->Initialise(); - drawingEngine->SetVSync(gConfigGeneral.use_vsync); - _drawingEngine = std::shared_ptr(std::move(drawingEngine)); - } - catch (const std::exception &ex) - { - delete _painter; - _painter = nullptr; - if (_drawingEngineType == DRAWING_ENGINE_SOFTWARE) - { - _drawingEngineType = DRAWING_ENGINE_NONE; - log_error(ex.what()); - log_fatal("Unable to initialise a drawing engine."); - exit(-1); - } - else - { - log_error(ex.what()); - log_error("Unable to initialise drawing engine. Falling back to software."); - - // Fallback to software - gConfigGeneral.drawing_engine = DRAWING_ENGINE_SOFTWARE; - config_save_default(); - drawing_engine_init(); - } - } + context->InitialiseDrawingEngine(); } } void drawing_engine_resize() { - if (_drawingEngine != nullptr) + auto context = GetContext(); + if (context != nullptr) { - auto uiContext = GetContext()->GetUiContext(); - _drawingEngine->Resize(uiContext->GetWidth(), uiContext->GetHeight()); + auto drawingEngine = context->GetDrawingEngine(); + if (drawingEngine != nullptr) + { + auto uiContext = context->GetUiContext(); + drawingEngine->Resize(uiContext->GetWidth(), uiContext->GetHeight()); + } } } void drawing_engine_set_palette(const rct_palette_entry * colours) { - if (_drawingEngine != nullptr) + auto context = GetContext(); + if (context != nullptr) { - _drawingEngine->SetPalette(colours); - } -} - -void drawing_engine_draw() -{ - if (_drawingEngine != nullptr && _painter != nullptr) - { - _drawingEngine->BeginDraw(); - _painter->Paint(*_drawingEngine); - _drawingEngine->EndDraw(); + auto drawingEngine = context->GetDrawingEngine(); + if (drawingEngine != nullptr) + { + drawingEngine->SetPalette(colours); + } } } void drawing_engine_copy_rect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) { - if (_drawingEngine != nullptr) + auto context = GetContext(); + if (context != nullptr) { - _drawingEngine->CopyRect(x, y, width, height, dx, dy); + auto drawingEngine = context->GetDrawingEngine(); + if (drawingEngine != nullptr) + { + drawingEngine->CopyRect(x, y, width, height, dx, dy); + } } } void drawing_engine_dispose() { - delete _painter; - _drawingEngine = nullptr; - _painter = nullptr; + auto context = GetContext(); + if (context != nullptr) + { + context->DisposeDrawingEngine(); + } } rct_drawpixelinfo * drawing_engine_get_dpi() { - assert(_drawingEngine != nullptr); - return _drawingEngine->GetDrawingPixelInfo(); + auto context = GetContext(); + auto drawingEngine = context->GetDrawingEngine(); + return drawingEngine->GetDrawingPixelInfo(); } bool drawing_engine_has_dirty_optimisations() { bool result = false; - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - result = (_drawingEngine->GetFlags() & DEF_DIRTY_OPTIMISATIONS); + result = (drawingEngine->GetFlags() & DEF_DIRTY_OPTIMISATIONS); } return result; } void drawing_engine_invalidate_image(uint32 image) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - _drawingEngine->InvalidateImage(image); + drawingEngine->InvalidateImage(image); } } void drawing_engine_set_vsync(bool vsync) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - _drawingEngine->SetVSync(vsync); + drawingEngine->SetVSync(vsync); } } void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - _drawingEngine->Invalidate(left, top, right, bottom); + drawingEngine->Invalidate(left, top, right, bottom); } } @@ -214,81 +178,90 @@ void gfx_draw_all_dirty_blocks() void gfx_clear(rct_drawpixelinfo * dpi, uint8 paletteIndex) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->Clear(paletteIndex); } } void gfx_fill_rect(rct_drawpixelinfo * dpi, sint32 left, sint32 top, sint32 right, sint32 bottom, sint32 colour) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->FillRect(colour, left, top, right, bottom); } } void gfx_filter_rect(rct_drawpixelinfo * dpi, sint32 left, sint32 top, sint32 right, sint32 bottom, FILTER_PALETTE_ID palette) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->FilterRect(palette, left, top, right, bottom); } } void gfx_draw_line(rct_drawpixelinfo *dpi, sint32 x1, sint32 y1, sint32 x2, sint32 y2, sint32 colour) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->DrawLine(colour, x1, y1, x2, y2); } } void FASTCALL gfx_draw_sprite(rct_drawpixelinfo * dpi, sint32 image, sint32 x, sint32 y, uint32 tertiary_colour) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->DrawSprite(image, x, y, tertiary_colour); } } void FASTCALL gfx_draw_glpyh(rct_drawpixelinfo * dpi, sint32 image, sint32 x, sint32 y, uint8 * palette) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->DrawGlyph(image, x, y, palette); } } void FASTCALL gfx_draw_sprite_raw_masked(rct_drawpixelinfo * dpi, sint32 x, sint32 y, sint32 maskImage, sint32 colourImage) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->DrawSpriteRawMasked(x, y, maskImage, colourImage); } } void FASTCALL gfx_draw_sprite_solid(rct_drawpixelinfo * dpi, sint32 image, sint32 x, sint32 y, uint8 colour) { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - IDrawingContext * dc = _drawingEngine->GetDrawingContext(dpi); + IDrawingContext * dc = drawingEngine->GetDrawingContext(dpi); dc->DrawSpriteSolid(image, x, y, colour); } } sint32 screenshot_dump() { - if (_drawingEngine != nullptr) + auto drawingEngine = GetDrawingEngine(); + if (drawingEngine != nullptr) { - return _drawingEngine->Screenshot(); + return drawingEngine->Screenshot(); } return false; } diff --git a/src/openrct2/drawing/NewDrawing.h b/src/openrct2/drawing/NewDrawing.h index 244bd3fca3..1d5e791d09 100644 --- a/src/openrct2/drawing/NewDrawing.h +++ b/src/openrct2/drawing/NewDrawing.h @@ -28,7 +28,6 @@ bool drawing_engine_requires_new_window(sint32 srcEngine, sint32 dstEngine); void drawing_engine_init(); void drawing_engine_resize(); void drawing_engine_set_palette(const rct_palette_entry * colours); -void drawing_engine_draw(); void drawing_engine_copy_rect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy); void drawing_engine_dispose();