mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #14561 from IntelOrca/increase-paint-structs
Dynamically allocate paint structs and remove 4000 per column limit
This commit is contained in:
commit
14845b61e5
|
@ -34,47 +34,50 @@
|
|||
# include <iterator>
|
||||
# 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
|
||||
{
|
||||
auto nextQuadrantPs = reinterpret_cast<uintptr_t>(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<size_t>(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<paint_struct*>(quadrant_entries))
|
||||
if (quadrants[j] == reinterpret_cast<paint_struct*>(-1))
|
||||
{
|
||||
s[i].Quadrants[j] = nullptr;
|
||||
quadrants[j] = nullptr;
|
||||
}
|
||||
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();
|
||||
gOpenRCT2Headless = true;
|
||||
auto context = OpenRCT2::CreateContext();
|
||||
std::vector<paint_session> sessions;
|
||||
std::vector<RecordedPaintSession> 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<paint_session> 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<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.
|
||||
// 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<paint_session> sessions(1);
|
||||
for (auto& ps : sessions[0].PaintStructs)
|
||||
std::vector<RecordedPaintSession> sessions(1);
|
||||
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);
|
||||
}
|
||||
|
@ -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<paint_session> sessions = extract_paint_session(argv[i]);
|
||||
std::vector<RecordedPaintSession> sessions = extract_paint_session(argv[i]);
|
||||
if (!sessions.empty())
|
||||
benchmark::RegisterBenchmark(argv[i], BM_paint_session_arrange, sessions);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
|
@ -805,7 +806,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<paint_session>* sessions)
|
||||
std::vector<RecordedPaintSession>* sessions)
|
||||
{
|
||||
if (right <= viewport->pos.x)
|
||||
return;
|
||||
|
@ -846,30 +847,68 @@ void viewport_render(
|
|||
#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.
|
||||
// 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<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*>(
|
||||
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<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*>(
|
||||
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<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);
|
||||
if (recorded_sessions != nullptr)
|
||||
|
@ -922,7 +961,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<paint_session>* recorded_sessions)
|
||||
std::vector<RecordedPaintSession>* recorded_sessions)
|
||||
{
|
||||
uint32_t viewFlags = viewport->flags;
|
||||
uint16_t width = right - left;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <vector>
|
||||
|
||||
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<paint_session>* sessions = nullptr);
|
||||
std::vector<RecordedPaintSession>* 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<paint_session>* sessions = nullptr);
|
||||
std::vector<RecordedPaintSession>* sessions = nullptr);
|
||||
|
||||
CoordsXYZ viewport_adjust_for_map_height(const ScreenCoordsXY& startCoords);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -423,7 +425,7 @@ template<int TRotation> static void PaintSessionArrange(paint_session* session,
|
|||
*
|
||||
* rct2: 0x00688217
|
||||
*/
|
||||
void PaintSessionArrange(paint_session* session)
|
||||
void PaintSessionArrange(PaintSessionCore* session)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
@ -966,3 +968,133 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include "../interface/Colour.h"
|
||||
#include "../world/Location.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
struct TileElement;
|
||||
enum class ViewportInteractionItem : uint8_t;
|
||||
|
||||
|
@ -135,10 +138,58 @@ struct tunnel_entry
|
|||
#define MAX_PAINT_QUADRANTS 512
|
||||
#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* LastPS;
|
||||
paint_string_struct* PSStringHead;
|
||||
|
@ -168,38 +219,60 @@ struct paint_session
|
|||
uint8_t Unk141E9DB;
|
||||
uint16_t WaterHeight;
|
||||
uint32_t TrackColours[4];
|
||||
};
|
||||
|
||||
constexpr bool NoPaintStructsAvailable() noexcept
|
||||
{
|
||||
return PaintStructs.size() >= PaintStructs.capacity();
|
||||
}
|
||||
struct paint_session : public PaintSessionCore
|
||||
{
|
||||
rct_drawpixelinfo DPI;
|
||||
PaintEntryPool::Chain PaintEntryChain;
|
||||
|
||||
constexpr paint_struct* AllocateNormalPaintEntry() noexcept
|
||||
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 = PaintEntryChain.Allocate();
|
||||
if (entry != nullptr)
|
||||
{
|
||||
PSStringHead = string;
|
||||
LastPS = &entry->basic;
|
||||
return LastPS;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastPSString->next = string;
|
||||
}
|
||||
LastPSString = string;
|
||||
return LastPSString;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -260,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);
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ paint_session* Painter::CreateSession(rct_drawpixelinfo* dpi, uint32_t viewFlags
|
|||
session->ViewFlags = viewFlags;
|
||||
session->QuadrantBackIndex = std::numeric_limits<uint32_t>::max();
|
||||
session->QuadrantFrontIndex = 0;
|
||||
session->PaintStructs.clear();
|
||||
session->PaintEntryChain = _paintStructPool.Create();
|
||||
|
||||
std::fill(std::begin(session->Quadrants), std::end(session->Quadrants), nullptr);
|
||||
session->LastPS = nullptr;
|
||||
|
@ -167,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);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace OpenRCT2
|
|||
std::shared_ptr<Ui::IUiContext> const _uiContext;
|
||||
std::vector<std::unique_ptr<paint_session>> _paintSessionPool;
|
||||
std::vector<paint_session*> _freePaintSessions;
|
||||
PaintEntryPool _paintStructPool;
|
||||
time_t _lastSecond = 0;
|
||||
int32_t _currentFPS = 0;
|
||||
int32_t _frames = 0;
|
||||
|
|
Loading…
Reference in New Issue