Skip to content

Commit

Permalink
#5893: Winding registration is taking a render entity reference now. …
Browse files Browse the repository at this point in the history
…The material's WindingRenderer should group the incoming windings by entity and register them, such that they can be picked up by the back end renderer when iterating through entities.

Not functional yet, this is WIP.
  • Loading branch information
codereader committed Feb 6, 2022
1 parent 0bf1d39 commit 9570138
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 67 deletions.
4 changes: 2 additions & 2 deletions include/irender.h
Expand Up @@ -174,14 +174,14 @@ class IRenderEntity
* Associates the given object with this entity and the given shader.
* It will be processed during the following lighting mode rendering passes.
*/
virtual void addRenderable(const render::IRenderableObject::Ptr& object, const ShaderPtr& shader) = 0;
virtual void addRenderable(const render::IRenderableObject::Ptr& object, Shader* shader) = 0;

/**
* Removes the object from this entity.
*/
virtual void removeRenderable(const render::IRenderableObject::Ptr& object) = 0;

using ObjectVisitFunction = std::function<void(const render::IRenderableObject::Ptr&, const ShaderPtr&)>;
using ObjectVisitFunction = std::function<void(const render::IRenderableObject::Ptr&, Shader*)>;

/**
* Enumerate all entity object (partially) intersecting with the given bounds.
Expand Down
11 changes: 8 additions & 3 deletions include/iwindingrenderer.h
Expand Up @@ -5,6 +5,8 @@
#include <cstdint>
#include "render/ArbitraryMeshVertex.h"

class IRenderEntity;

namespace render
{

Expand All @@ -27,14 +29,17 @@ class IWindingRenderer
using Slot = std::uint64_t;
static constexpr Slot InvalidSlot = std::numeric_limits<Slot>::max();

// Allocate a slot to hold the vertex data of a winding of the given size
// Allocate a slot to hold the vertex data of a winding of the given size.
// The winding will be associated to the given render entity (causing it to be grouped internally
// by the render entities when the surfaces are processed in lit render views).
// Returns the handle which can be used to update or deallocate the data later
virtual Slot addWinding(const std::vector<ArbitraryMeshVertex>& vertices) = 0;
virtual Slot addWinding(const std::vector<ArbitraryMeshVertex>& vertices, IRenderEntity* entity) = 0;

// Releases a previously allocated winding slot. This invalidates the handle.
virtual void removeWinding(Slot slot) = 0;

// Sets the winding data
// Updates the winding data. An IRenderEntity change is not supported through updateWinding(), in case the
// winding has to be associated to a different entity, call removeWinding() first.
virtual void updateWinding(Slot slot, const std::vector<ArbitraryMeshVertex>& vertices) = 0;

// Mode used to specify how to render a single winding
Expand Down
2 changes: 1 addition & 1 deletion libs/render/RenderableGeometry.h
Expand Up @@ -173,7 +173,7 @@ class RenderableGeometry :

_renderEntity = entity;
ensureRenderAdapter();
_renderEntity->addRenderable(_renderAdapter, _shader);
_renderEntity->addRenderable(_renderAdapter, _shader.get());
}

void detachFromEntity()
Expand Down
2 changes: 1 addition & 1 deletion libs/render/RenderableSurface.h
Expand Up @@ -106,7 +106,7 @@ class RenderableSurface :
}

_renderEntity = entity;
_renderEntity->addRenderable(shared_from_this(), shader);
_renderEntity->addRenderable(shared_from_this(), shader.get());
_storageLocation = shader->getSurfaceStorageLocation(_shaders[shader]);
}

Expand Down
220 changes: 178 additions & 42 deletions libs/render/WindingRenderer.h
Expand Up @@ -32,18 +32,24 @@ template<>
struct RenderingTraits<WindingIndexer_Lines>
{
constexpr static GLenum Mode() { return GL_LINES; }

constexpr static bool SupportsEntitySurfaces() { return false; }
};

template<>
struct RenderingTraits<WindingIndexer_Triangles>
{
constexpr static GLenum Mode() { return GL_TRIANGLES; }

constexpr static bool SupportsEntitySurfaces() { return true; }
};

template<>
struct RenderingTraits<WindingIndexer_Polygon>
{
constexpr static GLenum Mode() { return GL_POLYGON; }

constexpr static bool SupportsEntitySurfaces() { return false; }
};

template<class WindingIndexerT>
Expand All @@ -63,6 +69,9 @@ class WindingRenderer :
std::vector<typename VertexBuffer::Slot> pendingDeletions;
};

IGeometryStore& _geometryStore;
Shader* _owningShader;

// Maintain one bucket per winding size, allocated on demand
std::vector<Bucket> _buckets;

Expand All @@ -75,26 +84,168 @@ class WindingRenderer :
{
BucketIndex bucketIndex = InvalidBucketIndex;
typename VertexBuffer::Slot slotNumber = InvalidVertexBufferSlot;
IRenderEntity* renderEntity = nullptr;
};

std::vector<SlotMapping> _slots;
static constexpr std::size_t InvalidSlotMapping = std::numeric_limits<std::size_t>::max();
std::size_t _freeSlotMappingHint;

std::size_t _windings;
std::size_t _windingCount;

class WindingGroup :
public IRenderableObject
{
private:
WindingRenderer& _owner;

std::set<std::size_t> _slotIndices;
bool _surfaceNeedsRebuild;
AABB _bounds;
bool _boundsNeedUpdate;

IGeometryStore::Slot _geometrySlot;

sigc::signal<void> _sigBoundsChanged;
public:
WindingGroup(WindingRenderer& owner) :
_owner(owner),
_surfaceNeedsRebuild(true),
_boundsNeedUpdate(true),
_geometrySlot(std::numeric_limits<IGeometryStore::Slot>::max())
{}

void addWinding(std::size_t slotMappingIndex)
{
_slotIndices.insert(slotMappingIndex);
_surfaceNeedsRebuild = true;
_sigBoundsChanged.emit();
}

void updateWinding(std::size_t slotMappingIndex)
{
_surfaceNeedsRebuild = true;
_sigBoundsChanged.emit();
}

void removeWinding(std::size_t slotMappingIndex)
{
_slotIndices.erase(slotMappingIndex);
_surfaceNeedsRebuild = true;
_sigBoundsChanged.emit();
}

bool empty() const
{
return _slotIndices.empty();
}

bool isVisible() override
{
return !empty();
}

const Matrix4& getObjectTransform() override
{
static Matrix4 _identity = Matrix4::getIdentity();
return _identity;
}

const AABB& getObjectBounds() override
{
if (_surfaceNeedsRebuild || _boundsNeedUpdate)
{
_boundsNeedUpdate = false;
_bounds = _owner._geometryStore.getBounds(_geometrySlot);
}

return _bounds;
}

sigc::signal<void>& signal_boundsChanged() override
{
return _sigBoundsChanged;
}

IGeometryStore::Slot getStorageLocation() override
{
return _geometrySlot;
}
};

class EntityWindings
{
private:
WindingRenderer& _owner;

std::map<IRenderEntity*, std::shared_ptr<WindingGroup>> _windingsByEntity;

public:
EntityWindings(WindingRenderer& owner) :
_owner(owner)
{}

void addWinding(std::size_t slotMappingIndex)
{
const auto& slot = _owner._slots[slotMappingIndex];

// Find or create a surface for the entity
auto existing = _windingsByEntity.find(slot.renderEntity);

if (existing != _windingsByEntity.end())
{
existing = _windingsByEntity.emplace(slot.renderEntity,
std::make_shared<WindingGroup>(_owner)).first;

// New surface, register this with the entity
slot.renderEntity->addRenderable(existing->second, _owner._owningShader);
}

existing->second->addWinding(slotMappingIndex);
}

void updateWinding(std::size_t slotMappingIndex)
{
const auto& slot = _owner._slots[slotMappingIndex];
_windingsByEntity[slot.renderEntity]->updateWinding(slotMappingIndex);
}

void removeWinding(std::size_t slotMappingIndex)
{
const auto& slot = _owner._slots[slotMappingIndex];

auto& group = _windingsByEntity[slot.renderEntity];
group->removeWinding(slotMappingIndex);

if (group->empty())
{
slot.renderEntity->removeRenderable(group);
_windingsByEntity.erase(slot.renderEntity);
}
}
};

std::unique_ptr<EntityWindings> _entitySurfaces;

public:
WindingRenderer() :
_windings(0),
WindingRenderer(IGeometryStore& geometryStore, Shader* owningShader) :
_geometryStore(geometryStore),
_owningShader(owningShader),
_windingCount(0),
_freeSlotMappingHint(InvalidSlotMapping)
{}
{
if (RenderingTraits<WindingIndexerT>::SupportsEntitySurfaces())
{
_entitySurfaces.reset(new EntityWindings(*this));
}
}

bool empty() const
{
return _windings == 0;
return _windingCount == 0;
}

Slot addWinding(const std::vector<ArbitraryMeshVertex>& vertices) override
Slot addWinding(const std::vector<ArbitraryMeshVertex>& vertices, IRenderEntity* entity) override
{
auto windingSize = vertices.size();

Expand Down Expand Up @@ -125,7 +276,15 @@ class WindingRenderer :
slotMapping.slotNumber = bucket.buffer.pushWinding(vertices);
}

++_windings;
++_windingCount;

if (RenderingTraits<WindingIndexerT>::SupportsEntitySurfaces())
{
slotMapping.renderEntity = entity;

// Add this winding to the surface associated to the render entity
_entitySurfaces->addWinding(slotMappingIndex);
}

return slotMappingIndex;
}
Expand All @@ -138,35 +297,26 @@ class WindingRenderer :
auto bucketIndex = slotMapping.bucketIndex;
assert(bucketIndex != InvalidBucketIndex);

#if 1
// Mark this winding slot as pending for deletion
_buckets[bucketIndex].pendingDeletions.push_back(slotMapping.slotNumber);
#else
// Remove the winding from the bucket
_buckets[bucketIndex].removeWinding(slotMapping.slotNumber);
// Update the value in other slot mappings, now that the bucket shrunk
for (auto& mapping : _slots)
if (RenderingTraits<WindingIndexerT>::SupportsEntitySurfaces())
{
// Every index in the same bucket beyond the removed winding needs to be shifted to left
if (mapping.bucketIndex == bucketIndex && mapping.slotNumber > slotMapping.slotNumber)
{
--mapping.slotNumber;
}
_entitySurfaces->removeWinding(slot);
}
#endif

// Mark this winding slot as pending for deletion
_buckets[bucketIndex].pendingDeletions.push_back(slotMapping.slotNumber);

// Invalidate the slot mapping
slotMapping.bucketIndex = InvalidBucketIndex;
slotMapping.slotNumber = InvalidVertexBufferSlot;
slotMapping.renderEntity = nullptr;

// Update the free slot hint, for the next round we allocate one
if (slot < _freeSlotMappingHint)
{
_freeSlotMappingHint = slot;
}

--_windings;
--_windingCount;
}

void updateWinding(Slot slot, const std::vector<ArbitraryMeshVertex>& vertices) override
Expand All @@ -184,6 +334,11 @@ class WindingRenderer :
}

bucket.buffer.replaceWinding(slotMapping.slotNumber, vertices);

if (RenderingTraits<WindingIndexerT>::SupportsEntitySurfaces())
{
_entitySurfaces->updateWinding(slot);
}
}

void renderAllWindings(const RenderInfo& info) override
Expand Down Expand Up @@ -276,7 +431,6 @@ class WindingRenderer :

std::sort(bucket.pendingDeletions.begin(), bucket.pendingDeletions.end());

#if 1
// Remove the winding from the bucket
bucket.buffer.removeWindings(bucket.pendingDeletions);

Expand Down Expand Up @@ -311,25 +465,7 @@ class WindingRenderer :
mapping.slotNumber -= maxOffsetToApply;
}
}
#else
for (auto s = bucket.pendingDeletions.rbegin(); s != bucket.pendingDeletions.rend(); ++s)
{
auto slotNumber = *s;
// Remove the winding from the bucket
bucket.buffer.removeWinding(slotNumber);

// Update the value in other slot mappings, now that the bucket shrank
for (auto& mapping : _slots)
{
// Every index in the same bucket beyond the removed winding needs to be shifted to left
if (mapping.bucketIndex == bucketIndex && mapping.slotNumber > slotNumber)
{
--mapping.slotNumber;
}
}
}
#endif
bucket.pendingDeletions.clear();
}

Expand Down

0 comments on commit 9570138

Please sign in to comment.