Files
FlaxEngine/Source/Engine/Renderer/Culling/OcclusionCullingTools.h
T

87 lines
2.6 KiB
C++

// Copyright (c) Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Graphics/Config.h"
GPU_CB_STRUCT(OcclusionCullingData {
Matrix ViewProjectionMatrix;
float RTSizeX;
float RTSizeY;
float MaxMipLevel;
uint32 CullCount;
});
/// <summary>
/// Utility for occlusion culling implementations to manage stable CullingId for objects with state tracking (over multiple frames).
/// </summary>
template<typename Item>
class OcclusionCullingItems : public Array<Item>
{
private:
volatile int64 _freeItemsCount = 0;
volatile int64 _newItemsCount = 0;
Array<uint32> _freeItems;
Array<uint32> _freedItems;
public:
void BeginFrame()
{
// Remove used free items
_freeItems.Resize(Math::Max((int32)_freeItemsCount, 0));
// Put back freed items to the free list
_freeItems.Add(_freedItems);
_freedItems.Clear();
// Allocate new items (as requested during the previous frame)
if (_newItemsCount > 0)
{
int32 itemsStart = this->Count(), count = (int32)_newItemsCount, freeStart = _freeItems.Count();
if (itemsStart == 0)
count++; // 0 is invalid for cullingId
this->AddZeroed(count);
_freeItems.AddUninitialized(count);
for (int32 i = 0; i < count; i++)
_freeItems.Get()[freeStart + i] = itemsStart + i;
if (itemsStart == 0)
_freeItems.RemoveAt(0); // 0 is invalid for cullingId
_newItemsCount = 0;
}
_freeItemsCount = _freeItems.Count();
}
bool GetCullingId(uint32& cullingId)
{
// Check if object doesn't have ID assigned yet
if (cullingId == 0 || cullingId >= (uint32)this->Count())
{
int64 freeIndex = Platform::InterlockedDecrement(&_freeItemsCount);
if (freeIndex >= 0)
{
// Use the ID from the free list
ASSERT_LOW_LAYER(freeIndex < _freeItems.Count());
cullingId = _freeItems.Get()[freeIndex];
}
else
{
// Count space needed to contain all objects (for the next frame)
Platform::InterlockedIncrement(&_newItemsCount);
return true;
}
}
return false;
}
void FreeObject(uint32 cullingId)
{
ASSERT(cullingId > 0 && cullingId < (uint32)this->Count());
_freedItems.Add(cullingId);
auto& item = this->Get()[cullingId];
Platform::MemoryClear(&item, sizeof(item));
}
};