Add multi-threaded scene rendering with Job System
This commit is contained in:
@@ -555,7 +555,7 @@ void AnimatedModel::UpdateBounds()
|
||||
BoundingBox::Transform(_boxLocal, _transform, _box);
|
||||
BoundingSphere::FromBox(_box, _sphere);
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void AnimatedModel::UpdateSockets()
|
||||
@@ -713,7 +713,13 @@ void AnimatedModel::Draw(RenderContext& renderContext)
|
||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.Position + renderContext.View.Origin));
|
||||
if (_skinningData.IsReady())
|
||||
{
|
||||
_skinningData.Flush(GPUDevice::Instance->GetMainContext());
|
||||
// Flush skinning data with GPU
|
||||
if (_skinningData.IsDirty())
|
||||
{
|
||||
RenderContext::GPULocker.Lock();
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(_skinningData.BoneMatrices, _skinningData.Data.Get(), _skinningData.Data.Count());
|
||||
RenderContext::GPULocker.Unlock();
|
||||
}
|
||||
|
||||
SkinnedMesh::DrawInfo draw;
|
||||
draw.Buffer = &Entries;
|
||||
@@ -749,7 +755,13 @@ void AnimatedModel::Draw(RenderContextBatch& renderContextBatch)
|
||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.Position + renderContext.View.Origin));
|
||||
if (_skinningData.IsReady())
|
||||
{
|
||||
_skinningData.Flush(GPUDevice::Instance->GetMainContext());
|
||||
// Flush skinning data with GPU
|
||||
if (_skinningData.IsDirty())
|
||||
{
|
||||
RenderContext::GPULocker.Lock();
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(_skinningData.BoneMatrices, _skinningData.Data.Get(), _skinningData.Data.Count());
|
||||
RenderContext::GPULocker.Unlock();
|
||||
}
|
||||
|
||||
SkinnedMesh::DrawInfo draw;
|
||||
draw.Buffer = &Entries;
|
||||
@@ -948,7 +960,7 @@ void AnimatedModel::OnTransformChanged()
|
||||
BoundingBox::Transform(_boxLocal, _transform, _box);
|
||||
BoundingSphere::FromBox(_box, _sphere);
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void AnimatedModel::WaitForModelLoad()
|
||||
|
||||
@@ -20,7 +20,7 @@ void ModelInstanceActor::SetEntries(const Array<ModelInstanceEntry>& value)
|
||||
Entries[i] = value[i];
|
||||
}
|
||||
if (anyChanged && _sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material)
|
||||
@@ -33,7 +33,7 @@ void ModelInstanceActor::SetMaterial(int32 entryIndex, MaterialBase* material)
|
||||
return;
|
||||
Entries[entryIndex].Material = material;
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
MaterialInstance* ModelInstanceActor::CreateAndSetVirtualMaterialInstance(int32 entryIndex)
|
||||
@@ -45,7 +45,7 @@ MaterialInstance* ModelInstanceActor::CreateAndSetVirtualMaterialInstance(int32
|
||||
const auto result = material->CreateVirtualInstance();
|
||||
Entries[entryIndex].Material = result;
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -56,12 +56,12 @@ void ModelInstanceActor::WaitForModelLoad()
|
||||
void ModelInstanceActor::OnLayerChanged()
|
||||
{
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void ModelInstanceActor::OnEnable()
|
||||
{
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
|
||||
// Base
|
||||
Actor::OnEnable();
|
||||
@@ -72,5 +72,5 @@ void ModelInstanceActor::OnDisable()
|
||||
// Base
|
||||
Actor::OnDisable();
|
||||
|
||||
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ API_CLASS(Abstract) class FLAXENGINE_API ModelInstanceActor : public Actor
|
||||
{
|
||||
DECLARE_SCENE_OBJECT_ABSTRACT(ModelInstanceActor);
|
||||
protected:
|
||||
int32 _sceneRenderingKey = -1;
|
||||
int32 _sceneRenderingKey = -1; // Uses SceneRendering::DrawCategory::SceneDrawAsync
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -210,7 +210,7 @@ void SplineModel::OnSplineUpdated()
|
||||
BoundingSphere::Merge(_sphere, _instances[i].Sphere, _sphere);
|
||||
BoundingBox::FromSphere(_sphere, _box);
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void SplineModel::UpdateDeformationBuffer()
|
||||
@@ -309,8 +309,7 @@ void SplineModel::UpdateDeformationBuffer()
|
||||
}
|
||||
|
||||
// Flush data with GPU
|
||||
auto context = GPUDevice::Instance->GetMainContext();
|
||||
context->UpdateBuffer(_deformationBuffer, _deformationBufferData, size);
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(_deformationBuffer, _deformationBufferData, size);
|
||||
|
||||
// Static splines are rarely updated so release scratch memory
|
||||
if (IsTransformStatic())
|
||||
@@ -359,7 +358,11 @@ void SplineModel::Draw(RenderContext& renderContext)
|
||||
|
||||
// Build mesh deformation buffer for the whole spline
|
||||
if (_deformationDirty)
|
||||
{
|
||||
RenderContext::GPULocker.Lock();
|
||||
UpdateDeformationBuffer();
|
||||
RenderContext::GPULocker.Unlock();
|
||||
}
|
||||
|
||||
// Draw all segments
|
||||
DrawCall drawCall;
|
||||
|
||||
@@ -173,7 +173,7 @@ void StaticModel::OnModelChanged()
|
||||
if (Model && !Model->IsLoaded())
|
||||
UpdateBounds();
|
||||
else if (!Model && _sceneRenderingKey != -1)
|
||||
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void StaticModel::OnModelLoaded()
|
||||
@@ -190,7 +190,7 @@ void StaticModel::OnModelLoaded()
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,7 +199,7 @@ void StaticModel::OnModelResidencyChanged()
|
||||
{
|
||||
if (_sceneRenderingKey == -1 && _scene && Model && Model->GetLoadedLODs() > 0 && _residencyChangedModel)
|
||||
{
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
_residencyChangedModel->ResidencyChanged.Unbind<StaticModel, &StaticModel::OnModelResidencyChanged>(this);
|
||||
_residencyChangedModel = nullptr;
|
||||
}
|
||||
@@ -219,11 +219,12 @@ void StaticModel::UpdateBounds()
|
||||
}
|
||||
BoundingSphere::FromBox(_box, _sphere);
|
||||
if (_sceneRenderingKey != -1)
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->UpdateActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
|
||||
void StaticModel::FlushVertexColors()
|
||||
{
|
||||
RenderContext::GPULocker.Lock();
|
||||
for (int32 lodIndex = 0; lodIndex < _vertexColorsCount; lodIndex++)
|
||||
{
|
||||
auto& vertexColorsData = _vertexColorsData[lodIndex];
|
||||
@@ -236,7 +237,7 @@ void StaticModel::FlushVertexColors()
|
||||
if (vertexColorsBuffer->GetSize() != size)
|
||||
{
|
||||
if (vertexColorsBuffer->Init(GPUBufferDescription::Vertex(sizeof(Color32), vertexColorsData.Count())))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
GPUDevice::Instance->GetMainContext()->UpdateBuffer(vertexColorsBuffer, vertexColorsData.Get(), size);
|
||||
}
|
||||
@@ -245,6 +246,7 @@ void StaticModel::FlushVertexColors()
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexColorsBuffer);
|
||||
}
|
||||
}
|
||||
RenderContext::GPULocker.Unlock();
|
||||
}
|
||||
|
||||
bool StaticModel::HasContentLoaded() const
|
||||
@@ -559,7 +561,7 @@ void StaticModel::OnEnable()
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->AddActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +576,7 @@ void StaticModel::OnDisable()
|
||||
|
||||
if (_sceneRenderingKey != -1)
|
||||
{
|
||||
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey);
|
||||
GetSceneRendering()->RemoveActor(this, _sceneRenderingKey, SceneRendering::SceneDrawAsync);
|
||||
}
|
||||
if (_residencyChangedModel)
|
||||
{
|
||||
|
||||
@@ -1,25 +1,14 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#define SCENE_RENDERING_USE_PROFILER 0
|
||||
#define SCENE_RENDERING_USE_PROFILER_PER_ACTOR 0
|
||||
|
||||
#include "SceneRendering.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/RenderView.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Threading/JobSystem.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if SCENE_RENDERING_USE_PROFILER
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#endif
|
||||
|
||||
FORCE_INLINE bool FrustumsListCull(const BoundingSphere& bounds, const BoundingFrustum* frustums, int32 frustumsCount)
|
||||
{
|
||||
for (int32 i = 0; i < frustumsCount; i++)
|
||||
{
|
||||
if (frustums[i].Intersects(bounds))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ISceneRenderingListener::~ISceneRenderingListener()
|
||||
{
|
||||
@@ -38,99 +27,65 @@ void ISceneRenderingListener::ListenSceneRendering(SceneRendering* scene)
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE bool FrustumsListCull(const BoundingSphere& bounds, const Array<BoundingFrustum>& frustums)
|
||||
{
|
||||
const int32 count = frustums.Count();
|
||||
const BoundingFrustum* data = frustums.Get();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
if (data[i].Intersects(bounds))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SceneRendering::Draw(RenderContextBatch& renderContextBatch, DrawCategory category)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
auto& view = renderContextBatch.GetMainContext().View;
|
||||
const Vector3 origin = view.Origin;
|
||||
for (auto& renderContext : renderContextBatch.Contexts)
|
||||
renderContext.List->Scenes.Add(this);
|
||||
auto& list = Actors[(int32)category];
|
||||
_drawListData = list.Get();
|
||||
_drawListSize = list.Count();
|
||||
_drawBatch = &renderContextBatch;
|
||||
|
||||
// Setup frustum data
|
||||
Array<BoundingFrustum, RendererAllocation> frustumsData;
|
||||
BoundingFrustum* frustums = &view.CullingFrustum;
|
||||
int32 frustumsCount = renderContextBatch.Contexts.Count();
|
||||
auto& frustumsData = _drawFrustumsData;
|
||||
const int32 frustumsCount = renderContextBatch.Contexts.Count();
|
||||
if (frustumsCount != 1)
|
||||
{
|
||||
frustumsData.Resize(frustumsCount);
|
||||
frustums = frustumsData.Get();
|
||||
for (int32 i = 0; i < frustumsCount; i++)
|
||||
frustums[i] = renderContextBatch.Contexts[i].View.CullingFrustum;
|
||||
frustumsData.Get()[i] = renderContextBatch.Contexts[i].View.CullingFrustum;
|
||||
}
|
||||
|
||||
#define CHECK_ACTOR ((view.RenderLayersMask.Mask & e.LayerMask) && (e.NoCulling || FrustumsListCull(e.Bounds, frustums, frustumsCount)))
|
||||
#define CHECK_ACTOR_SINGLE_FRUSTUM ((view.RenderLayersMask.Mask & e.LayerMask) && (e.NoCulling || frustums->Intersects(e.Bounds)))
|
||||
#if SCENE_RENDERING_USE_PROFILER
|
||||
#define DRAW_ACTOR(mode) PROFILE_CPU_ACTOR(e.Actor); e.Actor->Draw(mode)
|
||||
#else
|
||||
#define DRAW_ACTOR(mode) e.Actor->Draw(mode)
|
||||
#endif
|
||||
|
||||
// Draw all visual components
|
||||
if (view.IsOfflinePass)
|
||||
_drawListIndex = -1;
|
||||
if (_drawListSize >= 64 && category == SceneDrawAsync)
|
||||
{
|
||||
// Offline pass with additional static flags culling
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
e.Bounds.Center -= origin;
|
||||
if (CHECK_ACTOR && e.Actor->GetStaticFlags() & view.StaticFlagsMask)
|
||||
{
|
||||
DRAW_ACTOR(renderContextBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (origin.IsZero() && frustumsCount == 1)
|
||||
{
|
||||
// Fast path for no origin shifting with a single context
|
||||
RenderContext& renderContext = renderContextBatch.GetMainContext();
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
if (CHECK_ACTOR_SINGLE_FRUSTUM)
|
||||
{
|
||||
DRAW_ACTOR(renderContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (origin.IsZero())
|
||||
{
|
||||
// Fast path for no origin shifting
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
if (CHECK_ACTOR)
|
||||
{
|
||||
DRAW_ACTOR(renderContextBatch);
|
||||
}
|
||||
}
|
||||
// Run in async via Job System
|
||||
Function<void(int32)> func;
|
||||
func.Bind<SceneRendering, &SceneRendering::DrawActorsJob>(this);
|
||||
const uint64 waitLabel = JobSystem::Dispatch(func, JobSystem::GetThreadsCount());
|
||||
renderContextBatch.WaitLabels.Add(waitLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generic case
|
||||
for (int32 i = 0; i < list.Count(); i++)
|
||||
{
|
||||
auto e = list.Get()[i];
|
||||
e.Bounds.Center -= origin;
|
||||
if (CHECK_ACTOR)
|
||||
{
|
||||
DRAW_ACTOR(renderContextBatch);
|
||||
}
|
||||
}
|
||||
// Scene is small so draw on a main-thread
|
||||
DrawActorsJob(0);
|
||||
}
|
||||
|
||||
#undef CHECK_ACTOR
|
||||
#undef DRAW_ACTOR
|
||||
#if USE_EDITOR
|
||||
if (view.Pass & DrawPass::GBuffer && category == SceneDraw)
|
||||
{
|
||||
// Draw physics shapes
|
||||
if (view.Flags & ViewFlags::PhysicsDebug || view.Mode == ViewMode::PhysicsColliders)
|
||||
{
|
||||
const PhysicsDebugCallback* physicsDebugData = PhysicsDebug.Get();
|
||||
for (int32 i = 0; i < PhysicsDebug.Count(); i++)
|
||||
{
|
||||
PhysicsDebug[i](view);
|
||||
physicsDebugData[i](view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,7 +99,7 @@ void SceneRendering::CollectPostFxVolumes(RenderContext& renderContext)
|
||||
#endif
|
||||
for (int32 i = 0; i < PostFxProviders.Count(); i++)
|
||||
{
|
||||
PostFxProviders[i]->Collect(renderContext);
|
||||
PostFxProviders.Get()[i]->Collect(renderContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +129,7 @@ void SceneRendering::AddActor(Actor* a, int32& key, DrawCategory category)
|
||||
key = 0;
|
||||
for (; key < list.Count(); key++)
|
||||
{
|
||||
if (list[key].Actor == nullptr)
|
||||
if (list.Get()[key].Actor == nullptr)
|
||||
break;
|
||||
}
|
||||
if (key == list.Count())
|
||||
@@ -217,3 +172,65 @@ void SceneRendering::RemoveActor(Actor* a, int32& key, DrawCategory category)
|
||||
}
|
||||
key = -1;
|
||||
}
|
||||
|
||||
#define FOR_EACH_BATCH_ACTOR const int64 count = _drawListSize; while (true) { const int64 index = Platform::InterlockedIncrement(&_drawListIndex); if (index >= count) break; auto e = _drawListData[index];
|
||||
#define CHECK_ACTOR ((view.RenderLayersMask.Mask & e.LayerMask) && (e.NoCulling || FrustumsListCull(e.Bounds, _drawFrustumsData)))
|
||||
#define CHECK_ACTOR_SINGLE_FRUSTUM ((view.RenderLayersMask.Mask & e.LayerMask) && (e.NoCulling || view.CullingFrustum.Intersects(e.Bounds)))
|
||||
#if SCENE_RENDERING_USE_PROFILER_PER_ACTOR
|
||||
#define DRAW_ACTOR(mode) PROFILE_CPU_ACTOR(e.Actor); e.Actor->Draw(mode)
|
||||
#else
|
||||
#define DRAW_ACTOR(mode) e.Actor->Draw(mode)
|
||||
#endif
|
||||
|
||||
void SceneRendering::DrawActorsJob(int32 i)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
auto& mainContext = _drawBatch->GetMainContext();
|
||||
const auto& view = mainContext.View;
|
||||
if (view.IsOfflinePass)
|
||||
{
|
||||
// Offline pass with additional static flags culling
|
||||
FOR_EACH_BATCH_ACTOR
|
||||
e.Bounds.Center -= view.Origin;
|
||||
if (CHECK_ACTOR && e.Actor->GetStaticFlags() & view.StaticFlagsMask)
|
||||
{
|
||||
DRAW_ACTOR(*_drawBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (view.Origin.IsZero() && _drawFrustumsData.Count() == 1)
|
||||
{
|
||||
// Fast path for no origin shifting with a single context
|
||||
FOR_EACH_BATCH_ACTOR
|
||||
if (CHECK_ACTOR_SINGLE_FRUSTUM)
|
||||
{
|
||||
DRAW_ACTOR(mainContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (view.Origin.IsZero())
|
||||
{
|
||||
// Fast path for no origin shifting
|
||||
FOR_EACH_BATCH_ACTOR
|
||||
if (CHECK_ACTOR)
|
||||
{
|
||||
DRAW_ACTOR(*_drawBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generic case
|
||||
FOR_EACH_BATCH_ACTOR
|
||||
e.Bounds.Center -= view.Origin;
|
||||
if (CHECK_ACTOR)
|
||||
{
|
||||
DRAW_ACTOR(*_drawBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef FOR_EACH_BATCH_ACTOR
|
||||
#undef CHECK_ACTOR
|
||||
#undef DRAW_ACTOR
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Math/BoundingSphere.h"
|
||||
#include "Engine/Core/Math/BoundingFrustum.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Platform/CriticalSection.h"
|
||||
|
||||
@@ -81,6 +82,7 @@ public:
|
||||
enum DrawCategory
|
||||
{
|
||||
SceneDraw = 0,
|
||||
SceneDrawAsync,
|
||||
PreRender,
|
||||
PostRender,
|
||||
MAX
|
||||
@@ -161,4 +163,13 @@ public:
|
||||
ViewportIcons.Remove(obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
Array<BoundingFrustum> _drawFrustumsData;
|
||||
DrawActor* _drawListData;
|
||||
int64 _drawListSize;
|
||||
volatile int64 _drawListIndex;
|
||||
RenderContextBatch* _drawBatch;
|
||||
|
||||
void DrawActorsJob(int32 i);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user