diff --git a/Bin/CoreData/RenderPaths/Deferred.xml b/Bin/CoreData/RenderPaths/Deferred.xml
index 3acf22265..1c2e9b11b 100644
--- a/Bin/CoreData/RenderPaths/Deferred.xml
+++ b/Bin/CoreData/RenderPaths/Deferred.xml
@@ -18,6 +18,6 @@
-
+
diff --git a/Bin/CoreData/RenderPaths/Forward.xml b/Bin/CoreData/RenderPaths/Forward.xml
index 19e19c614..c7073bcfd 100644
--- a/Bin/CoreData/RenderPaths/Forward.xml
+++ b/Bin/CoreData/RenderPaths/Forward.xml
@@ -6,6 +6,6 @@
-
+
\ No newline at end of file
diff --git a/Bin/CoreData/RenderPaths/ForwardDepth.xml b/Bin/CoreData/RenderPaths/ForwardDepth.xml
index 6be56a38c..0b7cff690 100644
--- a/Bin/CoreData/RenderPaths/ForwardDepth.xml
+++ b/Bin/CoreData/RenderPaths/ForwardDepth.xml
@@ -9,6 +9,6 @@
-
+
\ No newline at end of file
diff --git a/Bin/CoreData/RenderPaths/Prepass.xml b/Bin/CoreData/RenderPaths/Prepass.xml
index c8ee57761..7954e8c65 100644
--- a/Bin/CoreData/RenderPaths/Prepass.xml
+++ b/Bin/CoreData/RenderPaths/Prepass.xml
@@ -19,6 +19,6 @@
-
+
diff --git a/Docs/Reference.dox b/Docs/Reference.dox
index 271acd62d..9cb72975a 100644
--- a/Docs/Reference.dox
+++ b/Docs/Reference.dox
@@ -1076,7 +1076,7 @@ The render path XML definition looks like this:
-
+
diff --git a/Source/Engine/Graphics/Batch.cpp b/Source/Engine/Graphics/Batch.cpp
index 5131595e2..8d738494c 100644
--- a/Source/Engine/Graphics/Batch.cpp
+++ b/Source/Engine/Graphics/Batch.cpp
@@ -766,16 +766,13 @@ unsigned BatchGroupKey::ToHash() const
void BatchQueue::Clear(int maxSortedInstances)
{
batches_.Clear();
- sortedBaseBatches_.Clear();
sortedBatches_.Clear();
- baseBatchGroups_.Clear();
batchGroups_.Clear();
maxSortedInstances_ = maxSortedInstances;
}
void BatchQueue::SortBackToFront()
{
- sortedBaseBatches_.Clear();
sortedBatches_.Resize(batches_.Size());
for (unsigned i = 0; i < batches_.Size(); ++i)
@@ -784,52 +781,23 @@ void BatchQueue::SortBackToFront()
Sort(sortedBatches_.Begin(), sortedBatches_.End(), CompareBatchesBackToFront);
// Do not actually sort batch groups, just list them
- sortedBaseBatchGroups_.Resize(baseBatchGroups_.Size());
sortedBatchGroups_.Resize(batchGroups_.Size());
unsigned index = 0;
- for (HashMap::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
- sortedBaseBatchGroups_[index++] = &i->second_;
- index = 0;
for (HashMap::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
sortedBatchGroups_[index++] = &i->second_;
}
void BatchQueue::SortFrontToBack()
{
- sortedBaseBatches_.Clear();
sortedBatches_.Clear();
- // Need to divide into base and non-base batches here to ensure proper order in relation to grouped batches
for (unsigned i = 0; i < batches_.Size(); ++i)
- {
- if (batches_[i].isBase_)
- sortedBaseBatches_.Push(&batches_[i]);
- else
- sortedBatches_.Push(&batches_[i]);
- }
+ sortedBatches_.Push(&batches_[i]);
- SortFrontToBack2Pass(sortedBaseBatches_);
SortFrontToBack2Pass(sortedBatches_);
// Sort each group front to back
- for (HashMap::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
- {
- if (i->second_.instances_.Size() <= maxSortedInstances_)
- {
- Sort(i->second_.instances_.Begin(), i->second_.instances_.End(), CompareInstancesFrontToBack);
- if (i->second_.instances_.Size())
- i->second_.distance_ = i->second_.instances_[0].distance_;
- }
- else
- {
- float minDistance = M_INFINITY;
- for (PODVector::ConstIterator j = i->second_.instances_.Begin(); j != i->second_.instances_.End(); ++j)
- minDistance = Min(minDistance, j->distance_);
- i->second_.distance_ = minDistance;
- }
- }
-
for (HashMap::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
{
if (i->second_.instances_.Size() <= maxSortedInstances_)
@@ -847,17 +815,12 @@ void BatchQueue::SortFrontToBack()
}
}
- sortedBaseBatchGroups_.Resize(baseBatchGroups_.Size());
sortedBatchGroups_.Resize(batchGroups_.Size());
unsigned index = 0;
- for (HashMap::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
- sortedBaseBatchGroups_[index++] = &i->second_;
- index = 0;
for (HashMap::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
sortedBatchGroups_[index++] = &i->second_;
- SortFrontToBack2Pass(reinterpret_cast& >(sortedBaseBatchGroups_));
SortFrontToBack2Pass(reinterpret_cast& >(sortedBatchGroups_));
}
@@ -923,25 +886,27 @@ void BatchQueue::SortFrontToBack2Pass(PODVector& batches)
void BatchQueue::SetTransforms(void* lockedData, unsigned& freeIndex)
{
- for (HashMap::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
- i->second_.SetTransforms(lockedData, freeIndex);
for (HashMap::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
i->second_.SetTransforms(lockedData, freeIndex);
}
-void BatchQueue::Draw(View* view, bool useScissor, bool markToStencil) const
+void BatchQueue::Draw(View* view, bool markToStencil, bool usingLightOptimization) const
{
Graphics* graphics = view->GetGraphics();
Renderer* renderer = view->GetRenderer();
- graphics->SetScissorTest(false);
+ // If View has set up its own light optimizations, do not disturb the stencil/scissor test settings
+ if (!usingLightOptimization)
+ {
+ graphics->SetScissorTest(false);
+
+ // During G-buffer rendering, mark opaque pixels' lightmask to stencil buffer if requested
+ if (!markToStencil)
+ graphics->SetStencilTest(false);
+ }
- // During G-buffer rendering, mark opaque pixels to stencil buffer
- if (!markToStencil)
- graphics->SetStencilTest(false);
-
- // Base instanced
- for (PODVector::ConstIterator i = sortedBaseBatchGroups_.Begin(); i != sortedBaseBatchGroups_.End(); ++i)
+ // Instanced
+ for (PODVector::ConstIterator i = sortedBatchGroups_.Begin(); i != sortedBatchGroups_.End(); ++i)
{
BatchGroup* group = *i;
if (markToStencil)
@@ -949,104 +914,29 @@ void BatchQueue::Draw(View* view, bool useScissor, bool markToStencil) const
group->Draw(view);
}
- // Base non-instanced
- for (PODVector::ConstIterator i = sortedBaseBatches_.Begin(); i != sortedBaseBatches_.End(); ++i)
+ // Non-instanced
+ for (PODVector::ConstIterator i = sortedBatches_.Begin(); i != sortedBatches_.End(); ++i)
{
Batch* batch = *i;
if (markToStencil)
graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, batch->lightMask_);
-
- batch->Draw(view);
- }
-
- // Non-base instanced
- for (PODVector::ConstIterator i = sortedBatchGroups_.Begin(); i != sortedBatchGroups_.End(); ++i)
- {
- BatchGroup* group = *i;
- if (useScissor && group->lightQueue_)
- renderer->OptimizeLightByScissor(group->lightQueue_->light_, group->camera_);
- if (markToStencil)
- graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, group->lightMask_);
-
- group->Draw(view);
- }
- // Non-base non-instanced
- for (PODVector::ConstIterator i = sortedBatches_.Begin(); i != sortedBatches_.End(); ++i)
- {
- Batch* batch = *i;
- if (useScissor)
+ if (!usingLightOptimization)
{
+ // If drawing an alpha batch, we can optimize fillrate by scissor test
if (!batch->isBase_ && batch->lightQueue_)
renderer->OptimizeLightByScissor(batch->lightQueue_->light_, batch->camera_);
else
graphics->SetScissorTest(false);
}
- if (markToStencil)
- graphics->SetStencilTest(true, CMP_ALWAYS, OP_REF, OP_KEEP, OP_KEEP, batch->lightMask_);
batch->Draw(view);
}
}
-void BatchQueue::Draw(Light* light, View* view) const
-{
- Graphics* graphics = view->GetGraphics();
- Renderer* renderer = view->GetRenderer();
-
- graphics->SetScissorTest(false);
- graphics->SetStencilTest(false);
-
- // Base instanced
- for (PODVector::ConstIterator i = sortedBaseBatchGroups_.Begin(); i != sortedBaseBatchGroups_.End(); ++i)
- {
- BatchGroup* group = *i;
- group->Draw(view);
- }
- // Base non-instanced
- for (PODVector::ConstIterator i = sortedBaseBatches_.Begin(); i != sortedBaseBatches_.End(); ++i)
- {
- Batch* batch = *i;
- batch->Draw(view);
- }
-
- // All base passes have been drawn. Optimize at this point by both stencil volume and scissor
- bool optimized = false;
-
- // Non-base instanced
- for (PODVector::ConstIterator i = sortedBatchGroups_.Begin(); i != sortedBatchGroups_.End(); ++i)
- {
- BatchGroup* group = *i;
- if (!optimized)
- {
- renderer->OptimizeLightByStencil(light, group->camera_);
- renderer->OptimizeLightByScissor(light, group->camera_);
- optimized = true;
- }
- group->Draw(view);
- }
- // Non-base non-instanced
- for (PODVector::ConstIterator i = sortedBatches_.Begin(); i != sortedBatches_.End(); ++i)
- {
- Batch* batch = *i;
- if (!optimized)
- {
- renderer->OptimizeLightByStencil(light, batch->camera_);
- renderer->OptimizeLightByScissor(light, batch->camera_);
- optimized = true;
- }
- batch->Draw(view);
- }
-}
-
unsigned BatchQueue::GetNumInstances() const
{
unsigned total = 0;
- for (HashMap::ConstIterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
- {
- if (i->second_.geometryType_ == GEOM_INSTANCED)
- total += i->second_.instances_.Size();
- }
for (HashMap::ConstIterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
{
if (i->second_.geometryType_ == GEOM_INSTANCED)
diff --git a/Source/Engine/Graphics/Batch.h b/Source/Engine/Graphics/Batch.h
index ef4bdbf7b..c09e7e0b8 100644
--- a/Source/Engine/Graphics/Batch.h
+++ b/Source/Engine/Graphics/Batch.h
@@ -229,16 +229,12 @@ public:
/// Pre-set instance transforms of all groups. The vertex buffer must be big enough to hold all transforms.
void SetTransforms(void* lockedData, unsigned& freeIndex);
/// Draw.
- void Draw(View* view, bool useScissor = false, bool markToStencil = false) const;
- /// Draw with forward light optimizations.
- void Draw(Light* light, View* view) const;
+ void Draw(View* view, bool markToStencil = false, bool usingLightOptimization = false) const;
/// Return the combined amount of instances.
unsigned GetNumInstances() const;
/// Return whether the batch group is empty.
- bool IsEmpty() const { return batches_.Empty() && baseBatchGroups_.Empty() && batchGroups_.Empty(); }
+ bool IsEmpty() const { return batches_.Empty() && batchGroups_.Empty(); }
- /// Instanced draw calls with base flag.
- HashMap baseBatchGroups_;
/// Instanced draw calls.
HashMap batchGroups_;
/// Shader remapping table for 2-pass state and distance sort.
@@ -250,12 +246,8 @@ public:
/// Unsorted non-instanced draw calls.
PODVector batches_;
- /// Sorted non-instanced draw calls with base flag.
- PODVector sortedBaseBatches_;
/// Sorted non-instanced draw calls.
PODVector sortedBatches_;
- /// Sorted instanced draw calls with base flag.
- PODVector sortedBaseBatchGroups_;
/// Sorted instanced draw calls.
PODVector sortedBatchGroups_;
/// Maximum sorted instances.
@@ -284,7 +276,9 @@ struct LightBatchQueue
Light* light_;
/// Shadow map depth texture.
Texture2D* shadowMap_;
- /// Lit geometry draw calls.
+ /// Lit geometry draw calls, base (replace blend mode)
+ BatchQueue litBaseBatches_;
+ /// Lit geometry draw calls, non-base (additive)
BatchQueue litBatches_;
/// Shadow map split queues.
Vector shadowSplits_;
diff --git a/Source/Engine/Graphics/RenderPath.cpp b/Source/Engine/Graphics/RenderPath.cpp
index 1d8de3664..d79ce9945 100644
--- a/Source/Engine/Graphics/RenderPath.cpp
+++ b/Source/Engine/Graphics/RenderPath.cpp
@@ -129,8 +129,6 @@ void RenderPathCommand::Load(const XMLElement& element)
markToStencil_ = element.GetBool("marktostencil");
if (element.HasAttribute("vertexlights"))
vertexLights_ = element.GetBool("vertexlights");
- if (element.HasAttribute("usescissor"))
- useScissor_ = element.GetBool("usescissor");
break;
case CMD_FORWARDLIGHTS:
diff --git a/Source/Engine/Graphics/RenderPath.h b/Source/Engine/Graphics/RenderPath.h
index 223d2c759..3befbd6b6 100644
--- a/Source/Engine/Graphics/RenderPath.h
+++ b/Source/Engine/Graphics/RenderPath.h
@@ -107,7 +107,6 @@ struct RenderPathCommand
useFogColor_(false),
markToStencil_(false),
useLitBase_(true),
- useScissor_(false),
vertexLights_(false)
{
}
@@ -174,8 +173,6 @@ struct RenderPathCommand
bool markToStencil_;
/// Use lit base pass optimization for forward per-pixel lights.
bool useLitBase_;
- /// Scissor optimization flag.
- bool useScissor_;
/// Vertex lights flag.
bool vertexLights_;
};
diff --git a/Source/Engine/Graphics/View.cpp b/Source/Engine/Graphics/View.cpp
index e1d0f877b..f614810ae 100644
--- a/Source/Engine/Graphics/View.cpp
+++ b/Source/Engine/Graphics/View.cpp
@@ -275,6 +275,7 @@ void SortBatchQueueBackToFrontWork(const WorkItem* item, unsigned threadIndex)
void SortLightQueueWork(const WorkItem* item, unsigned threadIndex)
{
LightBatchQueue* start = reinterpret_cast(item->start_);
+ start->litBaseBatches_.SortFrontToBack();
start->litBatches_.SortFrontToBack();
}
@@ -356,7 +357,6 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
info.pass_ = command.pass_;
info.allowInstancing_ = command.sortMode_ != SORT_BACKTOFRONT;
info.markToStencil_ = command.markToStencil_;
- info.useScissor_ = command.useScissor_;
info.vertexLights_ = command.vertexLights_;
// Check scenepass metadata for defining custom passes which interact with lighting
@@ -818,6 +818,7 @@ void View::GetBatches()
light->SetLightQueue(&lightQueue);
lightQueue.light_ = light;
lightQueue.shadowMap_ = 0;
+ lightQueue.litBaseBatches_.Clear(maxSortedInstances);
lightQueue.litBatches_.Clear(maxSortedInstances);
lightQueue.volumeBatches_.Clear();
@@ -1201,7 +1202,12 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
destBatch.zone_ = zone;
if (!isLitAlpha)
- AddBatchToQueue(lightQueue.litBatches_, destBatch, tech);
+ {
+ if (destBatch.isBase_)
+ AddBatchToQueue(lightQueue.litBaseBatches_, destBatch, tech);
+ else
+ AddBatchToQueue(lightQueue.litBatches_, destBatch, tech);
+ }
else if (alphaQueue)
{
// Transparent batches can not be instanced
@@ -1337,7 +1343,7 @@ void View::ExecuteRenderPathCommands()
SetTextures(command);
graphics_->SetFillMode(camera_->GetFillMode());
graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(), camera_->GetProjection());
- batchQueues_[command.pass_].Draw(this, command.useScissor_, command.markToStencil_);
+ batchQueues_[command.pass_].Draw(this, command.markToStencil_, false);
}
break;
@@ -1371,7 +1377,17 @@ void View::ExecuteRenderPathCommands()
SetTextures(command);
graphics_->SetFillMode(camera_->GetFillMode());
graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(), camera_->GetProjection());
- i->litBatches_.Draw(i->light_, this);
+
+ // Draw base (replace blend) batches first
+ i->litBaseBatches_.Draw(this);
+
+ // Then, if there are additive passes, optimize the light and draw them
+ if (!i->litBatches_.IsEmpty())
+ {
+ renderer_->OptimizeLightByScissor(i->light_, camera_);
+ renderer_->OptimizeLightByStencil(i->light_, camera_);
+ i->litBatches_.Draw(this, false, true);
+ }
}
graphics_->SetScissorTest(false);
@@ -2545,11 +2561,10 @@ void View::AddBatchToQueue(BatchQueue& batchQueue, Batch& batch, Technique* tech
if (batch.geometryType_ == GEOM_INSTANCED)
{
- HashMap* groups = batch.isBase_ ? &batchQueue.baseBatchGroups_ : &batchQueue.batchGroups_;
BatchGroupKey key(batch);
- HashMap::Iterator i = groups->Find(key);
- if (i == groups->End())
+ HashMap::Iterator i = batchQueue.batchGroups_.Find(key);
+ if (i == batchQueue.batchGroups_.End())
{
// Create a new group based on the batch
// In case the group remains below the instancing limit, do not enable instancing shaders yet
@@ -2557,7 +2572,7 @@ void View::AddBatchToQueue(BatchQueue& batchQueue, Batch& batch, Technique* tech
newGroup.geometryType_ = GEOM_STATIC;
renderer_->SetBatchShaders(newGroup, tech, allowShadows);
newGroup.CalculateSortKey();
- i = groups->Insert(MakePair(key, newGroup));
+ i = batchQueue.batchGroups_.Insert(MakePair(key, newGroup));
}
int oldSize = i->second_.instances_.Size();
@@ -2591,6 +2606,7 @@ void View::PrepareInstancingBuffer()
{
for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
totalInstances += i->shadowSplits_[j].shadowBatches_.GetNumInstances();
+ totalInstances += i->litBaseBatches_.GetNumInstances();
totalInstances += i->litBatches_.GetNumInstances();
}
@@ -2610,6 +2626,7 @@ void View::PrepareInstancingBuffer()
{
for (unsigned j = 0; j < i->shadowSplits_.Size(); ++j)
i->shadowSplits_[j].shadowBatches_.SetTransforms(dest, freeIndex);
+ i->litBaseBatches_.SetTransforms(dest, freeIndex);
i->litBatches_.SetTransforms(dest, freeIndex);
}
diff --git a/Source/Engine/Script/GraphicsAPI.cpp b/Source/Engine/Script/GraphicsAPI.cpp
index cbf1713de..3f48b0cbb 100644
--- a/Source/Engine/Script/GraphicsAPI.cpp
+++ b/Source/Engine/Script/GraphicsAPI.cpp
@@ -339,7 +339,6 @@ static void RegisterRenderPath(asIScriptEngine* engine)
engine->RegisterObjectProperty("RenderPathCommand", "bool markToStencil", offsetof(RenderPathCommand, markToStencil_));
engine->RegisterObjectProperty("RenderPathCommand", "bool vertexLights", offsetof(RenderPathCommand, vertexLights_));
engine->RegisterObjectProperty("RenderPathCommand", "bool useLitBase", offsetof(RenderPathCommand, useLitBase_));
- engine->RegisterObjectProperty("RenderPathCommand", "bool useScissor", offsetof(RenderPathCommand, useScissor_));
engine->RegisterObjectProperty("RenderPathCommand", "String vertexShaderName", offsetof(RenderPathCommand, vertexShaderName_));
engine->RegisterObjectProperty("RenderPathCommand", "String pixelShaderName", offsetof(RenderPathCommand, pixelShaderName_));
engine->RegisterObjectProperty("RenderPathCommand", "String vertexShaderDefines", offsetof(RenderPathCommand, vertexShaderDefines_));