Browse Source

Refactor Technique to not use HashTable for passes, but instead a vector with dynamically allocated pass indices. HashTable class removed as there were no other uses for it, and it was programmer-unfriendly compared to HashMap.

Lasse Öörni 10 years ago
parent
commit
e2afa34bb7

+ 0 - 191
Source/Urho3D/Container/HashTable.h

@@ -1,191 +0,0 @@
-//
-// Copyright (c) 2008-2015 the Urho3D project.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-#include "../Container/Allocator.h"
-#include "../Container/Vector.h"
-
-namespace Urho3D
-{
-
-/// Hash table with fixed bucket count. Does not support iteration. Should only be used when performance is critical, as HashMap is much more user-friendly.
-template <class T, unsigned U> class HashTable
-{
-public:
-    /// Hash table node.
-    struct Node
-    {
-        /// Construct.
-        Node(unsigned hash, const T& value, Node* next) :
-            hash_(hash),
-            value_(value),
-            next_(next)
-        {
-        }
-        
-        /// Hash value.
-        unsigned hash_;
-        /// Node value.
-        T value_;
-        /// Next node in bucket.
-        Node* next_;
-    };
-    
-    /// Construct empty.
-    HashTable() :
-        allocator_(0)
-    {
-        for (unsigned i = 0; i < U; ++i)
-            ptrs_[i] = 0;
-    }
-    
-    /// Destruct.
-    ~HashTable()
-    {
-        Clear();
-        AllocatorUninitialize(allocator_);
-    }
-    
-    /// Insert by hash value. If value with same hash already exists, it is replaced.
-    void Insert(unsigned hash, const T& value)
-    {
-        unsigned bucket = hash & (U - 1);
-        
-        if (!allocator_)
-            allocator_ = AllocatorInitialize(sizeof(Node));
-        
-        Node* ptr = ptrs_[bucket];
-        while (ptr)
-        {
-            if (ptr->hash_ == hash)
-            {
-                ptr->value_ = value;
-                return;
-            }
-            ptr = ptr->next_;
-        }
-        
-        Node* newNode = static_cast<Node*>(AllocatorReserve(allocator_));
-        // Insert at the top of the bucket, connect to the previous top node if exists
-        new(newNode) Node(hash, value, ptrs_[bucket]);
-        ptrs_[bucket] = newNode;
-    }
-    
-    /// Remove by hash value. Return true if was found and removed.
-    bool Erase(unsigned hash)
-    {
-        unsigned bucket = hash & (U - 1);
-        
-        Node* ptr = ptrs_[bucket];
-        while (ptr)
-        {
-            if (ptr->hash_ == hash)
-            {
-                (ptr)->~Node();
-                AllocatorFree(allocator_, ptr);
-                return true;
-            }
-            else
-                ptr = ptr->next_;
-        }
-        
-        return false;
-    }
-    
-    /// Remove all values.
-    void Clear()
-    {
-        for (unsigned i = 0; i < U; ++i)
-        {
-            Node* ptr = ptrs_[i];
-            while (ptr)
-            {
-                Node* next = ptr->next_;
-                (ptr)->~Node();
-                AllocatorFree(allocator_, ptr);
-                ptr = next;
-            }
-        }
-    }
-    
-    /// Find by hash value. Return pointer if was found or null if not found.
-    T* Find(unsigned hash) const
-    {
-        unsigned bucket = hash & (U - 1);
-        
-        Node* ptr = ptrs_[bucket];
-        while (ptr)
-        {
-            if (ptr->hash_ == hash)
-                return &ptr->value_;
-            else
-                ptr = ptr->next_;
-        }
-        
-        return 0;
-    }
-    
-    /// Return all the keys.
-    PODVector<unsigned> Keys() const
-    {
-        PODVector<unsigned> ret;
-
-        for (unsigned i = 0; i < U; ++i)
-        {
-            Node* ptr = ptrs_[i];
-            while (ptr)
-            {
-                ret.Push(ptr->hash_);
-                ptr = ptr->next_;
-            }
-        }
-
-        return ret;
-    }
-
-    /// Return pointers to all values.
-    PODVector<T*> Values() const
-    {
-        PODVector<T*> ret;
-        
-        for (unsigned i = 0; i < U; ++i)
-        {
-            Node* ptr = ptrs_[i];
-            while (ptr)
-            {
-                ret.Push(&ptr->value_);
-                ptr = ptr->next_;
-            }
-        }
-        
-        return ret;
-    }
-    
-private:
-    /// Allocator.
-    AllocatorBlock* allocator_;
-    /// Bucket pointers, fixed size.
-    Node* ptrs_[U];
-};
-
-}

+ 3 - 3
Source/Urho3D/Graphics/Batch.cpp

@@ -182,8 +182,6 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     // Set pass / material-specific renderstates
     // Set pass / material-specific renderstates
     if (pass_ && material_)
     if (pass_ && material_)
     {
     {
-        bool isShadowPass = pass_->GetType() == PASS_SHADOW;
-        
         BlendMode blend = pass_->GetBlendMode();
         BlendMode blend = pass_->GetBlendMode();
         // Turn additive blending into subtract if the light is negative
         // Turn additive blending into subtract if the light is negative
         if (light && light->IsNegative())
         if (light && light->IsNegative())
@@ -193,14 +191,16 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
             else if (blend == BLEND_ADDALPHA)
             else if (blend == BLEND_ADDALPHA)
                 blend = BLEND_SUBTRACTALPHA;
                 blend = BLEND_SUBTRACTALPHA;
         }
         }
-        
         graphics->SetBlendMode(blend);
         graphics->SetBlendMode(blend);
+
+        bool isShadowPass = pass_->GetIndex() == Technique::shadowPassIndex;
         renderer->SetCullMode(isShadowPass ? material_->GetShadowCullMode() : material_->GetCullMode(), camera_);
         renderer->SetCullMode(isShadowPass ? material_->GetShadowCullMode() : material_->GetCullMode(), camera_);
         if (!isShadowPass)
         if (!isShadowPass)
         {
         {
             const BiasParameters& depthBias = material_->GetDepthBias();
             const BiasParameters& depthBias = material_->GetDepthBias();
             graphics->SetDepthBias(depthBias.constantBias_, depthBias.slopeScaledBias_);
             graphics->SetDepthBias(depthBias.constantBias_, depthBias.slopeScaledBias_);
         }
         }
+
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthWrite(pass_->GetDepthWrite() && allowDepthWrite);
         graphics->SetDepthWrite(pass_->GetDepthWrite() && allowDepthWrite);
     }
     }

+ 0 - 13
Source/Urho3D/Graphics/GraphicsDefs.cpp

@@ -76,19 +76,6 @@ extern URHO3D_API const StringHash PSP_SHADOWMAPINVSIZE("ShadowMapInvSize");
 extern URHO3D_API const StringHash PSP_SHADOWSPLITS("ShadowSplits");
 extern URHO3D_API const StringHash PSP_SHADOWSPLITS("ShadowSplits");
 extern URHO3D_API const StringHash PSP_LIGHTMATRICES("LightMatricesPS");
 extern URHO3D_API const StringHash PSP_LIGHTMATRICES("LightMatricesPS");
 
 
-extern URHO3D_API const StringHash PASS_BASE("base");
-extern URHO3D_API const StringHash PASS_LITBASE("litbase");
-extern URHO3D_API const StringHash PASS_LIGHT("light");
-extern URHO3D_API const StringHash PASS_ALPHA("alpha");
-extern URHO3D_API const StringHash PASS_LITALPHA("litalpha");
-extern URHO3D_API const StringHash PASS_SHADOW("shadow");
-extern URHO3D_API const StringHash PASS_DEFERRED("deferred");
-extern URHO3D_API const StringHash PASS_PREPASS("prepass");
-extern URHO3D_API const StringHash PASS_MATERIAL("material");
-extern URHO3D_API const StringHash PASS_POSTOPAQUE("postopaque");
-extern URHO3D_API const StringHash PASS_REFRACT("refract");
-extern URHO3D_API const StringHash PASS_POSTALPHA("postalpha");
-
 extern URHO3D_API const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
 extern URHO3D_API const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
 
 
 }
 }

+ 0 - 14
Source/Urho3D/Graphics/GraphicsDefs.h

@@ -322,20 +322,6 @@ extern URHO3D_API const StringHash PSP_SHADOWMAPINVSIZE;
 extern URHO3D_API const StringHash PSP_SHADOWSPLITS;
 extern URHO3D_API const StringHash PSP_SHADOWSPLITS;
 extern URHO3D_API const StringHash PSP_LIGHTMATRICES;
 extern URHO3D_API const StringHash PSP_LIGHTMATRICES;
 
 
-// Inbuilt pass types
-extern URHO3D_API const StringHash PASS_BASE;
-extern URHO3D_API const StringHash PASS_LITBASE;
-extern URHO3D_API const StringHash PASS_LIGHT;
-extern URHO3D_API const StringHash PASS_ALPHA;
-extern URHO3D_API const StringHash PASS_LITALPHA;
-extern URHO3D_API const StringHash PASS_SHADOW;
-extern URHO3D_API const StringHash PASS_DEFERRED;
-extern URHO3D_API const StringHash PASS_PREPASS;
-extern URHO3D_API const StringHash PASS_MATERIAL;
-extern URHO3D_API const StringHash PASS_POSTOPAQUE;
-extern URHO3D_API const StringHash PASS_REFRACT;
-extern URHO3D_API const StringHash PASS_POSTALPHA;
-
 // Scale calculation from bounding box diagonal.
 // Scale calculation from bounding box diagonal.
 extern URHO3D_API const Vector3 DOT_SCALE;
 extern URHO3D_API const Vector3 DOT_SCALE;
 
 

+ 3 - 3
Source/Urho3D/Graphics/Material.cpp

@@ -676,10 +676,10 @@ Technique* Material::GetTechnique(unsigned index) const
     return index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
     return index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
 }
 }
 
 
-Pass* Material::GetPass(unsigned index, StringHash passType) const
+Pass* Material::GetPass(unsigned index, const String& passName) const
 {
 {
     Technique* tech = index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
     Technique* tech = index < techniques_.Size() ? techniques_[index].technique_ : (Technique*)0;
-    return tech ? tech->GetPass(passType) : 0;
+    return tech ? tech->GetPass(passName) : 0;
 }
 }
 
 
 Texture* Material::GetTexture(TextureUnit unit) const
 Texture* Material::GetTexture(TextureUnit unit) const
@@ -740,7 +740,7 @@ void Material::CheckOcclusion()
         Technique* tech = techniques_[i].technique_;
         Technique* tech = techniques_[i].technique_;
         if (tech)
         if (tech)
         {
         {
-            Pass* pass = tech->GetPass(PASS_BASE);
+            Pass* pass = tech->GetPass("base");
             if (pass && pass->GetDepthWrite() && !pass->GetAlphaMask())
             if (pass && pass->GetDepthWrite() && !pass->GetAlphaMask())
                 occlusion_ = true;
                 occlusion_ = true;
         }
         }

+ 2 - 2
Source/Urho3D/Graphics/Material.h

@@ -165,8 +165,8 @@ public:
     const TechniqueEntry& GetTechniqueEntry(unsigned index) const;
     const TechniqueEntry& GetTechniqueEntry(unsigned index) const;
     /// Return technique by index.
     /// Return technique by index.
     Technique* GetTechnique(unsigned index) const;
     Technique* GetTechnique(unsigned index) const;
-    /// Return pass by technique index and pass type.
-    Pass* GetPass(unsigned index, StringHash passType) const;
+    /// Return pass by technique index and pass name.
+    Pass* GetPass(unsigned index, const String& passName) const;
     /// Return texture by unit.
     /// Return texture by unit.
     Texture* GetTexture(TextureUnit unit) const;
     Texture* GetTexture(TextureUnit unit) const;
    /// Return all textures.
    /// Return all textures.

+ 2 - 0
Source/Urho3D/Graphics/RenderPath.h

@@ -146,6 +146,8 @@ struct RenderPathCommand
     RenderCommandSortMode sortMode_;
     RenderCommandSortMode sortMode_;
     /// Scene pass name.
     /// Scene pass name.
     String pass_;
     String pass_;
+    /// Scene pass index. Filled by View.
+    unsigned passIndex_;
     /// Command/pass metadata.
     /// Command/pass metadata.
     String metadata_;
     String metadata_;
     /// Vertex shader name.
     /// Vertex shader name.

+ 2 - 6
Source/Urho3D/Graphics/Renderer.cpp

@@ -1044,7 +1044,7 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* tech, bool allowShadows)
     {
     {
         // First release all previous shaders, then load
         // First release all previous shaders, then load
         pass->ReleaseShaders();
         pass->ReleaseShaders();
-        LoadPassShaders(tech, pass->GetType());
+        LoadPassShaders(pass);
     }
     }
     
     
     // Make sure shaders are loaded now
     // Make sure shaders are loaded now
@@ -1457,12 +1457,8 @@ void Renderer::LoadShaders()
     shadersDirty_ = false;
     shadersDirty_ = false;
 }
 }
 
 
-void Renderer::LoadPassShaders(Technique* tech, StringHash type)
+void Renderer::LoadPassShaders(Pass* pass)
 {
 {
-    Pass* pass = tech->GetPass(type);
-    if (!pass)
-        return;
-    
     PROFILE(LoadPassShaders);
     PROFILE(LoadPassShaders);
     
     
     unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
     unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);

+ 1 - 1
Source/Urho3D/Graphics/Renderer.h

@@ -331,7 +331,7 @@ private:
     /// Reload shaders.
     /// Reload shaders.
     void LoadShaders();
     void LoadShaders();
     /// Reload shaders for a material pass.
     /// Reload shaders for a material pass.
-    void LoadPassShaders(Technique* tech, StringHash passType);
+    void LoadPassShaders(Pass* pass);
     /// Release shaders used in materials.
     /// Release shaders used in materials.
     void ReleaseMaterialShaders();
     void ReleaseMaterialShaders();
     /// Reload textures.
     /// Reload textures.

+ 120 - 38
Source/Urho3D/Graphics/Technique.cpp

@@ -69,8 +69,7 @@ static const char* lightingModeNames[] =
     0
     0
 };
 };
 
 
-Pass::Pass(StringHash type) :
-    type_(type),
+Pass::Pass(const String& name) :
     blendMode_(BLEND_REPLACE),
     blendMode_(BLEND_REPLACE),
     depthTestMode_(CMP_LESSEQUAL),
     depthTestMode_(CMP_LESSEQUAL),
     lightingMode_(LIGHTING_UNLIT),
     lightingMode_(LIGHTING_UNLIT),
@@ -79,10 +78,14 @@ Pass::Pass(StringHash type) :
     alphaMask_(false),
     alphaMask_(false),
     isDesktop_(false)
     isDesktop_(false)
 {
 {
+    name_ = name.ToLower();
+    index_ = Technique::GetPassIndex(name_);
+
     // Guess default lighting mode from pass name
     // Guess default lighting mode from pass name
-    if (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
+    if (index_ == Technique::basePassIndex || index_ == Technique::alphaPassIndex || index_ == Technique::materialPassIndex ||
+        index_ == Technique::deferredPassIndex)
         lightingMode_ = LIGHTING_PERVERTEX;
         lightingMode_ = LIGHTING_PERVERTEX;
-    else if (type == PASS_LIGHT || type == PASS_LITBASE || type == PASS_LITALPHA)
+    else if (index_ == Technique::lightPassIndex || index_ == Technique::litBasePassIndex || index_ == Technique::litAlphaPassIndex)
         lightingMode_ = LIGHTING_PERPIXEL;
         lightingMode_ = LIGHTING_PERPIXEL;
 }
 }
 
 
@@ -155,10 +158,19 @@ void Pass::MarkShadersLoaded(unsigned frameNumber)
     shadersLoadedFrameNumber_ = frameNumber;
     shadersLoadedFrameNumber_ = frameNumber;
 }
 }
 
 
+unsigned Technique::basePassIndex = 0;
+unsigned Technique::alphaPassIndex = 0;
+unsigned Technique::materialPassIndex = 0;
+unsigned Technique::deferredPassIndex = 0;
+unsigned Technique::lightPassIndex = 0;
+unsigned Technique::litBasePassIndex = 0;
+unsigned Technique::litAlphaPassIndex = 0;
+unsigned Technique::shadowPassIndex = 0;
+HashMap<String, unsigned> Technique::passIndices;
+
 Technique::Technique(Context* context) :
 Technique::Technique(Context* context) :
     Resource(context),
     Resource(context),
-    isDesktop_(false),
-    numPasses_(0)
+    isDesktop_(false)
 {
 {
     #ifdef DESKTOP_GRAPHICS
     #ifdef DESKTOP_GRAPHICS
     desktopSupport_ = true;
     desktopSupport_ = true;
@@ -180,7 +192,6 @@ bool Technique::BeginLoad(Deserializer& source)
 {
 {
     passes_.Clear();
     passes_.Clear();
 
 
-    numPasses_ = 0;
     SetMemoryUse(sizeof(Technique));
     SetMemoryUse(sizeof(Technique));
     
     
     SharedPtr<XMLFile> xml(new XMLFile(context_));
     SharedPtr<XMLFile> xml(new XMLFile(context_));
@@ -209,10 +220,8 @@ bool Technique::BeginLoad(Deserializer& source)
     {
     {
         if (passElem.HasAttribute("name"))
         if (passElem.HasAttribute("name"))
         {
         {
-            StringHash nameHash(passElem.GetAttribute("name"));
-            
-            Pass* newPass = CreatePass(nameHash);
-            
+            Pass* newPass = CreatePass(passElem.GetAttribute("name"));
+
             if (passElem.HasAttribute("desktop"))
             if (passElem.HasAttribute("desktop"))
                 newPass->SetIsDesktop(passElem.GetBool("desktop"));
                 newPass->SetIsDesktop(passElem.GetBool("desktop"));
             
             
@@ -284,55 +293,128 @@ void Technique::SetIsDesktop(bool enable)
 
 
 void Technique::ReleaseShaders()
 void Technique::ReleaseShaders()
 {
 {
-    PODVector<SharedPtr<Pass>*> allPasses = passes_.Values();
-    
-    for (unsigned i = 0; i < allPasses.Size(); ++i)
-        allPasses[i]->Get()->ReleaseShaders();
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        Pass* pass = i->Get();
+        if (pass)
+            pass->ReleaseShaders();
+    }
 }
 }
 
 
-Pass* Technique::CreatePass(StringHash type)
+Pass* Technique::CreatePass(const String& name)
 {
 {
-    Pass* oldPass = GetPass(type);
+    Pass* oldPass = GetPass(name);
     if (oldPass)
     if (oldPass)
         return oldPass;
         return oldPass;
     
     
-    SharedPtr<Pass> newPass(new Pass(type));
-    passes_.Insert(type.Value(), newPass);
+    SharedPtr<Pass> newPass(new Pass(name));
+    unsigned passIndex = newPass->GetIndex();
+    if (passIndex >= passes_.Size())
+        passes_.Resize(passIndex + 1);
+    passes_[passIndex] = newPass;
     
     
     // Calculate memory use now
     // Calculate memory use now
-    SetMemoryUse(sizeof(Technique) + ++numPasses_ * sizeof(Pass));
+    SetMemoryUse(sizeof(Technique) + GetNumPasses() * sizeof(Pass));
 
 
     return newPass;
     return newPass;
 }
 }
 
 
-void Technique::RemovePass(StringHash type)
+void Technique::RemovePass(const String& name)
 {
 {
-    if (passes_.Erase(type.Value()))
-        SetMemoryUse(sizeof(Technique) + --numPasses_ * sizeof(Pass));
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    if (i == passIndices.End())
+        return;
+    else if (i->second_ < passes_.Size() && passes_[i->second_].Get())
+    {
+        passes_[i->second_].Reset();
+        SetMemoryUse(sizeof(Technique) + GetNumPasses() * sizeof(Pass));
+    }
 }
 }
 
 
-Vector<StringHash> Technique::GetPassTypes() const
+bool Technique::HasPass(const String& name) const
 {
 {
-    // Convert PODVector<unsigned> to Vector<StringHash>
-    PODVector<unsigned> vectorIn = passes_.Keys();
-    Vector<StringHash> vectorOut;
-    vectorOut.Reserve(vectorIn.Size());
-    for (unsigned i = 0; i < vectorIn.Size(); ++i)
-        vectorOut.Push(StringHash(vectorIn[i]));
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    return i != passIndices.End() ? HasPass(i->second_) : false;
+}
 
 
-    return vectorOut;
+Pass* Technique::GetPass(const String& name) const
+{
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    return i != passIndices.End() ? GetPass(i->second_) : 0;
+}
+
+Pass* Technique::GetSupportedPass(const String& name) const
+{
+    HashMap<String, unsigned>::ConstIterator i = passIndices.Find(name.ToLower());
+    return i != passIndices.End() ? GetSupportedPass(i->second_) : 0;
+}
+
+unsigned Technique::GetNumPasses() const
+{
+    unsigned ret = 0;
+
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        if (i->Get())
+            ++ret;
+    }
+
+    return ret;
+}
+
+Vector<String> Technique::GetPassNames() const
+{
+    Vector<String> ret;
+
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        Pass* pass = i->Get();
+        if (pass)
+            ret.Push(pass->GetName());
+    }
+
+    return ret;
 }
 }
 
 
 PODVector<Pass*> Technique::GetPasses() const
 PODVector<Pass*> Technique::GetPasses() const
 {
 {
-    // Convert PODVector<SharedPtr<Pass>*> to PODVector<Pass*>
-    PODVector<SharedPtr<Pass>*> vectorIn = passes_.Values();
-    PODVector<Pass*> vectorOut;
-    vectorOut.Reserve(vectorIn.Size());
-    for (unsigned i = 0; i < vectorIn.Size(); ++i)
-        vectorOut.Push(vectorIn[i]->Get());
+    PODVector<Pass*> ret;
+
+    for (Vector<SharedPtr<Pass> >::ConstIterator i = passes_.Begin(); i != passes_.End(); ++i)
+    {
+        Pass* pass = i->Get();
+        if (pass)
+            ret.Push(pass);
+    }
+
+    return ret;
+}
+
+unsigned Technique::GetPassIndex(const String& passName)
+{
+    // Initialize built-in pass indices on first call
+    if (passIndices.Empty())
+    {
+        basePassIndex = passIndices["base"] = 0;
+        alphaPassIndex = passIndices["alpha"] = 1;
+        materialPassIndex = passIndices["material"] = 2;
+        deferredPassIndex = passIndices["deferred"] = 3;
+        lightPassIndex = passIndices["light"] = 4;
+        litBasePassIndex = passIndices["litbase"] = 5;
+        litAlphaPassIndex = passIndices["litalpha"] = 6;
+        shadowPassIndex = passIndices["shadow"] = 7;
+    }
 
 
-    return vectorOut;
+    String nameLower = passName.ToLower();
+    HashMap<String, unsigned>::Iterator i = passIndices.Find(nameLower);
+    if (i != passIndices.End())
+        return i->second_;
+    else
+    {
+        unsigned newPassIndex = passIndices.Size();
+        passIndices[nameLower] = newPassIndex;
+        return newPassIndex;
+    }
 }
 }
 
 
 }
 }

+ 50 - 25
Source/Urho3D/Graphics/Technique.h

@@ -23,7 +23,6 @@
 #pragma once
 #pragma once
 
 
 #include "../Graphics/GraphicsDefs.h"
 #include "../Graphics/GraphicsDefs.h"
-#include "../Container/HashTable.h"
 #include "../Resource/Resource.h"
 #include "../Resource/Resource.h"
 
 
 namespace Urho3D
 namespace Urho3D
@@ -44,7 +43,7 @@ class URHO3D_API Pass : public RefCounted
 {
 {
 public:
 public:
     /// Construct.
     /// Construct.
-    Pass(StringHash type);
+    Pass(const String& passName);
     /// Destruct.
     /// Destruct.
     ~Pass();
     ~Pass();
     
     
@@ -73,8 +72,10 @@ public:
     /// Mark shaders loaded this frame.
     /// Mark shaders loaded this frame.
     void MarkShadersLoaded(unsigned frameNumber);
     void MarkShadersLoaded(unsigned frameNumber);
     
     
-    /// Return pass type.
-    const StringHash& GetType() const { return type_; }
+    /// Return pass name.
+    const String& GetName() const { return name_; }
+    /// Return pass index. This is used for optimal render-time pass queries that avoid map lookups.
+    unsigned GetIndex() const { return index_; }
     /// Return blend mode.
     /// Return blend mode.
     BlendMode GetBlendMode() const { return blendMode_; }
     BlendMode GetBlendMode() const { return blendMode_; }
     /// Return depth compare mode.
     /// Return depth compare mode.
@@ -103,8 +104,8 @@ public:
     Vector<SharedPtr<ShaderVariation> >& GetPixelShaders() { return pixelShaders_; }
     Vector<SharedPtr<ShaderVariation> >& GetPixelShaders() { return pixelShaders_; }
     
     
 private:
 private:
-    /// Pass type.
-    StringHash type_;
+    /// Pass index.
+    unsigned index_;
     /// Blend mode.
     /// Blend mode.
     BlendMode blendMode_;
     BlendMode blendMode_;
     /// Depth compare mode.
     /// Depth compare mode.
@@ -131,6 +132,8 @@ private:
     Vector<SharedPtr<ShaderVariation> > vertexShaders_;
     Vector<SharedPtr<ShaderVariation> > vertexShaders_;
     /// Pixel shaders.
     /// Pixel shaders.
     Vector<SharedPtr<ShaderVariation> > pixelShaders_;
     Vector<SharedPtr<ShaderVariation> > pixelShaders_;
+    /// Pass name.
+    String name_;
 };
 };
 
 
 /// %Material technique. Consists of several passes.
 /// %Material technique. Consists of several passes.
@@ -154,9 +157,9 @@ public:
     /// Set whether requires desktop level hardware.
     /// Set whether requires desktop level hardware.
     void SetIsDesktop(bool enable);
     void SetIsDesktop(bool enable);
     /// Create a new pass.
     /// Create a new pass.
-    Pass* CreatePass(StringHash type);
+    Pass* CreatePass(const String& passName);
     /// Remove a pass.
     /// Remove a pass.
-    void RemovePass(StringHash type);
+    void RemovePass(const String& passName);
     /// Reset shader pointers in all passes.
     /// Reset shader pointers in all passes.
     void ReleaseShaders();
     void ReleaseShaders();
     
     
@@ -165,39 +168,61 @@ public:
     /// Return whether technique is supported by the current hardware.
     /// Return whether technique is supported by the current hardware.
     bool IsSupported() const { return !isDesktop_ || desktopSupport_; }
     bool IsSupported() const { return !isDesktop_ || desktopSupport_; }
     /// Return whether has a pass.
     /// Return whether has a pass.
-    bool HasPass(StringHash type) const { return  passes_.Find(type.Value()) != 0; }
-    
+    bool HasPass(unsigned passIndex) const { return passIndex < passes_.Size() && passes_[passIndex].Get() != 0; }
+    /// Return whether has a pass by name. This overload should not be called in time-critical rendering loops; use a pre-acquired pass index instead.
+    bool HasPass(const String& passName) const;
     /// Return a pass, or null if not found.
     /// Return a pass, or null if not found.
-    Pass* GetPass(StringHash type) const
-    {
-        SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
-        return passPtr ? passPtr->Get() : 0;
-    }
+    Pass* GetPass(unsigned passIndex) const { return passIndex < passes_.Size() ? passes_[passIndex].Get() : 0; }
+    /// Return a pass by name, or null if not found. This overload should not be called in time-critical rendering loops; use a pre-acquired pass index instead.
+    Pass* GetPass(const String& passName) const;
     
     
     /// Return a pass that is supported for rendering, or null if not found.
     /// Return a pass that is supported for rendering, or null if not found.
-    Pass* GetSupportedPass(StringHash type) const
+    Pass* GetSupportedPass(unsigned passIndex) const
     {
     {
-        SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
-        Pass* pass = passPtr ? passPtr->Get() : 0;
+        Pass* pass = passIndex < passes_.Size() ? passes_[passIndex].Get() : 0;
         return pass && (!pass->IsDesktop() || desktopSupport_) ? pass : 0;
         return pass && (!pass->IsDesktop() || desktopSupport_) ? pass : 0;
     }
     }
+
+    /// Return a supported pass by name. This overload should not be called in time-critical rendering loops; use a pre-acquired pass index instead.
+    Pass* GetSupportedPass(const String& passName) const;
     
     
     /// Return number of passes.
     /// Return number of passes.
-    unsigned GetNumPasses() const { return numPasses_; }
-    /// Return all the pass types in the hash table. The returned collection is not guaranteed to be in the same order as the hash table insertion order.
-    Vector<StringHash> GetPassTypes() const;
-    /// Return all the passes in the hash table. The returned collection is not guaranteed to be in the same order as the hash table insertion order.
+    unsigned GetNumPasses() const;
+    /// Return all pass names.
+    Vector<String> GetPassNames() const;
+    /// Return all passes.
     PODVector<Pass*> GetPasses() const;
     PODVector<Pass*> GetPasses() const;
 
 
+    /// Return a pass type index by name. Allocate new if not used yet.
+    static unsigned GetPassIndex(const String& passName);
+
+    /// Index for base pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned basePassIndex;
+    /// Index for alpha pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned alphaPassIndex;
+    /// Index for prepass material pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned materialPassIndex;
+    /// Index for deferred G-buffer pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned deferredPassIndex;
+    /// Index for per-pixel light pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned lightPassIndex;
+    /// Index for lit base pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned litBasePassIndex;
+    /// Index for lit alpha pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned litAlphaPassIndex;
+    /// Index for shadow pass. Initialized once GetPassIndex() has been called for the first time.
+    static unsigned shadowPassIndex;
+
 private:
 private:
     /// Require desktop GPU flag.
     /// Require desktop GPU flag.
     bool isDesktop_;
     bool isDesktop_;
     /// Cached desktop GPU support flag.
     /// Cached desktop GPU support flag.
     bool desktopSupport_;
     bool desktopSupport_;
     /// Passes.
     /// Passes.
-    HashTable<SharedPtr<Pass>, 16> passes_;
-    /// Number of passes.
-    unsigned numPasses_;
+    Vector<SharedPtr<Pass> > passes_;
+
+    /// Pass index assignments.
+    static HashMap<String, unsigned> passIndices;
 };
 };
 
 
 }
 }

+ 41 - 39
Source/Urho3D/Graphics/View.cpp

@@ -313,6 +313,14 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
     if (!renderPath_)
     if (!renderPath_)
         return false;
         return false;
     
     
+    // Set default passes
+    gBufferPassIndex_ = M_MAX_UNSIGNED;
+    basePassIndex_ = Technique::GetPassIndex("base");
+    alphaPassIndex_ = Technique::GetPassIndex("alpha");
+    lightPassIndex_ = Technique::GetPassIndex("light");
+    litBasePassIndex_ = Technique::GetPassIndex("litbase");
+    litAlphaPassIndex_ = Technique::GetPassIndex("litalpha");
+
     drawDebug_ = viewport->GetDrawDebug();
     drawDebug_ = viewport->GetDrawDebug();
     hasScenePasses_ = false;
     hasScenePasses_ = false;
     lightVolumeCommand_ = 0;
     lightVolumeCommand_ = 0;
@@ -345,7 +353,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
 
 
     for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
     for (unsigned i = 0; i < renderPath_->commands_.Size(); ++i)
     {
     {
-        const RenderPathCommand& command = renderPath_->commands_[i];
+        RenderPathCommand& command = renderPath_->commands_[i];
         if (!command.enabled_)
         if (!command.enabled_)
             continue;
             continue;
         
         
@@ -354,7 +362,7 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
             hasScenePasses_ = true;
             hasScenePasses_ = true;
             
             
             ScenePassInfo info;
             ScenePassInfo info;
-            info.pass_ = command.pass_;
+            info.passIndex_ = command.passIndex_ = Technique::GetPassIndex(command.pass_);
             info.allowInstancing_ = command.sortMode_ != SORT_BACKTOFRONT;
             info.allowInstancing_ = command.sortMode_ != SORT_BACKTOFRONT;
             info.markToStencil_ = !noStencil_ && command.markToStencil_;
             info.markToStencil_ = !noStencil_ && command.markToStencil_;
             info.vertexLights_ = command.vertexLights_;
             info.vertexLights_ = command.vertexLights_;
@@ -363,32 +371,31 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
             if (!command.metadata_.Empty())
             if (!command.metadata_.Empty())
             {
             {
                 if (command.metadata_ == "gbuffer")
                 if (command.metadata_ == "gbuffer")
-                    gBufferPassName_ = command.pass_;
+                    gBufferPassIndex_ = command.passIndex_;
                 else if (command.metadata_ == "base" && command.pass_ != "base")
                 else if (command.metadata_ == "base" && command.pass_ != "base")
                 {
                 {
-                    basePassName_ = command.pass_;
-                    litBasePassName_ = "lit" + command.pass_;
+                    basePassIndex_ = command.passIndex_;
+                    litBasePassIndex_ = Technique::GetPassIndex("lit" + command.pass_);
                 }
                 }
                 else if (command.metadata_ == "alpha" && command.pass_ != "alpha")
                 else if (command.metadata_ == "alpha" && command.pass_ != "alpha")
                 {
                 {
-                    alphaPassName_ = command.pass_;
-                    litAlphaPassName_ = "lit" + command.pass_;
+                    alphaPassIndex_ = command.passIndex_;
+                    litAlphaPassIndex_ = Technique::GetPassIndex("lit" + command.pass_);
                 }
                 }
             }
             }
             
             
-            HashMap<StringHash, BatchQueue>::Iterator j = batchQueues_.Find(command.pass_);
+            HashMap<unsigned, BatchQueue>::Iterator j = batchQueues_.Find(info.passIndex_);
             if (j == batchQueues_.End())
             if (j == batchQueues_.End())
-                j = batchQueues_.Insert(Pair<StringHash, BatchQueue>(command.pass_, BatchQueue()));
+                j = batchQueues_.Insert(Pair<unsigned, BatchQueue>(info.passIndex_, BatchQueue()));
             info.batchQueue_ = &j->second_;
             info.batchQueue_ = &j->second_;
             
             
             scenePasses_.Push(info);
             scenePasses_.Push(info);
         }
         }
         // Allow a custom forward light pass
         // Allow a custom forward light pass
         else if (command.type_ == CMD_FORWARDLIGHTS && !command.pass_.Empty())
         else if (command.type_ == CMD_FORWARDLIGHTS && !command.pass_.Empty())
-            lightPassName_ = command.pass_;
+            lightPassIndex_ = command.passIndex_ = Technique::GetPassIndex(command.pass_);
     }
     }
     
     
-    
     scene_ = viewport->GetScene();
     scene_ = viewport->GetScene();
     camera_ = viewport->GetCamera();
     camera_ = viewport->GetCamera();
     octree_ = 0;
     octree_ = 0;
@@ -417,13 +424,6 @@ bool View::Define(RenderSurface* renderTarget, Viewport* viewport)
     cameraNode_ = camera_ ? camera_->GetNode() : (Node*)0;
     cameraNode_ = camera_ ? camera_->GetNode() : (Node*)0;
     renderTarget_ = renderTarget;
     renderTarget_ = renderTarget;
     
     
-    gBufferPassName_ = StringHash();
-    basePassName_  = PASS_BASE;
-    alphaPassName_ = PASS_ALPHA;
-    lightPassName_ = PASS_LIGHT;
-    litBasePassName_ = PASS_LITBASE;
-    litAlphaPassName_ = PASS_LITALPHA;
-    
     // Go through commands to check for deferred rendering and other flags
     // Go through commands to check for deferred rendering and other flags
     deferred_ = false;
     deferred_ = false;
     deferredAmbient_ = false;
     deferredAmbient_ = false;
@@ -524,7 +524,7 @@ void View::Update(const FrameInfo& frame)
     zones_.Clear();
     zones_.Clear();
     occluders_.Clear();
     occluders_.Clear();
     vertexLightQueues_.Clear();
     vertexLightQueues_.Clear();
-    for (HashMap<StringHash, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
+    for (HashMap<unsigned, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
         i->second_.Clear(maxSortedInstances);
         i->second_.Clear(maxSortedInstances);
     
     
     if (hasScenePasses_ && (!camera_ || !octree_))
     if (hasScenePasses_ && (!camera_ || !octree_))
@@ -917,7 +917,7 @@ void View::GetBatches()
     threadedGeometries_.Clear();
     threadedGeometries_.Clear();
     
     
     WorkQueue* queue = GetSubsystem<WorkQueue>();
     WorkQueue* queue = GetSubsystem<WorkQueue>();
-    BatchQueue* alphaQueue = batchQueues_.Contains(alphaPassName_) ? &batchQueues_[alphaPassName_] : (BatchQueue*)0;
+    BatchQueue* alphaQueue = batchQueues_.Contains(alphaPassIndex_) ? &batchQueues_[alphaPassIndex_] : (BatchQueue*)0;
     
     
     // Process lit geometries and shadow casters for each light
     // Process lit geometries and shadow casters for each light
     {
     {
@@ -1036,7 +1036,7 @@ void View::GetBatches()
                             if (!srcBatch.geometry_ || !srcBatch.numWorldTransforms_ || !tech)
                             if (!srcBatch.geometry_ || !srcBatch.numWorldTransforms_ || !tech)
                                 continue;
                                 continue;
                             
                             
-                            Pass* pass = tech->GetSupportedPass(PASS_SHADOW);
+                            Pass* pass = tech->GetSupportedPass(Technique::shadowPassIndex);
                             // Skip if material has no shadow pass
                             // Skip if material has no shadow pass
                             if (!pass)
                             if (!pass)
                                 continue;
                                 continue;
@@ -1154,10 +1154,10 @@ void View::GetBatches()
                 {
                 {
                     ScenePassInfo& info = scenePasses_[k];
                     ScenePassInfo& info = scenePasses_[k];
                     // Skip forward base pass if the corresponding litbase pass already exists
                     // Skip forward base pass if the corresponding litbase pass already exists
-                    if (info.pass_ == basePassName_ && j < 32 && drawable->HasBasePass(j))
+                    if (info.passIndex_ == basePassIndex_ && j < 32 && drawable->HasBasePass(j))
                         continue;
                         continue;
 
 
-                    Pass* pass = tech->GetSupportedPass(info.pass_);
+                    Pass* pass = tech->GetSupportedPass(info.passIndex_);
                     if (!pass)
                     if (!pass)
                         continue;
                         continue;
                     
                     
@@ -1229,7 +1229,7 @@ void View::UpdateGeometries()
                 SharedPtr<WorkItem> item = queue->GetFreeItem();
                 SharedPtr<WorkItem> item = queue->GetFreeItem();
                 item->priority_ = M_MAX_UNSIGNED;
                 item->priority_ = M_MAX_UNSIGNED;
                 item->workFunction_ = command.sortMode_ == SORT_FRONTTOBACK ? SortBatchQueueFrontToBackWork : SortBatchQueueBackToFrontWork;
                 item->workFunction_ = command.sortMode_ == SORT_FRONTTOBACK ? SortBatchQueueFrontToBackWork : SortBatchQueueBackToFrontWork;
-                item->start_ = &batchQueues_[command.pass_];
+                item->start_ = &batchQueues_[command.passIndex_];
                 queue->AddWorkItem(item);
                 queue->AddWorkItem(item);
             }
             }
         }
         }
@@ -1318,7 +1318,7 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
             continue;
             continue;
         
         
         // Do not create pixel lit forward passes for materials that render into the G-buffer
         // Do not create pixel lit forward passes for materials that render into the G-buffer
-        if (gBufferPassName_.Value() && tech->HasPass(gBufferPassName_))
+        if (gBufferPassIndex_ != M_MAX_UNSIGNED && tech->HasPass(gBufferPassIndex_))
             continue;
             continue;
         
         
         Batch destBatch(srcBatch);
         Batch destBatch(srcBatch);
@@ -1328,22 +1328,22 @@ void View::GetLitBatches(Drawable* drawable, LightBatchQueue& lightQueue, BatchQ
         // Also vertex lighting or ambient gradient require the non-lit base pass, so skip in those cases
         // Also vertex lighting or ambient gradient require the non-lit base pass, so skip in those cases
         if (i < 32 && allowLitBase)
         if (i < 32 && allowLitBase)
         {
         {
-            destBatch.pass_ = tech->GetSupportedPass(litBasePassName_);
+            destBatch.pass_ = tech->GetSupportedPass(litBasePassIndex_);
             if (destBatch.pass_)
             if (destBatch.pass_)
             {
             {
                 destBatch.isBase_ = true;
                 destBatch.isBase_ = true;
                 drawable->SetBasePass(i);
                 drawable->SetBasePass(i);
             }
             }
             else
             else
-                destBatch.pass_ = tech->GetSupportedPass(lightPassName_);
+                destBatch.pass_ = tech->GetSupportedPass(lightPassIndex_);
         }
         }
         else
         else
-            destBatch.pass_ = tech->GetSupportedPass(lightPassName_);
+            destBatch.pass_ = tech->GetSupportedPass(lightPassIndex_);
         
         
         // If no lit pass, check for lit alpha
         // If no lit pass, check for lit alpha
         if (!destBatch.pass_)
         if (!destBatch.pass_)
         {
         {
-            destBatch.pass_ = tech->GetSupportedPass(litAlphaPassName_);
+            destBatch.pass_ = tech->GetSupportedPass(litAlphaPassIndex_);
             isLitAlpha = true;
             isLitAlpha = true;
         }
         }
         
         
@@ -1496,15 +1496,17 @@ void View::ExecuteRenderPathCommands()
                 break;
                 break;
                 
                 
             case CMD_SCENEPASS:
             case CMD_SCENEPASS:
-                if (!batchQueues_[command.pass_].IsEmpty())
                 {
                 {
-                    PROFILE(RenderScenePass);
+                    if (!batchQueues_[command.passIndex_].IsEmpty())
+                    {
+                        PROFILE(RenderScenePass);
                     
                     
-                    SetRenderTargets(command);
-                    bool allowDepthWrite = SetTextures(command);
-                    graphics_->SetFillMode(camera_->GetFillMode());
-                    graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(), camera_->GetProjection());
-                    batchQueues_[command.pass_].Draw(this, command.markToStencil_, false, allowDepthWrite);
+                        SetRenderTargets(command);
+                        bool allowDepthWrite = SetTextures(command);
+                        graphics_->SetFillMode(camera_->GetFillMode());
+                        graphics_->SetClipPlane(camera_->GetUseClipping(), camera_->GetClipPlane(), camera_->GetView(), camera_->GetProjection());
+                        batchQueues_[command.passIndex_].Draw(this, command.markToStencil_, false, allowDepthWrite);
+                    }
                 }
                 }
                 break;
                 break;
                 
                 
@@ -1797,7 +1799,7 @@ void View::RenderQuad(RenderPathCommand& command)
 bool View::IsNecessary(const RenderPathCommand& command)
 bool View::IsNecessary(const RenderPathCommand& command)
 {
 {
     return command.enabled_ && command.outputNames_.Size() && (command.type_ != CMD_SCENEPASS ||
     return command.enabled_ && command.outputNames_.Size() && (command.type_ != CMD_SCENEPASS ||
-        !batchQueues_[command.pass_].IsEmpty());
+        !batchQueues_[command.passIndex_].IsEmpty());
 }
 }
 
 
 bool View::CheckViewportRead(const RenderPathCommand& command)
 bool View::CheckViewportRead(const RenderPathCommand& command)
@@ -2803,7 +2805,7 @@ void View::PrepareInstancingBuffer()
     
     
     unsigned totalInstances = 0;
     unsigned totalInstances = 0;
     
     
-    for (HashMap<StringHash, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
+    for (HashMap<unsigned, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
         totalInstances += i->second_.GetNumInstances();
         totalInstances += i->second_.GetNumInstances();
     
     
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
@@ -2823,7 +2825,7 @@ void View::PrepareInstancingBuffer()
     if (!dest)
     if (!dest)
         return;
         return;
     
     
-    for (HashMap<StringHash, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
+    for (HashMap<unsigned, BatchQueue>::Iterator i = batchQueues_.Begin(); i != batchQueues_.End(); ++i)
         i->second_.SetTransforms(dest, freeIndex);
         i->second_.SetTransforms(dest, freeIndex);
         
         
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)
     for (Vector<LightBatchQueue>::Iterator i = lightQueues_.Begin(); i != lightQueues_.End(); ++i)

+ 16 - 16
Source/Urho3D/Graphics/View.h

@@ -78,8 +78,8 @@ struct LightQueryResult
 /// Scene render pass info.
 /// Scene render pass info.
 struct ScenePassInfo
 struct ScenePassInfo
 {
 {
-    /// Pass name hash.
-    StringHash pass_;
+    /// Pass index.
+    unsigned passIndex_;
     /// Allow instancing flag.
     /// Allow instancing flag.
     bool allowInstancing_;
     bool allowInstancing_;
     /// Mark to stencil flag.
     /// Mark to stencil flag.
@@ -354,20 +354,20 @@ private:
     Vector<LightBatchQueue> lightQueues_;
     Vector<LightBatchQueue> lightQueues_;
     /// Per-vertex light queues.
     /// Per-vertex light queues.
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
     HashMap<unsigned long long, LightBatchQueue> vertexLightQueues_;
-    /// Batch queues.
-    HashMap<StringHash, BatchQueue> batchQueues_;
-    /// Hash of the GBuffer pass, or null if none.
-    StringHash gBufferPassName_;
-    /// Hash of the opaque forward base pass.
-    StringHash basePassName_;
-    /// Hash of the alpha pass.
-    StringHash alphaPassName_;
-    /// Hash of the forward light pass.
-    StringHash lightPassName_;
-    /// Hash of the litbase pass.
-    StringHash litBasePassName_;
-    /// Hash of the litalpha pass.
-    StringHash litAlphaPassName_;
+    /// Batch queues by pass index.
+    HashMap<unsigned, BatchQueue> batchQueues_;
+    /// Index of the GBuffer pass.
+    unsigned gBufferPassIndex_;
+    /// Index of the opaque forward base pass.
+    unsigned basePassIndex_;
+    /// Index of the alpha pass.
+    unsigned alphaPassIndex_;
+    /// Index of the forward light pass.
+    unsigned lightPassIndex_;
+    /// Index of the litbase pass.
+    unsigned litBasePassIndex_;
+    /// Index of the litalpha pass.
+    unsigned litAlphaPassIndex_;
     /// Pointer to the light volume command if any.
     /// Pointer to the light volume command if any.
     const RenderPathCommand* lightVolumeCommand_;
     const RenderPathCommand* lightVolumeCommand_;
 };
 };

+ 2 - 3
Source/Urho3D/LuaScript/pkgs/Graphics/Material.pkg

@@ -33,9 +33,8 @@ class Material : public Resource
     unsigned GetNumTechniques() const;
     unsigned GetNumTechniques() const;
     
     
     Technique* GetTechnique(unsigned index) const;
     Technique* GetTechnique(unsigned index) const;
-    
-    Pass* GetPass(unsigned index, StringHash passType) const;
-    Pass* GetPass(unsigned index, const String passType) const;
+
+    Pass* GetPass(unsigned index, const String passName) const;
     
     
     Texture* GetTexture(TextureUnit unit) const;
     Texture* GetTexture(TextureUnit unit) const;
     ValueAnimation* GetShaderParameterAnimation(const String name) const;
     ValueAnimation* GetShaderParameterAnimation(const String name) const;

+ 6 - 6
Source/Urho3D/LuaScript/pkgs/Graphics/Technique.pkg

@@ -20,13 +20,13 @@ class Pass : public RefCounted
 
 
 class Technique : public Resource
 class Technique : public Resource
 {
 {
-    bool HasPass(const StringHash type) const;
-    Pass* GetPass(const StringHash type) const;
-    Pass* GetSupportedPass(const StringHash type) const;
+    bool HasPass(const String type) const;
+    Pass* GetPass(const String type) const;
+    Pass* GetSupportedPass(const String type) const;
     bool IsSupported() const;
     bool IsSupported() const;
     bool IsDesktop() const;
     bool IsDesktop() const;
     unsigned GetNumPasses() const;
     unsigned GetNumPasses() const;
-    tolua_outside const Vector<StringHash>& TechniqueGetPassTypes @ GetPassTypes() const;
+    tolua_outside const Vector<String>& TechniqueGetPassNames @ GetPassTypes() const;
     tolua_outside const PODVector<Pass*>& TechniqueGetPasses @ GetPasses() const;
     tolua_outside const PODVector<Pass*>& TechniqueGetPasses @ GetPasses() const;
 
 
     tolua_readonly tolua_property__is_set bool supported;
     tolua_readonly tolua_property__is_set bool supported;
@@ -35,9 +35,9 @@ class Technique : public Resource
 };
 };
 
 
 ${
 ${
-static const Vector<StringHash>& TechniqueGetPassTypes(const Technique* technique)
+static const Vector<String>& TechniqueGetPassNames(const Technique* technique)
 {
 {
-    static Vector<StringHash> vector = technique->GetPassTypes();
+    static Vector<String> vector = technique->GetPassNames();
     return vector;
     return vector;
 }
 }
 
 

+ 9 - 8
Source/Urho3D/Script/GraphicsAPI.cpp

@@ -517,9 +517,9 @@ static void ConstructTechniqueEntry(TechniqueEntry* ptr)
     new(ptr) TechniqueEntry();
     new(ptr) TechniqueEntry();
 }
 }
 
 
-static CScriptArray* TechniqueGetPassTypes(const Technique& technique)
+static CScriptArray* TechniqueGetPassNames(const Technique& technique)
 {
 {
-    return VectorToArray<StringHash>(technique.GetPassTypes(), "Array<StringHash>");
+    return VectorToArray<String>(technique.GetPassNames(), "Array<String>");
 }
 }
 
 
 static CScriptArray* TechniqueGetPasses(const Technique& technique)
 static CScriptArray* TechniqueGetPasses(const Technique& technique)
@@ -634,16 +634,16 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Pass", "const String& get_pixelShaderDefines() const", asMETHOD(Pass, GetPixelShaderDefines), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_pixelShaderDefines() const", asMETHOD(Pass, GetPixelShaderDefines), asCALL_THISCALL);
     
     
     RegisterResource<Technique>(engine, "Technique");
     RegisterResource<Technique>(engine, "Technique");
-    engine->RegisterObjectMethod("Technique", "Pass@+ CreatePass(StringHash)", asMETHOD(Technique, CreatePass), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "void RemovePass(StringHash)", asMETHOD(Technique, RemovePass), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "bool HasPass(StringHash) const", asMETHOD(Technique, HasPass), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "Pass@+ GetPass(StringHash)", asMETHOD(Technique, GetPass), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "Pass@+ GetSupportedPass(StringHash)", asMETHOD(Technique, GetSupportedPass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Pass@+ CreatePass(const String&in)", asMETHOD(Technique, CreatePass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "void RemovePass(const String&in)", asMETHOD(Technique, RemovePass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "bool HasPass(const String&in) const", asMETHODPR(Technique, HasPass, (const String&) const, bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Pass@+ GetPass(const String&in)", asMETHODPR(Technique, GetPass, (const String&) const, Pass*), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Pass@+ GetSupportedPass(const String&in)", asMETHODPR(Technique, GetSupportedPass, (const String&) const, Pass*), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_supported() const", asMETHOD(Technique, IsSupported), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_supported() const", asMETHOD(Technique, IsSupported), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_desktop(bool)", asMETHOD(Technique, SetIsDesktop), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_desktop(bool)", asMETHOD(Technique, SetIsDesktop), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_desktop() const", asMETHOD(Technique, IsDesktop), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_desktop() const", asMETHOD(Technique, IsDesktop), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "uint get_numPasses() const", asMETHOD(Technique, GetNumPasses), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "uint get_numPasses() const", asMETHOD(Technique, GetNumPasses), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "Array<StringHash>@ get_passTypes() const", asFUNCTION(TechniqueGetPassTypes), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Technique", "Array<String>@ get_passNames() const", asFUNCTION(TechniqueGetPassNames), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Technique", "Array<Pass@>@ get_passes() const", asFUNCTION(TechniqueGetPasses), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Technique", "Array<Pass@>@ get_passes() const", asFUNCTION(TechniqueGetPasses), asCALL_CDECL_OBJLAST);
     
     
     engine->RegisterObjectType("TechniqueEntry", sizeof(TechniqueEntry), asOBJ_VALUE | asOBJ_APP_CLASS_CD);
     engine->RegisterObjectType("TechniqueEntry", sizeof(TechniqueEntry), asOBJ_VALUE | asOBJ_APP_CLASS_CD);
@@ -665,6 +665,7 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "void RemoveShaderParameter(const String&in)", asMETHOD(Material, RemoveShaderParameter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void RemoveShaderParameter(const String&in)", asMETHOD(Material, RemoveShaderParameter), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void SortTechniques()", asMETHOD(Material, SortTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void SortTechniques()", asMETHOD(Material, SortTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Material@ Clone(const String&in cloneName = String()) const", asFUNCTION(MaterialClone), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Material", "Material@ Clone(const String&in cloneName = String()) const", asFUNCTION(MaterialClone), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Material", "Pass@+ GetPass(uint, const String&in)", asMETHOD(Material, GetPass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_numTechniques(uint)", asMETHOD(Material, SetNumTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_numTechniques(uint)", asMETHOD(Material, SetNumTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "uint get_numTechniques() const", asMETHOD(Material, GetNumTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "uint get_numTechniques() const", asMETHOD(Material, GetNumTechniques), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Technique@+ get_techniques(uint)", asMETHOD(Material, GetTechnique), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Technique@+ get_techniques(uint)", asMETHOD(Material, GetTechnique), asCALL_THISCALL);

+ 1 - 1
Source/Urho3D/UI/Text3D.cpp

@@ -522,7 +522,7 @@ void Text3D::UpdateTextMaterials(bool forceUpdate)
             {
             {
                 Material* material = new Material(context_);
                 Material* material = new Material(context_);
                 Technique* tech = new Technique(context_);
                 Technique* tech = new Technique(context_);
-                Pass* pass = tech->CreatePass(PASS_ALPHA);
+                Pass* pass = tech->CreatePass("alpha");
                 pass->SetVertexShader("Text");
                 pass->SetVertexShader("Text");
                 pass->SetPixelShader("Text");
                 pass->SetPixelShader("Text");
 
 

+ 1 - 1
Source/Urho3D/Urho2D/Renderer2D.cpp

@@ -434,7 +434,7 @@ Material* Renderer2D::CreateMaterial(Texture2D* texture, BlendMode blendMode)
         material->SetName(blendModeNames[blendMode]);
         material->SetName(blendModeNames[blendMode]);
 
 
     Technique* tech = new Technique(context_);
     Technique* tech = new Technique(context_);
-    Pass* pass = tech->CreatePass(PASS_ALPHA);
+    Pass* pass = tech->CreatePass("alpha");
     pass->SetBlendMode(blendMode);
     pass->SetBlendMode(blendMode);
 
 
     pass->SetVertexShader("Urho2D");
     pass->SetVertexShader("Urho2D");