From cb6d4715601e9524fbf4bd0a1f596e1d6730c34f Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 27 Apr 2021 01:27:49 +0100 Subject: [PATCH 1/4] Increase paint struct limit by using shared pool --- src/openrct2/interface/Viewport.cpp | 2 + src/openrct2/paint/Paint.cpp | 42 +++++++------- src/openrct2/paint/Paint.h | 88 ++++++++++++++++++++--------- src/openrct2/paint/Painter.cpp | 4 +- src/openrct2/paint/Painter.h | 1 + 5 files changed, 90 insertions(+), 47 deletions(-) diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index b99c5534f8..b4b46a1b8d 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -852,6 +852,7 @@ static void record_session(const paint_session* session, std::vectorat(record_index); @@ -867,6 +868,7 @@ static void record_session(const paint_session* session, std::vector( quad ? int(quad - &session->PaintStructs[0].basic) : std::size(session->Quadrants)); } + */ } static void viewport_fill_column(paint_session* session, std::vector* recorded_sessions, size_t record_index) diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 0bb434b384..f51955f23b 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -139,9 +139,6 @@ static paint_struct* CreateNormalPaintStruct( paint_session* session, const uint32_t image_id, const CoordsXYZ& offset, const CoordsXYZ& boundBoxSize, const CoordsXYZ& boundBoxOffset) { - if (session->NoPaintStructsAvailable()) - return nullptr; - auto* const g1 = gfx_get_g1_element(image_id & 0x7FFFF); if (g1 == nullptr) { @@ -162,7 +159,12 @@ static paint_struct* CreateNormalPaintStruct( const auto rotBoundBoxOffset = CoordsXYZ{ boundBoxOffset.Rotate(swappedRotation), boundBoxOffset.z }; const auto rotBoundBoxSize = RotateBoundBoxSize(boundBoxSize, session->CurrentRotation); - paint_struct* ps = session->AllocateNormalPaintEntry(); + auto* ps = session->AllocateNormalPaintEntry(); + if (ps == nullptr) + { + return nullptr; + } + ps->image_id = image_id; ps->x = imagePos.x; ps->y = imagePos.y; @@ -847,18 +849,18 @@ paint_struct* PaintAddImageAsChild( */ bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int16_t x, int16_t y) { - if (session->NoPaintStructsAvailable()) - { - return false; - } - - attached_paint_struct* previousAttachedPS = session->LastAttachedPS; + auto* previousAttachedPS = session->LastAttachedPS; if (previousAttachedPS == nullptr) { return PaintAttachToPreviousPS(session, image_id, x, y); } - attached_paint_struct* ps = session->AllocateAttachedPaintEntry(); + auto* ps = session->AllocateAttachedPaintEntry(); + if (ps == nullptr) + { + return false; + } + ps->image_id = image_id; ps->x = x; ps->y = y; @@ -880,18 +882,18 @@ bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int1 */ bool PaintAttachToPreviousPS(paint_session* session, uint32_t image_id, int16_t x, int16_t y) { - if (session->NoPaintStructsAvailable()) - { - return false; - } - - paint_struct* masterPs = session->LastPS; + auto* masterPs = session->LastPS; if (masterPs == nullptr) { return false; } - attached_paint_struct* ps = session->AllocateAttachedPaintEntry(); + auto* ps = session->AllocateAttachedPaintEntry(); + if (ps == nullptr) + { + return false; + } + ps->image_id = image_id; ps->x = x; ps->y = y; @@ -918,7 +920,8 @@ void PaintFloatingMoneyEffect( paint_session* session, money32 amount, rct_string_id string_id, int16_t y, int16_t z, int8_t y_offsets[], int16_t offset_x, uint32_t rotation) { - if (session->NoPaintStructsAvailable()) + auto* ps = session->AllocateStringPaintEntry(); + if (ps == nullptr) { return; } @@ -930,7 +933,6 @@ void PaintFloatingMoneyEffect( }; const auto coord = translate_3d_to_2d_with_z(rotation, position); - paint_string_struct* ps = session->AllocateStringPaintEntry(); ps->string_id = string_id; ps->next = nullptr; ps->args[0] = amount; diff --git a/src/openrct2/paint/Paint.h b/src/openrct2/paint/Paint.h index 664017af54..47ba653f95 100644 --- a/src/openrct2/paint/Paint.h +++ b/src/openrct2/paint/Paint.h @@ -15,6 +15,9 @@ #include "../interface/Colour.h" #include "../world/Location.hpp" +#include +#include + struct TileElement; enum class ViewportInteractionItem : uint8_t; @@ -135,10 +138,33 @@ struct tunnel_entry #define MAX_PAINT_QUADRANTS 512 #define TUNNEL_MAX_COUNT 65 +struct PaintStructPool +{ + FixedVector PaintStructs; + std::mutex _mutex; + + paint_entry* Allocate() + { + std::lock_guard guard(_mutex); + + if (PaintStructs.size() < PaintStructs.capacity()) + { + return &PaintStructs.emplace_back(); + } + return nullptr; + } + + void Clear() + { + PaintStructs.clear(); + } +}; + struct paint_session { rct_drawpixelinfo DPI; - FixedVector PaintStructs; + // FixedVector PaintStructs; + PaintStructPool* SharedPaintStructPool; paint_struct* Quadrants[MAX_PAINT_QUADRANTS]; paint_struct* LastPS; paint_string_struct* PSStringHead; @@ -169,36 +195,46 @@ struct paint_session uint16_t WaterHeight; uint32_t TrackColours[4]; - constexpr bool NoPaintStructsAvailable() noexcept + paint_struct* AllocateNormalPaintEntry() noexcept { - return PaintStructs.size() >= PaintStructs.capacity(); - } - - constexpr paint_struct* AllocateNormalPaintEntry() noexcept - { - LastPS = &PaintStructs.emplace_back().basic; - return LastPS; - } - - constexpr attached_paint_struct* AllocateAttachedPaintEntry() noexcept - { - LastAttachedPS = &PaintStructs.emplace_back().attached; - return LastAttachedPS; - } - - constexpr paint_string_struct* AllocateStringPaintEntry() noexcept - { - auto* string = &PaintStructs.emplace_back().string; - if (LastPSString == nullptr) + auto* entry = SharedPaintStructPool->Allocate(); + if (entry != nullptr) { - PSStringHead = string; + LastPS = &entry->basic; + return LastPS; } - else + return nullptr; + } + + attached_paint_struct* AllocateAttachedPaintEntry() noexcept + { + auto* entry = SharedPaintStructPool->Allocate(); + if (entry != nullptr) { - LastPSString->next = string; + LastAttachedPS = &entry->attached; + return LastAttachedPS; } - LastPSString = string; - return LastPSString; + return nullptr; + } + + paint_string_struct* AllocateStringPaintEntry() noexcept + { + auto* entry = SharedPaintStructPool->Allocate(); + if (entry != nullptr) + { + auto* string = &entry->string; + if (LastPSString == nullptr) + { + PSStringHead = string; + } + else + { + LastPSString->next = string; + } + LastPSString = string; + return LastPSString; + } + return nullptr; } }; diff --git a/src/openrct2/paint/Painter.cpp b/src/openrct2/paint/Painter.cpp index b9d6d0a3c2..9364b01160 100644 --- a/src/openrct2/paint/Painter.cpp +++ b/src/openrct2/paint/Painter.cpp @@ -37,6 +37,8 @@ Painter::Painter(const std::shared_ptr& uiContext) void Painter::Paint(IDrawingEngine& de) { + _paintStructPool.Clear(); + auto dpi = de.GetDrawingPixelInfo(); if (gIntroState != IntroState::None) { @@ -151,7 +153,7 @@ paint_session* Painter::CreateSession(rct_drawpixelinfo* dpi, uint32_t viewFlags session->ViewFlags = viewFlags; session->QuadrantBackIndex = std::numeric_limits::max(); session->QuadrantFrontIndex = 0; - session->PaintStructs.clear(); + session->SharedPaintStructPool = &_paintStructPool; std::fill(std::begin(session->Quadrants), std::end(session->Quadrants), nullptr); session->LastPS = nullptr; diff --git a/src/openrct2/paint/Painter.h b/src/openrct2/paint/Painter.h index e479a0e93c..42528d5d0a 100644 --- a/src/openrct2/paint/Painter.h +++ b/src/openrct2/paint/Painter.h @@ -38,6 +38,7 @@ namespace OpenRCT2 std::shared_ptr const _uiContext; std::vector> _paintSessionPool; std::vector _freePaintSessions; + PaintStructPool _paintStructPool; time_t _lastSecond = 0; int32_t _currentFPS = 0; int32_t _frames = 0; From 1caf47e45e0dffcf56818c62d3ea6f6237eb94da Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 28 Apr 2021 20:33:51 +0100 Subject: [PATCH 2/4] Use unrolled linked list for paint entries --- src/openrct2/paint/Paint.cpp | 118 +++++++++++++++++++++++++++++++++ src/openrct2/paint/Paint.h | 66 ++++++++++++------ src/openrct2/paint/Painter.cpp | 5 +- src/openrct2/paint/Painter.h | 2 +- 4 files changed, 167 insertions(+), 24 deletions(-) diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index f51955f23b..b000725ad9 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -968,3 +968,121 @@ void PaintDrawMoneyStructs(rct_drawpixelinfo* dpi, paint_string_struct* ps) FontSpriteBase::MEDIUM); } while ((ps = ps->next) != nullptr); } + +PaintEntryPool::Chain::Chain(PaintEntryPool* pool) + : Pool(pool) +{ +} + +PaintEntryPool::Chain::Chain(Chain&& chain) +{ + *this = std::move(chain); +} + +PaintEntryPool::Chain::~Chain() +{ + Clear(); +} + +PaintEntryPool::Chain& PaintEntryPool::Chain::operator=(Chain&& chain) noexcept +{ + Pool = chain.Pool; + Head = chain.Head; + Current = chain.Current; + chain.Pool = nullptr; + chain.Head = nullptr; + chain.Current = nullptr; + return *this; +} + +paint_entry* PaintEntryPool::Chain::Allocate() +{ + if (Pool == nullptr) + { + return nullptr; + } + + if (Current == nullptr) + { + assert(Head == nullptr); + Head = Pool->AllocateNode(); + if (Head == nullptr) + { + // Unable to allocate any more nodes + return nullptr; + } + Current = Head; + } + else if (Current->Count >= NodeSize) + { + // We need another node + Current->Next = Pool->AllocateNode(); + if (Current->Next == nullptr) + { + // Unable to allocate any more nodes + return nullptr; + } + Current = Current->Next; + } + + assert(Current->Count < NodeSize); + return &Current->PaintStructs[Current->Count++]; +} + +void PaintEntryPool::Chain::Clear() +{ + if (Pool != nullptr) + { + Pool->FreeNodes(Head); + Head = nullptr; + Current = nullptr; + } + assert(Head == nullptr); + assert(Current == nullptr); +} + +PaintEntryPool::~PaintEntryPool() +{ + for (auto node : _available) + { + delete node; + } + _available.clear(); +} + +PaintEntryPool::Node* PaintEntryPool::AllocateNode() +{ + std::lock_guard lock(_mutex); + + PaintEntryPool::Node* result; + if (_available.size() > 0) + { + result = _available.back(); + _available.pop_back(); + } + else + { + result = new (std::nothrow) PaintEntryPool::Node(); + } + return result; +} + +PaintEntryPool::Chain PaintEntryPool::Create() +{ + return PaintEntryPool::Chain(this); +} + +void PaintEntryPool::FreeNodes(PaintEntryPool::Node* head) +{ + std::lock_guard lock(_mutex); + + auto node = head; + while (node != nullptr) + { + auto next = node->Next; + node->Next = nullptr; + node->Count = 0; + _available.push_back(node); + node = next; + } +} diff --git a/src/openrct2/paint/Paint.h b/src/openrct2/paint/Paint.h index 47ba653f95..5360209c4b 100644 --- a/src/openrct2/paint/Paint.h +++ b/src/openrct2/paint/Paint.h @@ -138,33 +138,59 @@ struct tunnel_entry #define MAX_PAINT_QUADRANTS 512 #define TUNNEL_MAX_COUNT 65 -struct PaintStructPool +/** + * A pool of paint_entry instances that can be rented out. + * The internal implementation uses an unrolled linked list so that each + * paint session can quickly allocate a new paint entry until it requires + * another node / block of paint entries. Only the node allocation needs to + * be thread safe. + */ +class PaintEntryPool { - FixedVector PaintStructs; + static constexpr size_t NodeSize = 512; + +public: + struct Node + { + Node* Next{}; + size_t Count{}; + paint_entry PaintStructs[NodeSize]{}; + }; + + struct Chain + { + PaintEntryPool* Pool{}; + Node* Head{}; + Node* Current{}; + + Chain() = default; + Chain(PaintEntryPool* pool); + Chain(Chain&& chain); + ~Chain(); + + Chain& operator=(Chain&& chain) noexcept; + + paint_entry* Allocate(); + void Clear(); + }; + +private: + std::vector _available; std::mutex _mutex; - paint_entry* Allocate() - { - std::lock_guard guard(_mutex); + Node* AllocateNode(); - if (PaintStructs.size() < PaintStructs.capacity()) - { - return &PaintStructs.emplace_back(); - } - return nullptr; - } +public: + ~PaintEntryPool(); - void Clear() - { - PaintStructs.clear(); - } + Chain Create(); + void FreeNodes(Node* head); }; struct paint_session { rct_drawpixelinfo DPI; - // FixedVector PaintStructs; - PaintStructPool* SharedPaintStructPool; + PaintEntryPool::Chain PaintEntryChain; paint_struct* Quadrants[MAX_PAINT_QUADRANTS]; paint_struct* LastPS; paint_string_struct* PSStringHead; @@ -197,7 +223,7 @@ struct paint_session paint_struct* AllocateNormalPaintEntry() noexcept { - auto* entry = SharedPaintStructPool->Allocate(); + auto* entry = PaintEntryChain.Allocate(); if (entry != nullptr) { LastPS = &entry->basic; @@ -208,7 +234,7 @@ struct paint_session attached_paint_struct* AllocateAttachedPaintEntry() noexcept { - auto* entry = SharedPaintStructPool->Allocate(); + auto* entry = PaintEntryChain.Allocate(); if (entry != nullptr) { LastAttachedPS = &entry->attached; @@ -219,7 +245,7 @@ struct paint_session paint_string_struct* AllocateStringPaintEntry() noexcept { - auto* entry = SharedPaintStructPool->Allocate(); + auto* entry = PaintEntryChain.Allocate(); if (entry != nullptr) { auto* string = &entry->string; diff --git a/src/openrct2/paint/Painter.cpp b/src/openrct2/paint/Painter.cpp index 9364b01160..d39ea3186f 100644 --- a/src/openrct2/paint/Painter.cpp +++ b/src/openrct2/paint/Painter.cpp @@ -37,8 +37,6 @@ Painter::Painter(const std::shared_ptr& uiContext) void Painter::Paint(IDrawingEngine& de) { - _paintStructPool.Clear(); - auto dpi = de.GetDrawingPixelInfo(); if (gIntroState != IntroState::None) { @@ -153,7 +151,7 @@ paint_session* Painter::CreateSession(rct_drawpixelinfo* dpi, uint32_t viewFlags session->ViewFlags = viewFlags; session->QuadrantBackIndex = std::numeric_limits::max(); session->QuadrantFrontIndex = 0; - session->SharedPaintStructPool = &_paintStructPool; + session->PaintEntryChain = _paintStructPool.Create(); std::fill(std::begin(session->Quadrants), std::end(session->Quadrants), nullptr); session->LastPS = nullptr; @@ -169,5 +167,6 @@ paint_session* Painter::CreateSession(rct_drawpixelinfo* dpi, uint32_t viewFlags void Painter::ReleaseSession(paint_session* session) { + session->PaintEntryChain.Clear(); _freePaintSessions.push_back(session); } diff --git a/src/openrct2/paint/Painter.h b/src/openrct2/paint/Painter.h index 42528d5d0a..d776f6f557 100644 --- a/src/openrct2/paint/Painter.h +++ b/src/openrct2/paint/Painter.h @@ -38,7 +38,7 @@ namespace OpenRCT2 std::shared_ptr const _uiContext; std::vector> _paintSessionPool; std::vector _freePaintSessions; - PaintStructPool _paintStructPool; + PaintEntryPool _paintStructPool; time_t _lastSecond = 0; int32_t _currentFPS = 0; int32_t _frames = 0; From bba967d62e051c0e291219a0f2dec7f5d8c4efd3 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 2 May 2021 22:02:09 +0100 Subject: [PATCH 3/4] Start working on benchmark changes --- src/openrct2/interface/Viewport.cpp | 66 ++++++++++++++++++++++------- src/openrct2/interface/Viewport.h | 5 ++- src/openrct2/paint/Paint.cpp | 12 ++++++ src/openrct2/paint/Paint.h | 17 ++++++-- 4 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index b4b46a1b8d..f946022a2a 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -805,7 +805,7 @@ void viewport_update_smart_vehicle_follow(rct_window* window) */ void viewport_render( rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom, - std::vector* sessions) + std::vector* sessions) { if (right <= viewport->pos.x) return; @@ -846,32 +846,68 @@ void viewport_render( #endif } -static void record_session(const paint_session* session, std::vector* recorded_sessions, size_t record_index) +static void record_session( + const paint_session* session, std::vector* recorded_sessions, size_t record_index) { // Perform a deep copy of the paint session, use relative offsets. // This is done to extract the session for benchmark. // Place the copied session at provided record_index, so the caller can decide which columns/paint sessions to copy; // there is no column information embedded in the session itself. - /* - (*recorded_sessions)[record_index] = (*session); - paint_session* session_copy = &recorded_sessions->at(record_index); + auto& recordedSession = recorded_sessions->at(record_index); + recordedSession.Session = *session; + recordedSession.Entries.resize(session->PaintEntryChain.GetCount()); // Mind the offset needs to be calculated against the original `session`, not `session_copy` - for (auto& ps : session_copy->PaintStructs) + std::unordered_map entryRemap; + + // Copy all entries + auto paintIndex = 0; + auto chain = session->PaintEntryChain.Head; + while (chain != nullptr) { - ps.basic.next_quadrant_ps = reinterpret_cast( - ps.basic.next_quadrant_ps ? int(ps.basic.next_quadrant_ps - &session->PaintStructs[0].basic) - : std::size(session->PaintStructs)); + for (size_t i = 0; i < chain->Count; i++) + { + auto& src = chain->PaintStructs[i]; + auto& dst = recordedSession.Entries[paintIndex++]; + dst = src; + entryRemap[&src.basic] = reinterpret_cast(i * sizeof(paint_entry)); + } + chain = chain->Next; } - for (auto& quad : session_copy->Quadrants) + entryRemap[nullptr] = reinterpret_cast(-1); + + // Remap all entries + for (auto& ps : recordedSession.Entries) { - quad = reinterpret_cast( - quad ? int(quad - &session->PaintStructs[0].basic) : std::size(session->Quadrants)); + auto& ptr = ps.basic.next_quadrant_ps; + auto it = entryRemap.find(ptr); + if (it == entryRemap.end()) + { + assert(false); + ptr = nullptr; + } + else + { + ptr = it->second; + } + } + for (auto& ptr : recordedSession.Session.Quadrants) + { + auto it = entryRemap.find(ptr); + if (it == entryRemap.end()) + { + assert(false); + ptr = nullptr; + } + else + { + ptr = it->second; + } } - */ } -static void viewport_fill_column(paint_session* session, std::vector* recorded_sessions, size_t record_index) +static void viewport_fill_column( + paint_session* session, std::vector* recorded_sessions, size_t record_index) { PaintSessionGenerate(session); if (recorded_sessions != nullptr) @@ -924,7 +960,7 @@ static void viewport_paint_column(paint_session* session) */ void viewport_paint( const rct_viewport* viewport, rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom, - std::vector* recorded_sessions) + std::vector* recorded_sessions) { uint32_t viewFlags = viewport->flags; uint16_t width = right - left; diff --git a/src/openrct2/interface/Viewport.h b/src/openrct2/interface/Viewport.h index d62da72b0c..cc4750ab6a 100644 --- a/src/openrct2/interface/Viewport.h +++ b/src/openrct2/interface/Viewport.h @@ -18,6 +18,7 @@ #include struct paint_session; +struct RecordedPaintSession; struct paint_struct; struct rct_drawpixelinfo; struct Peep; @@ -116,10 +117,10 @@ void viewport_update_smart_staff_follow(rct_window* window, Peep* peep); void viewport_update_smart_vehicle_follow(rct_window* window); void viewport_render( rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom, - std::vector* sessions = nullptr); + std::vector* sessions = nullptr); void viewport_paint( const rct_viewport* viewport, rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom, - std::vector* sessions = nullptr); + std::vector* sessions = nullptr); CoordsXYZ viewport_adjust_for_map_height(const ScreenCoordsXY& startCoords); diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index b000725ad9..3251cde1b6 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -1041,6 +1041,18 @@ void PaintEntryPool::Chain::Clear() assert(Current == nullptr); } +size_t PaintEntryPool::Chain::GetCount() const +{ + size_t count = 0; + auto current = Head; + while (current != nullptr) + { + count += current->Count; + current = current->Next; + } + return count; +} + PaintEntryPool::~PaintEntryPool() { for (auto node : _available) diff --git a/src/openrct2/paint/Paint.h b/src/openrct2/paint/Paint.h index 5360209c4b..328311dbc5 100644 --- a/src/openrct2/paint/Paint.h +++ b/src/openrct2/paint/Paint.h @@ -172,6 +172,7 @@ public: paint_entry* Allocate(); void Clear(); + size_t GetCount() const; }; private: @@ -187,10 +188,8 @@ public: void FreeNodes(Node* head); }; -struct paint_session +struct PaintSessionCore { - rct_drawpixelinfo DPI; - PaintEntryPool::Chain PaintEntryChain; paint_struct* Quadrants[MAX_PAINT_QUADRANTS]; paint_struct* LastPS; paint_string_struct* PSStringHead; @@ -220,6 +219,12 @@ struct paint_session uint8_t Unk141E9DB; uint16_t WaterHeight; uint32_t TrackColours[4]; +}; + +struct paint_session : public PaintSessionCore +{ + rct_drawpixelinfo DPI; + PaintEntryPool::Chain PaintEntryChain; paint_struct* AllocateNormalPaintEntry() noexcept { @@ -264,6 +269,12 @@ struct paint_session } }; +struct RecordedPaintSession +{ + PaintSessionCore Session; + std::vector Entries; +}; + extern paint_session gPaintSession; // Globals for paint clipping From 7854d945995b6f2a096c488098b04c1c4df47e6e Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 3 May 2021 02:17:12 +0100 Subject: [PATCH 4/4] Fix benchmarking --- src/openrct2/cmdline/BenchSpriteSort.cpp | 53 +++++++++++++----------- src/openrct2/interface/Viewport.cpp | 1 + src/openrct2/paint/Paint.cpp | 4 +- src/openrct2/paint/Paint.h | 2 +- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/openrct2/cmdline/BenchSpriteSort.cpp b/src/openrct2/cmdline/BenchSpriteSort.cpp index db59000371..c7dcd8f0da 100644 --- a/src/openrct2/cmdline/BenchSpriteSort.cpp +++ b/src/openrct2/cmdline/BenchSpriteSort.cpp @@ -34,47 +34,50 @@ # include # include -static void fixup_pointers(paint_session* s, size_t paint_session_entries, size_t paint_struct_entries, size_t quadrant_entries) +static void fixup_pointers(std::vector& s) { - for (size_t i = 0; i < paint_session_entries; i++) + for (size_t i = 0; i < s.size(); i++) { - for (size_t j = 0; j < paint_struct_entries; j++) + auto& entries = s[i].Entries; + auto& quadrants = s[i].Session.Quadrants; + for (size_t j = 0; j < entries.size(); j++) { - if (s[i].PaintStructs[j].basic.next_quadrant_ps == reinterpret_cast(paint_struct_entries)) + if (entries[j].basic.next_quadrant_ps == reinterpret_cast(-1)) { - s[i].PaintStructs[j].basic.next_quadrant_ps = nullptr; + entries[j].basic.next_quadrant_ps = nullptr; } else { - auto nextQuadrantPs = reinterpret_cast(s[i].PaintStructs[j].basic.next_quadrant_ps); - s[i].PaintStructs[j].basic.next_quadrant_ps = &s[i].PaintStructs[nextQuadrantPs].basic; + auto nextQuadrantPs = reinterpret_cast(entries[j].basic.next_quadrant_ps) / sizeof(paint_entry); + entries[j].basic.next_quadrant_ps = &s[i].Entries[nextQuadrantPs].basic; } } - for (size_t j = 0; j < quadrant_entries; j++) + for (size_t j = 0; j < std::size(quadrants); j++) { - if (s[i].Quadrants[j] == reinterpret_cast(quadrant_entries)) + if (quadrants[j] == reinterpret_cast(-1)) { - s[i].Quadrants[j] = nullptr; + quadrants[j] = nullptr; } else { - s[i].Quadrants[j] = &s[i].PaintStructs[reinterpret_cast(s[i].Quadrants[j])].basic; + auto ps = reinterpret_cast(quadrants[j]) / sizeof(paint_entry); + quadrants[j] = &entries[ps].basic; } } } } -static std::vector extract_paint_session(const std::string parkFileName) +static std::vector extract_paint_session(std::string_view parkFileName) { core_init(); gOpenRCT2Headless = true; auto context = OpenRCT2::CreateContext(); - std::vector sessions; + std::vector sessions; log_info("Starting..."); if (context->Initialise()) { drawing_engine_init(); - if (!context->LoadParkFromFile(parkFileName)) + if (!context->LoadParkFromFile(std::string(parkFileName))) { log_error("Failed to load park!"); return {}; @@ -133,21 +136,21 @@ static std::vector extract_paint_session(const std::string parkFi } // This function is based on benchgfx_render_screenshots -static void BM_paint_session_arrange(benchmark::State& state, const std::vector inputSessions) +static void BM_paint_session_arrange(benchmark::State& state, const std::vector inputSessions) { - std::vector sessions = inputSessions; + auto sessions = inputSessions; // Fixing up the pointers continuously is wasteful. Fix it up once for `sessions` and store a copy. // Keep in mind we need bit-exact copy, as the lists use pointers. // Once sorted, just restore the copy with the original fixed-up version. - paint_session* local_s = new paint_session[std::size(sessions)]; - fixup_pointers(&sessions[0], std::size(sessions), std::size(local_s->PaintStructs), std::size(local_s->Quadrants)); + RecordedPaintSession* local_s = new RecordedPaintSession[std::size(sessions)]; + fixup_pointers(sessions); std::copy_n(sessions.cbegin(), std::size(sessions), local_s); for (auto _ : state) { state.PauseTiming(); std::copy_n(local_s, std::size(sessions), sessions.begin()); state.ResumeTiming(); - PaintSessionArrange(&sessions[0]); + PaintSessionArrange(&sessions[0].Session); benchmark::DoNotOptimize(sessions); } state.SetItemsProcessed(state.iterations() * std::size(sessions)); @@ -158,14 +161,14 @@ static int cmdline_for_bench_sprite_sort(int argc, const char** argv) { { // Register some basic "baseline" benchmark - std::vector sessions(1); - for (auto& ps : sessions[0].PaintStructs) + std::vector sessions(1); + for (auto& ps : sessions[0].Entries) { - ps.basic.next_quadrant_ps = reinterpret_cast((std::size(sessions[0].PaintStructs))); + ps.basic.next_quadrant_ps = reinterpret_cast(-1); } - for (auto& quad : sessions[0].Quadrants) + for (auto& quad : sessions[0].Session.Quadrants) { - quad = reinterpret_cast((std::size(sessions[0].Quadrants))); + quad = reinterpret_cast(-1); } benchmark::RegisterBenchmark("baseline", BM_paint_session_arrange, sessions); } @@ -183,7 +186,7 @@ static int cmdline_for_bench_sprite_sort(int argc, const char** argv) if (Platform::FileExists(argv[i])) { // Register benchmark for sv6 if valid - std::vector sessions = extract_paint_session(argv[i]); + std::vector sessions = extract_paint_session(argv[i]); if (!sessions.empty()) benchmark::RegisterBenchmark(argv[i], BM_paint_session_arrange, sessions); } diff --git a/src/openrct2/interface/Viewport.cpp b/src/openrct2/interface/Viewport.cpp index f946022a2a..549edbccc5 100644 --- a/src/openrct2/interface/Viewport.cpp +++ b/src/openrct2/interface/Viewport.cpp @@ -35,6 +35,7 @@ #include #include #include +#include using namespace OpenRCT2; diff --git a/src/openrct2/paint/Paint.cpp b/src/openrct2/paint/Paint.cpp index 3251cde1b6..b5d7ded9a6 100644 --- a/src/openrct2/paint/Paint.cpp +++ b/src/openrct2/paint/Paint.cpp @@ -385,7 +385,7 @@ static paint_struct* PaintArrangeStructsHelperRotation(paint_struct* ps_next, ui } } -template static void PaintSessionArrange(paint_session* session, bool) +template static void PaintSessionArrange(PaintSessionCore* session, bool) { paint_struct* psHead = &session->PaintHead; @@ -425,7 +425,7 @@ template static void PaintSessionArrange(paint_session* session, * * rct2: 0x00688217 */ -void PaintSessionArrange(paint_session* session) +void PaintSessionArrange(PaintSessionCore* session) { switch (session->CurrentRotation) { diff --git a/src/openrct2/paint/Paint.h b/src/openrct2/paint/Paint.h index 328311dbc5..a82832dea2 100644 --- a/src/openrct2/paint/Paint.h +++ b/src/openrct2/paint/Paint.h @@ -333,7 +333,7 @@ void PaintFloatingMoneyEffect( paint_session* PaintSessionAlloc(rct_drawpixelinfo* dpi, uint32_t viewFlags); void PaintSessionFree(paint_session* session); void PaintSessionGenerate(paint_session* session); -void PaintSessionArrange(paint_session* session); +void PaintSessionArrange(PaintSessionCore* session); void PaintDrawStructs(paint_session* session); void PaintDrawMoneyStructs(rct_drawpixelinfo* dpi, paint_string_struct* ps);