Using pool and vector wrapper for planes to prevent allocations

This commit is contained in:
lawnjelly 2019-09-12 19:53:24 +01:00 committed by GitHub
parent da3dff21ba
commit a2281009a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 251 additions and 19 deletions

1
SCsub
View File

@ -6,6 +6,7 @@ sources = [
"lroom.cpp",
"lroom_manager.cpp",
"lportal.cpp",
"lplanes_pool.cpp",
"CoBitField_Dynamic.cpp",
]

47
lplanes_pool.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "lplanes_pool.h"
LPlanesPool::LPlanesPool()
{
Reset();
// preallocate the vectors to a reasonable size
for (int n=0; n<POOL_MAX; n++)
{
m_Planes[n].reserve(32);
}
}
void LPlanesPool::Reset()
{
memset(m_ucTaken, 0, sizeof ( m_ucTaken));
m_uiCount = 0;
}
unsigned int LPlanesPool::Request()
{
// can't do, pool run out
if (m_uiCount >= POOL_MAX)
return -1;
for (unsigned int n=0; n<POOL_MAX; n++)
{
if (m_ucTaken[n] == 0)
{
m_ucTaken[n] = 255;
m_uiCount++;
return n;
}
}
assert (0);
}
void LPlanesPool::Free(unsigned int ui)
{
assert (ui <= POOL_MAX);
assert (m_ucTaken[ui]);
assert (m_uiCount);
m_ucTaken[ui] = 0;
m_uiCount--;
}

23
lplanes_pool.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#include "lvector.h"
#include "core/math/plane.h"
class LPlanesPool
{
public:
const static int POOL_MAX = 32;
void Reset();
unsigned int Request();
void Free(unsigned int ui);
LVector<Plane> &Get(unsigned int ui) {return m_Planes[ui];}
LPlanesPool();
private:
LVector<Plane> m_Planes[ POOL_MAX];
unsigned char m_ucTaken[POOL_MAX];
unsigned int m_uiCount;
};

View File

@ -61,21 +61,32 @@ String LPortal::FindNameAfter(Node * pNode, String szStart)
//////////////////////////////////////////////////////////
// add clipping planes to the vector formed by each portal edge and the camera
void LPortal::AddPlanes(const Vector3 &ptCam, Vector<Plane> &planes) const
void LPortal::AddPlanes(const Vector3 &ptCam, LVector<Plane> &planes) const
{
// short version
const Vector<Vector3> &pts = m_ptsWorld;
int nPoints = pts.size();
// ERR_FAIL_COND(nPoints < 3);
ERR_FAIL_COND(nPoints < 3);
Plane p;
for (int n=1; n<nPoints; n++)
{
p = Plane(ptCam, pts[n], pts[n-1]);
// detect null plane
// if (p.normal.length_squared() < 0.1f)
// {
// print("NULL plane detected from points : ");
// print(ptCam + pts[n] + pts[n-1]);
// }
planes.push_back(p);
}
// first and last
p = Plane(ptCam, pts[0], pts[nPoints-1]);
planes.push_back(p);
}
@ -93,7 +104,10 @@ LPortal::eClipResult LPortal::ClipWithPlane(const Plane &p) const
}
if (nOutside == nPoints)
{
print("LPortal::ClipWithPlane : Outside plane " + p);
return CLIP_OUTSIDE;
}
if (nOutside == 0)
return CLIP_INSIDE;

View File

@ -28,6 +28,7 @@
#include "scene/3d/spatial.h"
#include "lvector.h"
class LRoom;
@ -52,7 +53,7 @@ protected:
static void _bind_methods();
LPortal::eClipResult ClipWithPlane(const Plane &p) const;
void AddPlanes(const Vector3 &ptCam, Vector<Plane> &planes) const;
void AddPlanes(const Vector3 &ptCam, LVector<Plane> &planes) const;
public:
// normal determined by winding order

View File

@ -23,17 +23,19 @@
#include "scene/3d/mesh_instance.h"
#include "lportal.h"
#include "CoBitField_Dynamic.h"
#include "lroom_manager.h"
void LRoom::print(String sz)
{
// print_line(sz);
LPortal::print(sz);
}
LRoom::LRoom() {
m_LocalRoomID = -1;
}
void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector<Plane> &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from)
void LRoom::DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from)
{
// prevent too much depth
if (depth >= 8)
@ -60,7 +62,7 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V
VisualInstance * pObj = Object::cast_to<VisualInstance>(pNode);
if (pObj)
{
Vector3 pt = pObj->get_global_transform().origin;
//Vector3 pt = pObj->get_global_transform().origin;
bool bShow = true;
@ -102,7 +104,7 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V
// go through each portal out of here
int nPortals = m_portal_IDs.size();
ObjectID this_room_id = get_instance_id();
// ObjectID this_room_id = get_instance_id();
for (int p=0; p<nPortals; p++)
{
@ -165,7 +167,14 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V
}
// else recurse into that portal
Vector<Plane> new_planes = planes;
unsigned int uiPoolMem = manager.m_Pool.Request();
if (uiPoolMem != -1)
{
// get a vector of planes from the pool
LVector<Plane> &new_planes = manager.m_Pool.Get(uiPoolMem);
// copy the existing planes
new_planes.copy_from(planes);
// add the planes for the portal
pPortal->AddPlanes(cam.m_ptPos, new_planes);
@ -173,7 +182,15 @@ void LRoom::DetermineVisibility_Recursive(int depth, const LCamera &cam, const V
// get the room pointed to by the portal
LRoom * pLinkedRoom = pPortal->GetLinkedRoom();
if (pLinkedRoom)
pLinkedRoom->DetermineVisibility_Recursive(depth + 1, cam, new_planes, BF_visible, id);
pLinkedRoom->DetermineVisibility_Recursive(manager, depth + 1, cam, new_planes, BF_visible, id);
manager.m_Pool.Free(uiPoolMem);
}
else
{
// planes pool is empty!
WARN_PRINT_ONCE("Planes pool is empty");
}
}
}

View File

@ -28,11 +28,13 @@
#include "scene/3d/spatial.h"
#include "lvector.h"
namespace Core {class CoBitField_Dynamic;}
class LPortal;
class LRoomManager;
class MeshInstance;
class LCamera
@ -68,7 +70,7 @@ public:
void MakePortalQuickList();
// main function
void DetermineVisibility_Recursive(int depth, const LCamera &cam, const Vector<Plane> &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from = 0);
void DetermineVisibility_Recursive(LRoomManager &manager, int depth, const LCamera &cam, const LVector<Plane> &planes, Core::CoBitField_Dynamic &BF_visible, ObjectID portalID_from = 0);
// specific
public:

View File

@ -28,6 +28,7 @@ LRoomManager::LRoomManager()
{
m_room_curr = 0;
m_cameraID = 0;
}
@ -232,7 +233,13 @@ void LRoomManager::FrameUpdate()
cam.m_ptPos = Vector3(0, 0, 0);
cam.m_ptDir = Vector3 (-1, 0, 0);
Vector<Plane> planes;
// reset the pool for another frame
m_Pool.Reset();
unsigned int pool_member = m_Pool.Request();
assert (pool_member != -1);
LVector<Plane> &planes = m_Pool.Get(pool_member);
planes.clear();
// get the camera desired and make into lcamera
if (m_cameraID)
@ -246,11 +253,11 @@ void LRoomManager::FrameUpdate()
cam.m_ptPos = tr.origin;
cam.m_ptDir = tr.basis.get_row(2); // or possibly get_axis .. z is what we want
planes = pCamera->get_frustum();
planes.copy_from(pCamera->get_frustum());
}
}
pRoom->DetermineVisibility_Recursive(0, cam, planes, m_BF_visible_rooms);
pRoom->DetermineVisibility_Recursive(*this, 0, cam, planes, m_BF_visible_rooms);
// finally hide all the rooms that are currently visible but not in the visible bitfield as having been hit

View File

@ -28,10 +28,13 @@
#include "scene/3d/spatial.h"
#include "CoBitField_Dynamic.h"
#include "lplanes_pool.h"
class LRoomManager : public Spatial {
GDCLASS(LRoomManager, Spatial);
friend class LRoom;
// a quick list of object IDs of child rooms
Vector<ObjectID> m_room_IDs;
@ -40,20 +43,24 @@ class LRoomManager : public Spatial {
// keep track of which rooms are visible, so we can hide ones that aren't hit that were previously on
Core::CoBitField_Dynamic m_BF_visible_rooms;
// Vector<int> m_VisibleRoomList[2];
// int m_CurrentVisibleRoomList;
Vector<int> m_VisibleRoomList[2];
int m_CurrentVisibleRoomList;
public:
LRoomManager();
// convert empties and meshes to rooms and portals
void convert();
// choose which camera you want to use to determine visibility.
// normally this will be your main camera, but you can choose another for debugging
void set_camera(Node * pCam);
protected:
static void _bind_methods();
void _notification(int p_what);
LPlanesPool m_Pool;
private:
void Convert_Rooms();
bool Convert_Room(Spatial * pNode);

113
lvector.h Normal file
View File

@ -0,0 +1,113 @@
#pragma once
// just a light wrapper around the Godot vector until we get the allocation issues sorted
#include "core/vector.h"
#include <assert.h>
template <class T> class LVector
{
public:
// array subscript access
T& operator[](unsigned int ui)
{
assert (ui < m_iSize);
return m_Vec[ui];
}
const T& operator[](unsigned int ui) const
{
assert (ui < m_iSize);
return m_Vec[ui];
}
void clear(bool bCompact = false)
{
m_iSize = 0;
if (bCompact)
compact();
}
void compact()
{
m_Vec.resize(m_iSize);
}
void reserve(int s)
{
m_Vec.resize(s);
}
void set(unsigned int ui, const T &t)
{
assert (ui < m_iSize);
m_Vec.set(ui, t);
}
void push_back(const T &t)
{
int size_p1 = m_iSize+1;
if (size_p1 < m_Vec.size())
{
int size = m_iSize;
m_iSize = size_p1;
m_Vec.set(size, t);
}
else
{
// need more space
reserve(m_Vec.size() * 2);
// call recursive
push_back(t);
}
}
void copy_from(const LVector<T> &o)
{
// make sure enough space
if (o.size() > m_Vec.size())
{
reserve(o.size());
}
clear();
m_iSize = o.size();
for (int n=0; n<o.size(); n++)
{
set(n, o[n]);
}
}
void copy_from(const Vector<T> &o)
{
// make sure enough space
if (o.size() > m_Vec.size())
{
reserve(o.size());
}
clear();
m_iSize = o.size();
for (int n=0; n<o.size(); n++)
{
set(n, o[n]);
}
}
LVector()
{
m_iSize = 0;
}
int size() const {return m_iSize;}
private:
Vector<T> m_Vec;
// working size
int m_iSize;
};