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_));