mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-22 07:13:07 +01:00
Merge pull request #23408 from ZehMatt/render-update-2
Refactor some PaintSession things
This commit is contained in:
@@ -59,7 +59,6 @@ bool gPaintBoundingBoxes;
|
|||||||
bool gPaintBlockedTiles;
|
bool gPaintBlockedTiles;
|
||||||
bool gPaintStableSort;
|
bool gPaintStableSort;
|
||||||
|
|
||||||
static void PaintAttachedPS(DrawPixelInfo& dpi, PaintStruct* ps, uint32_t viewFlags);
|
|
||||||
static void PaintPSImageWithBoundingBoxes(PaintSession& session, PaintStruct* ps, ImageId imageId, int32_t x, int32_t y);
|
static void PaintPSImageWithBoundingBoxes(PaintSession& session, PaintStruct* ps, ImageId imageId, int32_t x, int32_t y);
|
||||||
static ImageId PaintPSColourifyImage(const PaintStruct* ps, ImageId imageId, uint32_t viewFlags);
|
static ImageId PaintPSColourifyImage(const PaintStruct* ps, ImageId imageId, uint32_t viewFlags);
|
||||||
|
|
||||||
@@ -634,7 +633,7 @@ void PaintSessionArrange(PaintSessionCore& session)
|
|||||||
return _paintArrangeFuncsLegacy[session.CurrentRotation](session);
|
return _paintArrangeFuncsLegacy[session.CurrentRotation](session);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PaintDrawStruct(PaintSession& session, PaintStruct* ps)
|
static inline void PaintDrawStruct(PaintSession& session, PaintStruct* ps)
|
||||||
{
|
{
|
||||||
auto screenPos = ps->ScreenPos;
|
auto screenPos = ps->ScreenPos;
|
||||||
if (ps->InteractionItem == ViewportInteractionItem::Entity)
|
if (ps->InteractionItem == ViewportInteractionItem::Entity)
|
||||||
@@ -660,15 +659,6 @@ static void PaintDrawStruct(PaintSession& session, PaintStruct* ps)
|
|||||||
{
|
{
|
||||||
GfxDrawSprite(session.DPI, imageId, screenPos);
|
GfxDrawSprite(session.DPI, imageId, screenPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps->Children != nullptr)
|
|
||||||
{
|
|
||||||
PaintDrawStruct(session, ps->Children);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PaintAttachedPS(session.DPI, ps, session.ViewFlags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -681,30 +671,29 @@ void PaintDrawStructs(PaintSession& session)
|
|||||||
|
|
||||||
for (PaintStruct* ps = session.PaintHead; ps != nullptr; ps = ps->NextQuadrantEntry)
|
for (PaintStruct* ps = session.PaintHead; ps != nullptr; ps = ps->NextQuadrantEntry)
|
||||||
{
|
{
|
||||||
|
// Paint parent node.
|
||||||
PaintDrawStruct(session, ps);
|
PaintDrawStruct(session, ps);
|
||||||
}
|
|
||||||
|
// Paint children.
|
||||||
|
for (auto* psChild = ps->Children; psChild != nullptr; psChild = psChild->NextQuadrantEntry)
|
||||||
|
{
|
||||||
|
PaintDrawStruct(session, psChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Paint attached.
|
||||||
*
|
for (auto* psAttached = ps->Attached; psAttached != nullptr; psAttached = psAttached->NextEntry)
|
||||||
* rct2: 0x00688596
|
|
||||||
* Part of 0x688485
|
|
||||||
*/
|
|
||||||
static void PaintAttachedPS(DrawPixelInfo& dpi, PaintStruct* ps, uint32_t viewFlags)
|
|
||||||
{
|
{
|
||||||
AttachedPaintStruct* attached_ps = ps->Attached;
|
const auto screenCoords = ps->ScreenPos + psAttached->RelativePos;
|
||||||
for (; attached_ps != nullptr; attached_ps = attached_ps->NextEntry)
|
|
||||||
{
|
|
||||||
const auto screenCoords = ps->ScreenPos + attached_ps->RelativePos;
|
|
||||||
|
|
||||||
auto imageId = PaintPSColourifyImage(ps, attached_ps->image_id, viewFlags);
|
auto imageId = PaintPSColourifyImage(ps, psAttached->image_id, session.ViewFlags);
|
||||||
if (attached_ps->IsMasked)
|
if (psAttached->IsMasked)
|
||||||
{
|
{
|
||||||
GfxDrawSpriteRawMasked(dpi, screenCoords, imageId, attached_ps->ColourImageId);
|
GfxDrawSpriteRawMasked(session.DPI, screenCoords, imageId, psAttached->ColourImageId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GfxDrawSprite(dpi, imageId, screenCoords);
|
GfxDrawSprite(session.DPI, imageId, screenCoords);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1041,134 +1030,3 @@ void PaintDrawMoneyStructs(DrawPixelInfo& dpi, PaintStringStruct* ps)
|
|||||||
FontStyle::Medium);
|
FontStyle::Medium);
|
||||||
} while ((ps = ps->NextEntry) != nullptr);
|
} while ((ps = ps->NextEntry) != 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
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
Pool = chain.Pool;
|
|
||||||
Head = chain.Head;
|
|
||||||
Current = chain.Current;
|
|
||||||
chain.Pool = nullptr;
|
|
||||||
chain.Head = nullptr;
|
|
||||||
chain.Current = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
PaintEntry* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "tile_element/Paint.Tunnel.h"
|
#include "tile_element/Paint.Tunnel.h"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <sfl/segmented_vector.hpp>
|
||||||
|
#include <sfl/static_vector.hpp>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
struct EntityBase;
|
struct EntityBase;
|
||||||
@@ -122,56 +124,6 @@ struct SupportHeight
|
|||||||
// the quadrant index is based on the x and y components combined.
|
// the quadrant index is based on the x and y components combined.
|
||||||
static constexpr int32_t MaxPaintQuadrants = kMaximumMapSizeTechnical * 2;
|
static constexpr int32_t MaxPaintQuadrants = kMaximumMapSizeTechnical * 2;
|
||||||
|
|
||||||
/**
|
|
||||||
* A pool of PaintEntry 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{};
|
|
||||||
PaintEntry PaintStructs[NodeSize]{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Chain
|
|
||||||
{
|
|
||||||
PaintEntryPool* Pool{};
|
|
||||||
Node* Head{};
|
|
||||||
Node* Current{};
|
|
||||||
|
|
||||||
Chain() = default;
|
|
||||||
Chain(PaintEntryPool* pool);
|
|
||||||
Chain(Chain&& chain);
|
|
||||||
~Chain();
|
|
||||||
|
|
||||||
Chain& operator=(Chain&& chain) noexcept;
|
|
||||||
|
|
||||||
PaintEntry* 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
|
struct PaintSessionCore
|
||||||
{
|
{
|
||||||
PaintStruct* PaintHead;
|
PaintStruct* PaintHead;
|
||||||
@@ -207,38 +159,59 @@ struct PaintSessionCore
|
|||||||
ViewportInteractionItem InteractionType;
|
ViewportInteractionItem InteractionType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PaintNodeStorage
|
||||||
|
{
|
||||||
|
// 1024 is typically enough to cover the column, after its full it will use dynamicPaintEntries.
|
||||||
|
sfl::static_vector<PaintEntry, 1024> fixedPaintEntries;
|
||||||
|
|
||||||
|
// This has to be wrapped in optional as it allocates memory before it is used.
|
||||||
|
std::optional<sfl::segmented_vector<PaintEntry, 256>> dynamicPaintEntries;
|
||||||
|
|
||||||
|
PaintEntry* allocate()
|
||||||
|
{
|
||||||
|
if (!fixedPaintEntries.full())
|
||||||
|
{
|
||||||
|
return &fixedPaintEntries.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dynamicPaintEntries.has_value())
|
||||||
|
{
|
||||||
|
dynamicPaintEntries.emplace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dynamicPaintEntries->emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
fixedPaintEntries.clear();
|
||||||
|
dynamicPaintEntries.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct PaintSession : public PaintSessionCore
|
struct PaintSession : public PaintSessionCore
|
||||||
{
|
{
|
||||||
DrawPixelInfo DPI;
|
DrawPixelInfo DPI;
|
||||||
PaintEntryPool::Chain PaintEntryChain;
|
PaintNodeStorage paintEntries;
|
||||||
|
|
||||||
PaintStruct* AllocateNormalPaintEntry() noexcept
|
PaintStruct* AllocateNormalPaintEntry() noexcept
|
||||||
{
|
{
|
||||||
auto* entry = PaintEntryChain.Allocate();
|
auto* entry = paintEntries.allocate();
|
||||||
if (entry != nullptr)
|
|
||||||
{
|
|
||||||
LastPS = entry->AsBasic();
|
LastPS = entry->AsBasic();
|
||||||
return LastPS;
|
return LastPS;
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AttachedPaintStruct* AllocateAttachedPaintEntry() noexcept
|
AttachedPaintStruct* AllocateAttachedPaintEntry() noexcept
|
||||||
{
|
{
|
||||||
auto* entry = PaintEntryChain.Allocate();
|
auto* entry = paintEntries.allocate();
|
||||||
if (entry != nullptr)
|
|
||||||
{
|
|
||||||
LastAttachedPS = entry->AsAttached();
|
LastAttachedPS = entry->AsAttached();
|
||||||
return LastAttachedPS;
|
return LastAttachedPS;
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
PaintStringStruct* AllocateStringPaintEntry() noexcept
|
PaintStringStruct* AllocateStringPaintEntry() noexcept
|
||||||
{
|
{
|
||||||
auto* entry = PaintEntryChain.Allocate();
|
auto* entry = paintEntries.allocate();
|
||||||
if (entry != nullptr)
|
|
||||||
{
|
|
||||||
auto* string = entry->AsString();
|
auto* string = entry->AsString();
|
||||||
if (LastPSString == nullptr)
|
if (LastPSString == nullptr)
|
||||||
{
|
{
|
||||||
@@ -248,11 +221,10 @@ struct PaintSession : public PaintSessionCore
|
|||||||
{
|
{
|
||||||
LastPSString->NextEntry = string;
|
LastPSString->NextEntry = string;
|
||||||
}
|
}
|
||||||
|
|
||||||
LastPSString = string;
|
LastPSString = string;
|
||||||
return LastPSString;
|
return LastPSString;
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FootpathPaintInfo
|
struct FootpathPaintInfo
|
||||||
|
|||||||
@@ -166,15 +166,13 @@ PaintSession* Painter::CreateSession(DrawPixelInfo& dpi, uint32_t viewFlags, uin
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create new one in pool.
|
// Create new one in pool.
|
||||||
_paintSessionPool.emplace_back(std::make_unique<PaintSession>());
|
session = &_paintSessionPool.emplace_back();
|
||||||
session = _paintSessionPool.back().get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
session->DPI = dpi;
|
session->DPI = dpi;
|
||||||
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->PaintEntryChain = _paintStructPool.Create();
|
|
||||||
session->Flags = 0;
|
session->Flags = 0;
|
||||||
session->CurrentRotation = rotation;
|
session->CurrentRotation = rotation;
|
||||||
|
|
||||||
@@ -197,15 +195,12 @@ void Painter::ReleaseSession(PaintSession* session)
|
|||||||
{
|
{
|
||||||
PROFILED_FUNCTION();
|
PROFILED_FUNCTION();
|
||||||
|
|
||||||
session->PaintEntryChain.Clear();
|
session->paintEntries.clear();
|
||||||
|
|
||||||
_freePaintSessions.push_back(session);
|
_freePaintSessions.push_back(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
Painter::~Painter()
|
Painter::~Painter()
|
||||||
{
|
{
|
||||||
for (auto&& session : _paintSessionPool)
|
|
||||||
{
|
|
||||||
ReleaseSession(session.get());
|
|
||||||
}
|
|
||||||
_paintSessionPool.clear();
|
_paintSessionPool.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sfl/segmented_vector.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct DrawPixelInfo;
|
struct DrawPixelInfo;
|
||||||
@@ -35,9 +36,8 @@ namespace OpenRCT2
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Ui::IUiContext> const _uiContext;
|
std::shared_ptr<Ui::IUiContext> const _uiContext;
|
||||||
std::vector<std::unique_ptr<PaintSession>> _paintSessionPool;
|
sfl::segmented_vector<PaintSession, 32> _paintSessionPool;
|
||||||
std::vector<PaintSession*> _freePaintSessions;
|
std::vector<PaintSession*> _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;
|
||||||
|
|||||||
Reference in New Issue
Block a user