Merge pull request #14561 from IntelOrca/increase-paint-structs

Dynamically allocate paint structs and remove 4000 per column limit
This commit is contained in:
Ted John 2021-05-08 23:36:40 +01:00 committed by GitHub
commit 14845b61e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 343 additions and 93 deletions

View File

@ -34,47 +34,50 @@
# include <iterator> # include <iterator>
# include <vector> # include <vector>
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<RecordedPaintSession>& 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*>(paint_struct_entries)) if (entries[j].basic.next_quadrant_ps == reinterpret_cast<paint_struct*>(-1))
{ {
s[i].PaintStructs[j].basic.next_quadrant_ps = nullptr; entries[j].basic.next_quadrant_ps = nullptr;
} }
else else
{ {
auto nextQuadrantPs = reinterpret_cast<uintptr_t>(s[i].PaintStructs[j].basic.next_quadrant_ps); auto nextQuadrantPs = reinterpret_cast<size_t>(entries[j].basic.next_quadrant_ps) / sizeof(paint_entry);
s[i].PaintStructs[j].basic.next_quadrant_ps = &s[i].PaintStructs[nextQuadrantPs].basic; 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<paint_struct*>(quadrant_entries)) if (quadrants[j] == reinterpret_cast<paint_struct*>(-1))
{ {
s[i].Quadrants[j] = nullptr; quadrants[j] = nullptr;
} }
else else
{ {
s[i].Quadrants[j] = &s[i].PaintStructs[reinterpret_cast<size_t>(s[i].Quadrants[j])].basic; auto ps = reinterpret_cast<size_t>(quadrants[j]) / sizeof(paint_entry);
quadrants[j] = &entries[ps].basic;
} }
} }
} }
} }
static std::vector<paint_session> extract_paint_session(const std::string parkFileName) static std::vector<RecordedPaintSession> extract_paint_session(std::string_view parkFileName)
{ {
core_init(); core_init();
gOpenRCT2Headless = true; gOpenRCT2Headless = true;
auto context = OpenRCT2::CreateContext(); auto context = OpenRCT2::CreateContext();
std::vector<paint_session> sessions; std::vector<RecordedPaintSession> sessions;
log_info("Starting..."); log_info("Starting...");
if (context->Initialise()) if (context->Initialise())
{ {
drawing_engine_init(); drawing_engine_init();
if (!context->LoadParkFromFile(parkFileName)) if (!context->LoadParkFromFile(std::string(parkFileName)))
{ {
log_error("Failed to load park!"); log_error("Failed to load park!");
return {}; return {};
@ -133,21 +136,21 @@ static std::vector<paint_session> extract_paint_session(const std::string parkFi
} }
// This function is based on benchgfx_render_screenshots // This function is based on benchgfx_render_screenshots
static void BM_paint_session_arrange(benchmark::State& state, const std::vector<paint_session> inputSessions) static void BM_paint_session_arrange(benchmark::State& state, const std::vector<RecordedPaintSession> inputSessions)
{ {
std::vector<paint_session> sessions = inputSessions; auto sessions = inputSessions;
// Fixing up the pointers continuously is wasteful. Fix it up once for `sessions` and store a copy. // 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. // 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. // Once sorted, just restore the copy with the original fixed-up version.
paint_session* local_s = new paint_session[std::size(sessions)]; RecordedPaintSession* local_s = new RecordedPaintSession[std::size(sessions)];
fixup_pointers(&sessions[0], std::size(sessions), std::size(local_s->PaintStructs), std::size(local_s->Quadrants)); fixup_pointers(sessions);
std::copy_n(sessions.cbegin(), std::size(sessions), local_s); std::copy_n(sessions.cbegin(), std::size(sessions), local_s);
for (auto _ : state) for (auto _ : state)
{ {
state.PauseTiming(); state.PauseTiming();
std::copy_n(local_s, std::size(sessions), sessions.begin()); std::copy_n(local_s, std::size(sessions), sessions.begin());
state.ResumeTiming(); state.ResumeTiming();
PaintSessionArrange(&sessions[0]); PaintSessionArrange(&sessions[0].Session);
benchmark::DoNotOptimize(sessions); benchmark::DoNotOptimize(sessions);
} }
state.SetItemsProcessed(state.iterations() * std::size(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 // Register some basic "baseline" benchmark
std::vector<paint_session> sessions(1); std::vector<RecordedPaintSession> sessions(1);
for (auto& ps : sessions[0].PaintStructs) for (auto& ps : sessions[0].Entries)
{ {
ps.basic.next_quadrant_ps = reinterpret_cast<paint_struct*>((std::size(sessions[0].PaintStructs))); ps.basic.next_quadrant_ps = reinterpret_cast<paint_struct*>(-1);
} }
for (auto& quad : sessions[0].Quadrants) for (auto& quad : sessions[0].Session.Quadrants)
{ {
quad = reinterpret_cast<paint_struct*>((std::size(sessions[0].Quadrants))); quad = reinterpret_cast<paint_struct*>(-1);
} }
benchmark::RegisterBenchmark("baseline", BM_paint_session_arrange, sessions); 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])) if (Platform::FileExists(argv[i]))
{ {
// Register benchmark for sv6 if valid // Register benchmark for sv6 if valid
std::vector<paint_session> sessions = extract_paint_session(argv[i]); std::vector<RecordedPaintSession> sessions = extract_paint_session(argv[i]);
if (!sessions.empty()) if (!sessions.empty())
benchmark::RegisterBenchmark(argv[i], BM_paint_session_arrange, sessions); benchmark::RegisterBenchmark(argv[i], BM_paint_session_arrange, sessions);
} }

View File

@ -35,6 +35,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <list> #include <list>
#include <unordered_map>
using namespace OpenRCT2; using namespace OpenRCT2;
@ -805,7 +806,7 @@ void viewport_update_smart_vehicle_follow(rct_window* window)
*/ */
void viewport_render( void viewport_render(
rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom, rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom,
std::vector<paint_session>* sessions) std::vector<RecordedPaintSession>* sessions)
{ {
if (right <= viewport->pos.x) if (right <= viewport->pos.x)
return; return;
@ -846,30 +847,68 @@ void viewport_render(
#endif #endif
} }
static void record_session(const paint_session* session, std::vector<paint_session>* recorded_sessions, size_t record_index) static void record_session(
const paint_session* session, std::vector<RecordedPaintSession>* recorded_sessions, size_t record_index)
{ {
// Perform a deep copy of the paint session, use relative offsets. // Perform a deep copy of the paint session, use relative offsets.
// This is done to extract the session for benchmark. // 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; // 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. // there is no column information embedded in the session itself.
(*recorded_sessions)[record_index] = (*session); auto& recordedSession = recorded_sessions->at(record_index);
paint_session* session_copy = &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` // Mind the offset needs to be calculated against the original `session`, not `session_copy`
for (auto& ps : session_copy->PaintStructs) std::unordered_map<paint_struct*, paint_struct*> entryRemap;
// Copy all entries
auto paintIndex = 0;
auto chain = session->PaintEntryChain.Head;
while (chain != nullptr)
{ {
ps.basic.next_quadrant_ps = reinterpret_cast<paint_struct*>( for (size_t i = 0; i < chain->Count; i++)
ps.basic.next_quadrant_ps ? int(ps.basic.next_quadrant_ps - &session->PaintStructs[0].basic) {
: std::size(session->PaintStructs)); auto& src = chain->PaintStructs[i];
auto& dst = recordedSession.Entries[paintIndex++];
dst = src;
entryRemap[&src.basic] = reinterpret_cast<paint_struct*>(i * sizeof(paint_entry));
}
chain = chain->Next;
} }
for (auto& quad : session_copy->Quadrants) entryRemap[nullptr] = reinterpret_cast<paint_struct*>(-1);
// Remap all entries
for (auto& ps : recordedSession.Entries)
{ {
quad = reinterpret_cast<paint_struct*>( auto& ptr = ps.basic.next_quadrant_ps;
quad ? int(quad - &session->PaintStructs[0].basic) : std::size(session->Quadrants)); 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<paint_session>* recorded_sessions, size_t record_index) static void viewport_fill_column(
paint_session* session, std::vector<RecordedPaintSession>* recorded_sessions, size_t record_index)
{ {
PaintSessionGenerate(session); PaintSessionGenerate(session);
if (recorded_sessions != nullptr) if (recorded_sessions != nullptr)
@ -922,7 +961,7 @@ static void viewport_paint_column(paint_session* session)
*/ */
void viewport_paint( void viewport_paint(
const rct_viewport* viewport, rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom, const rct_viewport* viewport, rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom,
std::vector<paint_session>* recorded_sessions) std::vector<RecordedPaintSession>* recorded_sessions)
{ {
uint32_t viewFlags = viewport->flags; uint32_t viewFlags = viewport->flags;
uint16_t width = right - left; uint16_t width = right - left;

View File

@ -18,6 +18,7 @@
#include <vector> #include <vector>
struct paint_session; struct paint_session;
struct RecordedPaintSession;
struct paint_struct; struct paint_struct;
struct rct_drawpixelinfo; struct rct_drawpixelinfo;
struct Peep; 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_update_smart_vehicle_follow(rct_window* window);
void viewport_render( void viewport_render(
rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom, rct_drawpixelinfo* dpi, const rct_viewport* viewport, int32_t left, int32_t top, int32_t right, int32_t bottom,
std::vector<paint_session>* sessions = nullptr); std::vector<RecordedPaintSession>* sessions = nullptr);
void viewport_paint( void viewport_paint(
const rct_viewport* viewport, rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom, const rct_viewport* viewport, rct_drawpixelinfo* dpi, int16_t left, int16_t top, int16_t right, int16_t bottom,
std::vector<paint_session>* sessions = nullptr); std::vector<RecordedPaintSession>* sessions = nullptr);
CoordsXYZ viewport_adjust_for_map_height(const ScreenCoordsXY& startCoords); CoordsXYZ viewport_adjust_for_map_height(const ScreenCoordsXY& startCoords);

View File

@ -139,9 +139,6 @@ static paint_struct* CreateNormalPaintStruct(
paint_session* session, const uint32_t image_id, const CoordsXYZ& offset, const CoordsXYZ& boundBoxSize, paint_session* session, const uint32_t image_id, const CoordsXYZ& offset, const CoordsXYZ& boundBoxSize,
const CoordsXYZ& boundBoxOffset) const CoordsXYZ& boundBoxOffset)
{ {
if (session->NoPaintStructsAvailable())
return nullptr;
auto* const g1 = gfx_get_g1_element(image_id & 0x7FFFF); auto* const g1 = gfx_get_g1_element(image_id & 0x7FFFF);
if (g1 == nullptr) if (g1 == nullptr)
{ {
@ -162,7 +159,12 @@ static paint_struct* CreateNormalPaintStruct(
const auto rotBoundBoxOffset = CoordsXYZ{ boundBoxOffset.Rotate(swappedRotation), boundBoxOffset.z }; const auto rotBoundBoxOffset = CoordsXYZ{ boundBoxOffset.Rotate(swappedRotation), boundBoxOffset.z };
const auto rotBoundBoxSize = RotateBoundBoxSize(boundBoxSize, session->CurrentRotation); 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->image_id = image_id;
ps->x = imagePos.x; ps->x = imagePos.x;
ps->y = imagePos.y; ps->y = imagePos.y;
@ -383,7 +385,7 @@ static paint_struct* PaintArrangeStructsHelperRotation(paint_struct* ps_next, ui
} }
} }
template<int TRotation> static void PaintSessionArrange(paint_session* session, bool) template<int TRotation> static void PaintSessionArrange(PaintSessionCore* session, bool)
{ {
paint_struct* psHead = &session->PaintHead; paint_struct* psHead = &session->PaintHead;
@ -423,7 +425,7 @@ template<int TRotation> static void PaintSessionArrange(paint_session* session,
* *
* rct2: 0x00688217 * rct2: 0x00688217
*/ */
void PaintSessionArrange(paint_session* session) void PaintSessionArrange(PaintSessionCore* session)
{ {
switch (session->CurrentRotation) switch (session->CurrentRotation)
{ {
@ -847,18 +849,18 @@ paint_struct* PaintAddImageAsChild(
*/ */
bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int16_t x, int16_t y) bool PaintAttachToPreviousAttach(paint_session* session, uint32_t image_id, int16_t x, int16_t y)
{ {
if (session->NoPaintStructsAvailable()) auto* previousAttachedPS = session->LastAttachedPS;
{
return false;
}
attached_paint_struct* previousAttachedPS = session->LastAttachedPS;
if (previousAttachedPS == nullptr) if (previousAttachedPS == nullptr)
{ {
return PaintAttachToPreviousPS(session, image_id, x, y); 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->image_id = image_id;
ps->x = x; ps->x = x;
ps->y = y; 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) bool PaintAttachToPreviousPS(paint_session* session, uint32_t image_id, int16_t x, int16_t y)
{ {
if (session->NoPaintStructsAvailable()) auto* masterPs = session->LastPS;
{
return false;
}
paint_struct* masterPs = session->LastPS;
if (masterPs == nullptr) if (masterPs == nullptr)
{ {
return false; return false;
} }
attached_paint_struct* ps = session->AllocateAttachedPaintEntry(); auto* ps = session->AllocateAttachedPaintEntry();
if (ps == nullptr)
{
return false;
}
ps->image_id = image_id; ps->image_id = image_id;
ps->x = x; ps->x = x;
ps->y = y; 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, 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) uint32_t rotation)
{ {
if (session->NoPaintStructsAvailable()) auto* ps = session->AllocateStringPaintEntry();
if (ps == nullptr)
{ {
return; return;
} }
@ -930,7 +933,6 @@ void PaintFloatingMoneyEffect(
}; };
const auto coord = translate_3d_to_2d_with_z(rotation, position); const auto coord = translate_3d_to_2d_with_z(rotation, position);
paint_string_struct* ps = session->AllocateStringPaintEntry();
ps->string_id = string_id; ps->string_id = string_id;
ps->next = nullptr; ps->next = nullptr;
ps->args[0] = amount; ps->args[0] = amount;
@ -966,3 +968,133 @@ void PaintDrawMoneyStructs(rct_drawpixelinfo* dpi, paint_string_struct* ps)
FontSpriteBase::MEDIUM); FontSpriteBase::MEDIUM);
} while ((ps = ps->next) != nullptr); } 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);
}
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)
{
delete node;
}
_available.clear();
}
PaintEntryPool::Node* PaintEntryPool::AllocateNode()
{
std::lock_guard<std::mutex> 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<std::mutex> lock(_mutex);
auto node = head;
while (node != nullptr)
{
auto next = node->Next;
node->Next = nullptr;
node->Count = 0;
_available.push_back(node);
node = next;
}
}

View File

@ -15,6 +15,9 @@
#include "../interface/Colour.h" #include "../interface/Colour.h"
#include "../world/Location.hpp" #include "../world/Location.hpp"
#include <mutex>
#include <thread>
struct TileElement; struct TileElement;
enum class ViewportInteractionItem : uint8_t; enum class ViewportInteractionItem : uint8_t;
@ -135,10 +138,58 @@ struct tunnel_entry
#define MAX_PAINT_QUADRANTS 512 #define MAX_PAINT_QUADRANTS 512
#define TUNNEL_MAX_COUNT 65 #define TUNNEL_MAX_COUNT 65
struct paint_session /**
* 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
{
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();
size_t GetCount() const;
};
private:
std::vector<Node*> _available;
std::mutex _mutex;
Node* AllocateNode();
public:
~PaintEntryPool();
Chain Create();
void FreeNodes(Node* head);
};
struct PaintSessionCore
{ {
rct_drawpixelinfo DPI;
FixedVector<paint_entry, 4000> PaintStructs;
paint_struct* Quadrants[MAX_PAINT_QUADRANTS]; paint_struct* Quadrants[MAX_PAINT_QUADRANTS];
paint_struct* LastPS; paint_struct* LastPS;
paint_string_struct* PSStringHead; paint_string_struct* PSStringHead;
@ -168,38 +219,60 @@ struct paint_session
uint8_t Unk141E9DB; uint8_t Unk141E9DB;
uint16_t WaterHeight; uint16_t WaterHeight;
uint32_t TrackColours[4]; uint32_t TrackColours[4];
};
constexpr bool NoPaintStructsAvailable() noexcept struct paint_session : public PaintSessionCore
{ {
return PaintStructs.size() >= PaintStructs.capacity(); rct_drawpixelinfo DPI;
} PaintEntryPool::Chain PaintEntryChain;
constexpr paint_struct* AllocateNormalPaintEntry() noexcept paint_struct* AllocateNormalPaintEntry() noexcept
{ {
LastPS = &PaintStructs.emplace_back().basic; auto* entry = PaintEntryChain.Allocate();
return LastPS; if (entry != nullptr)
}
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)
{ {
PSStringHead = string; LastPS = &entry->basic;
return LastPS;
} }
else return nullptr;
{
LastPSString->next = string;
}
LastPSString = string;
return LastPSString;
} }
attached_paint_struct* AllocateAttachedPaintEntry() noexcept
{
auto* entry = PaintEntryChain.Allocate();
if (entry != nullptr)
{
LastAttachedPS = &entry->attached;
return LastAttachedPS;
}
return nullptr;
}
paint_string_struct* AllocateStringPaintEntry() noexcept
{
auto* entry = PaintEntryChain.Allocate();
if (entry != nullptr)
{
auto* string = &entry->string;
if (LastPSString == nullptr)
{
PSStringHead = string;
}
else
{
LastPSString->next = string;
}
LastPSString = string;
return LastPSString;
}
return nullptr;
}
};
struct RecordedPaintSession
{
PaintSessionCore Session;
std::vector<paint_entry> Entries;
}; };
extern paint_session gPaintSession; extern paint_session gPaintSession;
@ -260,7 +333,7 @@ void PaintFloatingMoneyEffect(
paint_session* PaintSessionAlloc(rct_drawpixelinfo* dpi, uint32_t viewFlags); paint_session* PaintSessionAlloc(rct_drawpixelinfo* dpi, uint32_t viewFlags);
void PaintSessionFree(paint_session* session); void PaintSessionFree(paint_session* session);
void PaintSessionGenerate(paint_session* session); void PaintSessionGenerate(paint_session* session);
void PaintSessionArrange(paint_session* session); void PaintSessionArrange(PaintSessionCore* session);
void PaintDrawStructs(paint_session* session); void PaintDrawStructs(paint_session* session);
void PaintDrawMoneyStructs(rct_drawpixelinfo* dpi, paint_string_struct* ps); void PaintDrawMoneyStructs(rct_drawpixelinfo* dpi, paint_string_struct* ps);

View File

@ -151,7 +151,7 @@ paint_session* Painter::CreateSession(rct_drawpixelinfo* dpi, uint32_t viewFlags
session->ViewFlags = viewFlags; session->ViewFlags = viewFlags;
session->QuadrantBackIndex = std::numeric_limits<uint32_t>::max(); session->QuadrantBackIndex = std::numeric_limits<uint32_t>::max();
session->QuadrantFrontIndex = 0; session->QuadrantFrontIndex = 0;
session->PaintStructs.clear(); session->PaintEntryChain = _paintStructPool.Create();
std::fill(std::begin(session->Quadrants), std::end(session->Quadrants), nullptr); std::fill(std::begin(session->Quadrants), std::end(session->Quadrants), nullptr);
session->LastPS = nullptr; session->LastPS = nullptr;
@ -167,5 +167,6 @@ paint_session* Painter::CreateSession(rct_drawpixelinfo* dpi, uint32_t viewFlags
void Painter::ReleaseSession(paint_session* session) void Painter::ReleaseSession(paint_session* session)
{ {
session->PaintEntryChain.Clear();
_freePaintSessions.push_back(session); _freePaintSessions.push_back(session);
} }

View File

@ -38,6 +38,7 @@ namespace OpenRCT2
std::shared_ptr<Ui::IUiContext> const _uiContext; std::shared_ptr<Ui::IUiContext> const _uiContext;
std::vector<std::unique_ptr<paint_session>> _paintSessionPool; std::vector<std::unique_ptr<paint_session>> _paintSessionPool;
std::vector<paint_session*> _freePaintSessions; std::vector<paint_session*> _freePaintSessions;
PaintEntryPool _paintStructPool;
time_t _lastSecond = 0; time_t _lastSecond = 0;
int32_t _currentFPS = 0; int32_t _currentFPS = 0;
int32_t _frames = 0; int32_t _frames = 0;