1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-06 06:32:56 +01:00

Fix #7513: OpenRCT2 freezes on shutdown (#7514)

Store drawing engine and painter inside Context so that it is disposed before Context.
This commit is contained in:
Ted John
2018-05-13 15:52:59 +01:00
committed by GitHub
parent 3278fd55dc
commit 20fdd46b96
4 changed files with 187 additions and 117 deletions

View File

@@ -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> _titleScreen;
sint32 _drawingEngineType = DRAWING_ENGINE_SOFTWARE;
std::unique_ptr<IDrawingEngine> _drawingEngine;
std::unique_ptr<Painter> _painter;
bool _initialised = false;
bool _isWindowMinimised = false;
uint32 _lastTick = 0;
@@ -123,9 +131,9 @@ namespace OpenRCT2
const std::shared_ptr<IAudioContext>& audioContext,
const std::shared_ptr<IUiContext>& uiContext)
: _env(env),
_audioContext(audioContext),
_uiContext(uiContext),
_localisationService(std::make_shared<LocalisationService>(env))
_audioContext(audioContext),
_uiContext(uiContext),
_localisationService(std::make_shared<LocalisationService>(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<Painter>(_uiContext);
try
{
drawingEngine->Initialise();
drawingEngine->SetVSync(gConfigGeneral.use_vsync);
_drawingEngine = std::unique_ptr<IDrawingEngine>(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();
}

View File

@@ -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<IObjectRepository> 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;

View File

@@ -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<IDrawingEngine> _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<IDrawingEngine>(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;
}

View File

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