mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-10 09:32:29 +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 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 ImageId PaintPSColourifyImage(const PaintStruct* ps, ImageId imageId, uint32_t viewFlags);
|
||||
|
||||
@@ -634,7 +633,7 @@ void PaintSessionArrange(PaintSessionCore& 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;
|
||||
if (ps->InteractionItem == ViewportInteractionItem::Entity)
|
||||
@@ -660,15 +659,6 @@ static void PaintDrawStruct(PaintSession& session, PaintStruct* ps)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// Paint parent node.
|
||||
PaintDrawStruct(session, ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x00688596
|
||||
* Part of 0x688485
|
||||
*/
|
||||
static void PaintAttachedPS(DrawPixelInfo& dpi, PaintStruct* ps, uint32_t viewFlags)
|
||||
{
|
||||
AttachedPaintStruct* attached_ps = ps->Attached;
|
||||
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);
|
||||
if (attached_ps->IsMasked)
|
||||
// Paint children.
|
||||
for (auto* psChild = ps->Children; psChild != nullptr; psChild = psChild->NextQuadrantEntry)
|
||||
{
|
||||
GfxDrawSpriteRawMasked(dpi, screenCoords, imageId, attached_ps->ColourImageId);
|
||||
PaintDrawStruct(session, psChild);
|
||||
}
|
||||
else
|
||||
|
||||
// Paint attached.
|
||||
for (auto* psAttached = ps->Attached; psAttached != nullptr; psAttached = psAttached->NextEntry)
|
||||
{
|
||||
GfxDrawSprite(dpi, imageId, screenCoords);
|
||||
const auto screenCoords = ps->ScreenPos + psAttached->RelativePos;
|
||||
|
||||
auto imageId = PaintPSColourifyImage(ps, psAttached->image_id, session.ViewFlags);
|
||||
if (psAttached->IsMasked)
|
||||
{
|
||||
GfxDrawSpriteRawMasked(session.DPI, screenCoords, imageId, psAttached->ColourImageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
GfxDrawSprite(session.DPI, imageId, screenCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1041,134 +1030,3 @@ void PaintDrawMoneyStructs(DrawPixelInfo& dpi, PaintStringStruct* ps)
|
||||
FontStyle::Medium);
|
||||
} 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 <mutex>
|
||||
#include <sfl/segmented_vector.hpp>
|
||||
#include <sfl/static_vector.hpp>
|
||||
#include <thread>
|
||||
|
||||
struct EntityBase;
|
||||
@@ -122,56 +124,6 @@ struct SupportHeight
|
||||
// the quadrant index is based on the x and y components combined.
|
||||
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
|
||||
{
|
||||
PaintStruct* PaintHead;
|
||||
@@ -207,51 +159,71 @@ struct PaintSessionCore
|
||||
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
|
||||
{
|
||||
DrawPixelInfo DPI;
|
||||
PaintEntryPool::Chain PaintEntryChain;
|
||||
PaintNodeStorage paintEntries;
|
||||
|
||||
PaintStruct* AllocateNormalPaintEntry() noexcept
|
||||
{
|
||||
auto* entry = PaintEntryChain.Allocate();
|
||||
if (entry != nullptr)
|
||||
{
|
||||
LastPS = entry->AsBasic();
|
||||
return LastPS;
|
||||
}
|
||||
return nullptr;
|
||||
auto* entry = paintEntries.allocate();
|
||||
LastPS = entry->AsBasic();
|
||||
return LastPS;
|
||||
}
|
||||
|
||||
AttachedPaintStruct* AllocateAttachedPaintEntry() noexcept
|
||||
{
|
||||
auto* entry = PaintEntryChain.Allocate();
|
||||
if (entry != nullptr)
|
||||
{
|
||||
LastAttachedPS = entry->AsAttached();
|
||||
return LastAttachedPS;
|
||||
}
|
||||
return nullptr;
|
||||
auto* entry = paintEntries.allocate();
|
||||
LastAttachedPS = entry->AsAttached();
|
||||
return LastAttachedPS;
|
||||
}
|
||||
|
||||
PaintStringStruct* AllocateStringPaintEntry() noexcept
|
||||
{
|
||||
auto* entry = PaintEntryChain.Allocate();
|
||||
if (entry != nullptr)
|
||||
auto* entry = paintEntries.allocate();
|
||||
|
||||
auto* string = entry->AsString();
|
||||
if (LastPSString == nullptr)
|
||||
{
|
||||
auto* string = entry->AsString();
|
||||
if (LastPSString == nullptr)
|
||||
{
|
||||
PSStringHead = string;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastPSString->NextEntry = string;
|
||||
}
|
||||
LastPSString = string;
|
||||
return LastPSString;
|
||||
PSStringHead = string;
|
||||
}
|
||||
return nullptr;
|
||||
else
|
||||
{
|
||||
LastPSString->NextEntry = string;
|
||||
}
|
||||
|
||||
LastPSString = string;
|
||||
return LastPSString;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -166,15 +166,13 @@ PaintSession* Painter::CreateSession(DrawPixelInfo& dpi, uint32_t viewFlags, uin
|
||||
else
|
||||
{
|
||||
// Create new one in pool.
|
||||
_paintSessionPool.emplace_back(std::make_unique<PaintSession>());
|
||||
session = _paintSessionPool.back().get();
|
||||
session = &_paintSessionPool.emplace_back();
|
||||
}
|
||||
|
||||
session->DPI = dpi;
|
||||
session->ViewFlags = viewFlags;
|
||||
session->QuadrantBackIndex = std::numeric_limits<uint32_t>::max();
|
||||
session->QuadrantFrontIndex = 0;
|
||||
session->PaintEntryChain = _paintStructPool.Create();
|
||||
session->Flags = 0;
|
||||
session->CurrentRotation = rotation;
|
||||
|
||||
@@ -197,15 +195,12 @@ void Painter::ReleaseSession(PaintSession* session)
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
|
||||
session->PaintEntryChain.Clear();
|
||||
session->paintEntries.clear();
|
||||
|
||||
_freePaintSessions.push_back(session);
|
||||
}
|
||||
|
||||
Painter::~Painter()
|
||||
{
|
||||
for (auto&& session : _paintSessionPool)
|
||||
{
|
||||
ReleaseSession(session.get());
|
||||
}
|
||||
_paintSessionPool.clear();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <sfl/segmented_vector.hpp>
|
||||
#include <vector>
|
||||
|
||||
struct DrawPixelInfo;
|
||||
@@ -35,9 +36,8 @@ namespace OpenRCT2
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<Ui::IUiContext> const _uiContext;
|
||||
std::vector<std::unique_ptr<PaintSession>> _paintSessionPool;
|
||||
sfl::segmented_vector<PaintSession, 32> _paintSessionPool;
|
||||
std::vector<PaintSession*> _freePaintSessions;
|
||||
PaintEntryPool _paintStructPool;
|
||||
time_t _lastSecond = 0;
|
||||
int32_t _currentFPS = 0;
|
||||
int32_t _frames = 0;
|
||||
|
||||
Reference in New Issue
Block a user