Skip to content

Commit

Permalink
Merge pull request #8481 from ZehMatt/multicore-rendering
Browse files Browse the repository at this point in the history
Implement partial multicore rendering
  • Loading branch information
janisozaur committed Apr 2, 2019
2 parents 6b9e36f + 313117f commit 2fb3191
Show file tree
Hide file tree
Showing 47 changed files with 289 additions and 179 deletions.
2 changes: 2 additions & 0 deletions data/language/en-GB.txt
Expand Up @@ -3751,6 +3751,8 @@ STR_6301 :{SMALLFONT}{BLACK}Copy the selected object name to the clipboard.
STR_6302 :{SMALLFONT}{BLACK}Copy the entire list of missing objects to the clipboard.
STR_6303 :Downloading object ({COMMA16} / {COMMA16}): [{STRING}]
STR_6304 :Open scenery picker
STR_6305 :Multithreading
STR_6306 :{SMALLFONT}{BLACK}Use multiple threads to render

#############
# Scenarios #
Expand Down
1 change: 1 addition & 0 deletions distribution/changelog.txt
@@ -1,6 +1,7 @@
0.2.2+ (in development)
------------------------------------------------------------------------
- Feature: [#7296] Allow assigning a keyboard shortcut for the scenery picker.
- Feature: [#8481] Multi-threaded rendering.
- Feature: [#8919] Allow setting ride price from console.
- Feature: [#8963] Add missing Czech letters to sprite font, use sprite font for Czech.
- Change: [#8688] Move common actions from debug menu into cheats menu.
Expand Down
51 changes: 36 additions & 15 deletions src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp
Expand Up @@ -30,6 +30,8 @@ TextureCache::~TextureCache()

void TextureCache::InvalidateImage(uint32_t image)
{
unique_lock lock(_mutex);

uint32_t index = _indexMap[image];
if (index == UNUSED_INDEX)
return;
Expand Down Expand Up @@ -61,18 +63,28 @@ void TextureCache::InvalidateImage(uint32_t image)

BasicTextureInfo TextureCache::GetOrLoadImageTexture(uint32_t image)
{
uint32_t index;

image &= 0x7FFFF;

uint32_t index = _indexMap[image];
if (index != UNUSED_INDEX)
// Try to read cached texture first.
{
const auto& info = _textureCache[index];
return {
info.index,
info.normalizedBounds,
};
shared_lock lock(_mutex);

index = _indexMap[image];
if (index != UNUSED_INDEX)
{
const auto& info = _textureCache[index];
return {
info.index,
info.normalizedBounds,
};
}
}

// Load new texture.
unique_lock lock(_mutex);

index = (uint32_t)_textureCache.size();

AtlasTextureInfo info = LoadImageTexture(image);
Expand All @@ -87,18 +99,27 @@ BasicTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32_t image, uint8_t* pa
{
GlyphId glyphId;
glyphId.Image = image;
std::copy_n(palette, sizeof(glyphId.Palette), (uint8_t*)&glyphId.Palette);

auto kvp = _glyphTextureMap.find(glyphId);
if (kvp != _glyphTextureMap.end())
// Try to read cached texture first.
{
const auto& info = kvp->second;
return {
info.index,
info.normalizedBounds,
};
shared_lock lock(_mutex);

std::copy_n(palette, sizeof(glyphId.Palette), (uint8_t*)&glyphId.Palette);

auto kvp = _glyphTextureMap.find(glyphId);
if (kvp != _glyphTextureMap.end())
{
const auto& info = kvp->second;
return {
info.index,
info.normalizedBounds,
};
}
}

// Load new texture.
unique_lock lock(_mutex);

auto cacheInfo = LoadGlyphTexture(image, palette);
auto it = _glyphTextureMap.insert(std::make_pair(glyphId, cacheInfo));

Expand Down
14 changes: 14 additions & 0 deletions src/openrct2-ui/drawing/engines/opengl/TextureCache.h
Expand Up @@ -15,7 +15,11 @@
#include <SDL_pixels.h>
#include <algorithm>
#include <array>
#include <mutex>
#include <openrct2/common.h>
#ifndef __MACOSX__
# include <shared_mutex>
#endif
#include <unordered_map>
#include <vector>

Expand Down Expand Up @@ -199,6 +203,16 @@ class TextureCache final

GLuint _paletteTexture = 0;

#ifndef __MACOSX__
std::shared_mutex _mutex;
typedef std::shared_lock<std::shared_mutex> shared_lock;
typedef std::unique_lock<std::shared_mutex> unique_lock;
#else
std::mutex _mutex;
typedef std::unique_lock<std::mutex> shared_lock;
typedef std::unique_lock<std::mutex> unique_lock;
#endif

public:
TextureCache();
~TextureCache();
Expand Down
11 changes: 10 additions & 1 deletion src/openrct2-ui/windows/Options.cpp
Expand Up @@ -87,6 +87,7 @@ enum WINDOW_OPTIONS_WIDGET_IDX {
WIDX_STEAM_OVERLAY_PAUSE,
WIDX_UNCAP_FPS_CHECKBOX,
WIDX_SHOW_FPS_CHECKBOX,
WIDX_MULTITHREADING_CHECKBOX,
WIDX_USE_VSYNC_CHECKBOX,
WIDX_MINIMIZE_FOCUS_LOSS,

Expand Down Expand Up @@ -236,7 +237,8 @@ static rct_widget window_options_display_widgets[] = {
{ WWT_CHECKBOX, 1, 25, 290, 144, 155, STR_STEAM_OVERLAY_PAUSE, STR_STEAM_OVERLAY_PAUSE_TIP }, // Pause on steam overlay
{ WWT_CHECKBOX, 1, 11, 153, 161, 172, STR_UNCAP_FPS, STR_UNCAP_FPS_TIP }, // Uncap fps
{ WWT_CHECKBOX, 1, 155, 290, 161, 172, STR_SHOW_FPS, STR_SHOW_FPS_TIP }, // Show fps
{ WWT_CHECKBOX, 1, 11, 290, 176, 187, STR_USE_VSYNC, STR_USE_VSYNC_TIP }, // Use vsync
{ WWT_CHECKBOX, 1, 155, 290, 176, 187, STR_MULTITHREADING, STR_MULTITHREADING_TIP }, // Multithreading
{ WWT_CHECKBOX, 1, 11, 153, 176, 187, STR_USE_VSYNC, STR_USE_VSYNC_TIP }, // Use vsync
{ WWT_CHECKBOX, 1, 11, 290, 191, 202, STR_MINIMISE_FULLSCREEN_ON_FOCUS_LOSS, STR_MINIMISE_FULLSCREEN_ON_FOCUS_LOSS_TIP }, // Minimise fullscreen focus loss
{ WIDGETS_END },
};
Expand Down Expand Up @@ -522,6 +524,7 @@ static uint64_t window_options_page_enabled_widgets[] = {
(1 << WIDX_UNCAP_FPS_CHECKBOX) |
(1 << WIDX_USE_VSYNC_CHECKBOX) |
(1 << WIDX_SHOW_FPS_CHECKBOX) |
(1 << WIDX_MULTITHREADING_CHECKBOX) |
(1 << WIDX_MINIMIZE_FOCUS_LOSS) |
(1 << WIDX_STEAM_OVERLAY_PAUSE) |
(1 << WIDX_SCALE) |
Expand Down Expand Up @@ -693,6 +696,11 @@ static void window_options_mouseup(rct_window* w, rct_widgetindex widgetIndex)
config_save_default();
window_invalidate(w);
break;
case WIDX_MULTITHREADING_CHECKBOX:
gConfigGeneral.multithreading ^= 1;
config_save_default();
window_invalidate(w);
break;
case WIDX_MINIMIZE_FOCUS_LOSS:
gConfigGeneral.minimize_fullscreen_focus_loss ^= 1;
platform_refresh_video(false);
Expand Down Expand Up @@ -1711,6 +1719,7 @@ static void window_options_invalidate(rct_window* w)
widget_set_checkbox_value(w, WIDX_UNCAP_FPS_CHECKBOX, gConfigGeneral.uncap_fps);
widget_set_checkbox_value(w, WIDX_USE_VSYNC_CHECKBOX, gConfigGeneral.use_vsync);
widget_set_checkbox_value(w, WIDX_SHOW_FPS_CHECKBOX, gConfigGeneral.show_fps);
widget_set_checkbox_value(w, WIDX_MULTITHREADING_CHECKBOX, gConfigGeneral.multithreading);
widget_set_checkbox_value(w, WIDX_MINIMIZE_FOCUS_LOSS, gConfigGeneral.minimize_fullscreen_focus_loss);
widget_set_checkbox_value(w, WIDX_STEAM_OVERLAY_PAUSE, gConfigGeneral.steam_overlay_pause);

Expand Down
11 changes: 7 additions & 4 deletions src/openrct2/Context.cpp
Expand Up @@ -133,6 +133,7 @@ namespace OpenRCT2
, _audioContext(audioContext)
, _uiContext(uiContext)
, _localisationService(std::make_unique<LocalisationService>(env))
, _painter(std::make_unique<Painter>(uiContext))
{
// Can't have more than one context currently.
Guard::Assert(Instance == nullptr);
Expand Down Expand Up @@ -220,6 +221,11 @@ namespace OpenRCT2
return _drawingEngine.get();
}

virtual Paint::Painter* GetPainter() override
{
return _painter.get();
}

int32_t RunOpenRCT2(int argc, const char** argv) override
{
if (Initialise())
Expand Down Expand Up @@ -410,6 +416,7 @@ namespace OpenRCT2
lightfx_init();
#endif
}

gScenarioTicks = 0;
util_srand((uint32_t)time(nullptr));
input_reset_place_obj_modifier();
Expand All @@ -425,7 +432,6 @@ namespace OpenRCT2
void InitialiseDrawingEngine() final override
{
assert(_drawingEngine == nullptr);
assert(_painter == nullptr);

_drawingEngineType = gConfigGeneral.drawing_engine;

Expand All @@ -452,7 +458,6 @@ namespace OpenRCT2
}
else
{
_painter = std::make_unique<Painter>(_uiContext);
try
{
drawingEngine->Initialise();
Expand All @@ -461,7 +466,6 @@ namespace OpenRCT2
}
catch (const std::exception& ex)
{
_painter = nullptr;
if (_drawingEngineType == DRAWING_ENGINE_SOFTWARE)
{
_drawingEngineType = DRAWING_ENGINE_NONE;
Expand All @@ -486,7 +490,6 @@ namespace OpenRCT2
void DisposeDrawingEngine() final override
{
_drawingEngine = nullptr;
_painter = nullptr;
}

bool LoadParkFromFile(const std::string& path, bool loadTitleScreenOnFail) final override
Expand Down
6 changes: 6 additions & 0 deletions src/openrct2/Context.h
Expand Up @@ -88,6 +88,11 @@ namespace OpenRCT2
interface IUiContext;
}

namespace Paint
{
interface Painter;
}

/**
* Represents an instance of OpenRCT2 and can be used to get various services.
*/
Expand All @@ -107,6 +112,7 @@ namespace OpenRCT2
virtual IReplayManager* GetReplayManager() abstract;
virtual int32_t GetDrawingEngineType() abstract;
virtual Drawing::IDrawingEngine* GetDrawingEngine() abstract;
virtual Paint::Painter* GetPainter() abstract;

virtual int32_t RunOpenRCT2(int argc, const char** argv) abstract;

Expand Down
2 changes: 2 additions & 0 deletions src/openrct2/config/Config.cpp
Expand Up @@ -195,6 +195,7 @@ namespace Config
model->window_scale = reader->GetFloat("window_scale", platform_get_default_scale());
model->scale_quality = reader->GetEnum<int32_t>("scale_quality", SCALE_QUALITY_SMOOTH_NN, Enum_ScaleQuality);
model->show_fps = reader->GetBoolean("show_fps", false);
model->multithreading = reader->GetBoolean("multithreading", true);
model->trap_cursor = reader->GetBoolean("trap_cursor", false);
model->auto_open_shops = reader->GetBoolean("auto_open_shops", false);
model->scenario_select_mode = reader->GetInt32("scenario_select_mode", SCENARIO_SELECT_MODE_ORIGIN);
Expand Down Expand Up @@ -268,6 +269,7 @@ namespace Config
writer->WriteFloat("window_scale", model->window_scale);
writer->WriteEnum<int32_t>("scale_quality", model->scale_quality, Enum_ScaleQuality);
writer->WriteBoolean("show_fps", model->show_fps);
writer->WriteBoolean("multithreading", model->multithreading);
writer->WriteBoolean("trap_cursor", model->trap_cursor);
writer->WriteBoolean("auto_open_shops", model->auto_open_shops);
writer->WriteInt32("scenario_select_mode", model->scenario_select_mode);
Expand Down
1 change: 1 addition & 0 deletions src/openrct2/config/Config.h
Expand Up @@ -32,6 +32,7 @@ struct GeneralConfiguration
bool uncap_fps;
bool use_vsync;
bool show_fps;
bool multithreading;
bool minimize_fullscreen_focus_loss;

// Map rendering
Expand Down
6 changes: 4 additions & 2 deletions src/openrct2/core/JobPool.hpp
Expand Up @@ -9,6 +9,7 @@

#pragma once

#include <algorithm>
#include <atomic>
#include <cassert>
#include <condition_variable>
Expand Down Expand Up @@ -45,9 +46,10 @@ class JobPool
typedef std::unique_lock<std::mutex> unique_lock;

public:
JobPool()
JobPool(size_t maxThreads = 255)
{
for (size_t n = 0; n < std::thread::hardware_concurrency(); n++)
maxThreads = std::min<size_t>(maxThreads, std::thread::hardware_concurrency());
for (size_t n = 0; n < maxThreads; n++)
{
_threads.emplace_back(&JobPool::ProcessQueue, this);
}
Expand Down
8 changes: 4 additions & 4 deletions src/openrct2/drawing/Drawing.cpp
Expand Up @@ -19,11 +19,11 @@
#include "../world/Water.h"

// HACK These were originally passed back through registers
int32_t gLastDrawStringX;
int32_t gLastDrawStringY;
thread_local int32_t gLastDrawStringX;
thread_local int32_t gLastDrawStringY;

int16_t gCurrentFontSpriteBase;
uint16_t gCurrentFontFlags;
thread_local int16_t gCurrentFontSpriteBase;
thread_local uint16_t gCurrentFontFlags;

uint8_t gGamePalette[256 * 4];
uint32_t gPaletteEffectFrame;
Expand Down
8 changes: 4 additions & 4 deletions src/openrct2/drawing/Drawing.h
Expand Up @@ -237,8 +237,8 @@ struct rct_size16

#define MAX_SCROLLING_TEXT_MODES 38

extern int16_t gCurrentFontSpriteBase;
extern uint16_t gCurrentFontFlags;
extern thread_local int16_t gCurrentFontSpriteBase;
extern thread_local uint16_t gCurrentFontFlags;

extern rct_palette_entry gPalette[256];
extern uint8_t gGamePalette[256 * 4];
Expand All @@ -250,8 +250,8 @@ extern uint8_t gOtherPalette[256];
extern uint8_t text_palette[];
extern const translucent_window_palette TranslucentWindowPalettes[COLOUR_COUNT];

extern int32_t gLastDrawStringX;
extern int32_t gLastDrawStringY;
extern thread_local int32_t gLastDrawStringX;
extern thread_local int32_t gLastDrawStringY;

extern uint32_t gPickupPeepImage;
extern int32_t gPickupPeepX;
Expand Down
6 changes: 5 additions & 1 deletion src/openrct2/drawing/ScrollingText.cpp
Expand Up @@ -17,6 +17,7 @@
#include "TTF.h"

#include <algorithm>
#include <mutex>

#pragma pack(push, 1)
/* size: 0xA12 */
Expand All @@ -38,6 +39,7 @@ assert_struct_size(rct_draw_scroll_text, 0xA12);
static rct_draw_scroll_text _drawScrollTextList[MAX_SCROLLING_TEXT_ENTRIES];
static uint8_t _characterBitmaps[FONT_SPRITE_GLYPH_COUNT + SPR_G2_GLYPH_COUNT][8];
static uint32_t _drawSCrollNextIndex = 0;
static std::mutex _scrollingTextMutex;

static void scrolling_text_set_bitmap_for_sprite(
utf8* text, int32_t scroll, uint8_t* bitmap, const int16_t* scrollPositionOffsets);
Expand Down Expand Up @@ -1472,9 +1474,11 @@ void scrolling_text_invalidate()
*/
int32_t scrolling_text_setup(paint_session* session, rct_string_id stringId, uint16_t scroll, uint16_t scrollingMode)
{
std::scoped_lock<std::mutex> lock(_scrollingTextMutex);

assert(scrollingMode < MAX_SCROLLING_TEXT_MODES);

rct_drawpixelinfo* dpi = session->DPI;
rct_drawpixelinfo* dpi = &session->DPI;

if (dpi->zoom_level != 0)
return SPR_SCROLLING_TEXT_DEFAULT;
Expand Down

0 comments on commit 2fb3191

Please sign in to comment.