Browse Source

Added mechanism to limit material techniques on desktop hardware. Closes #516.

Lasse Öörni 11 years ago
parent
commit
943a2c348b

+ 5 - 3
Docs/Reference.dox

@@ -987,8 +987,8 @@ For the layout definitions, see http://www.cgtextures.com/content.php?action=tut
 A technique definition looks like this:
 A technique definition looks like this:
 
 
 \code
 \code
-<technique vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" sm3="false|true" >
-    <pass name="base|litbase|light|alpha|litalpha|postopaque|refract|postalpha|prepass|material|deferred|depth|shadow" sm3="false|true"
+<technique vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4" sm3="false|true" desktop="false|true" >
+    <pass name="base|litbase|light|alpha|litalpha|postopaque|refract|postalpha|prepass|material|deferred|depth|shadow" sm3="false|true" desktop="false|true" >
         vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4"
         vs="VertexShaderName" ps="PixelShaderName" vsdefines="DEFINE1 DEFINE2" psdefines="DEFINE3 DEFINE4"
         lighting="unlit|pervertex|perpixel"
         lighting="unlit|pervertex|perpixel"
         blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha|subtract|subtractalpha"
         blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha|subtract|subtractalpha"
@@ -1000,7 +1000,9 @@ A technique definition looks like this:
 </technique>
 </technique>
 \endcode
 \endcode
 
 
-The sm3 attribute in the technique root element allows the technique to specify it requires %Shader %Model 3 hardware. Omitting it is same as specifying false (works on both SM2 & 3.) The sm3 attribute can also be specified per pass, to disable for example a too complex lit base optimization pass on SM2.
+The "sm3" attribute in the technique root element allows the technique to specify it requires %Shader %Model 3 hardware. Omitting it is same as specifying false (works on both SM2 & 3.) The sm3 attribute can also be specified per pass, to disable for example a too complex lit base optimization pass on SM2.
+
+The "desktop" attribute in either technique or pass works similarly to allow requiring desktop hardware and excluding mobile devices.
 
 
 Shaders are referred to by giving the name of a shader without path and file extension. For example "Basic" or "LitSolid". The engine will add the correct path and file extension (Shaders/HLSL/LitSolid.hlsl for Direct3D9, and Shaders/GLSL/LitSolid.glsl for OpenGL) automatically. The same shader source file contains both the vertex and pixel shader. In addition, compilation defines can be specified, which are passed to the shader compiler. For example the define "DIFFMAP" typically enables diffuse mapping in the pixel shader.
 Shaders are referred to by giving the name of a shader without path and file extension. For example "Basic" or "LitSolid". The engine will add the correct path and file extension (Shaders/HLSL/LitSolid.hlsl for Direct3D9, and Shaders/GLSL/LitSolid.glsl for OpenGL) automatically. The same shader source file contains both the vertex and pixel shader. In addition, compilation defines can be specified, which are passed to the shader compiler. For example the define "DIFFMAP" typically enables diffuse mapping in the pixel shader.
 
 

+ 30 - 1
Source/Engine/Graphics/Technique.cpp

@@ -25,6 +25,7 @@
 #include "Graphics.h"
 #include "Graphics.h"
 #include "Log.h"
 #include "Log.h"
 #include "Technique.h"
 #include "Technique.h"
+#include "ProcessUtils.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
 #include "ShaderVariation.h"
 #include "ShaderVariation.h"
@@ -69,6 +70,9 @@ static const char* lightingModeNames[] =
     0
     0
 };
 };
 
 
+static bool desktopSupportChecked = false;
+static bool desktopSupportResult = false;
+
 Pass::Pass(StringHash type) :
 Pass::Pass(StringHash type) :
     type_(type),
     type_(type),
     blendMode_(BLEND_REPLACE),
     blendMode_(BLEND_REPLACE),
@@ -77,7 +81,8 @@ Pass::Pass(StringHash type) :
     shadersLoadedFrameNumber_(0),
     shadersLoadedFrameNumber_(0),
     depthWrite_(true),
     depthWrite_(true),
     alphaMask_(false),
     alphaMask_(false),
-    isSM3_(false)
+    isSM3_(false),
+    isDesktop_(false)
 {
 {
     // 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 (type == PASS_BASE || type == PASS_ALPHA || type == PASS_MATERIAL || type == PASS_DEFERRED)
@@ -120,6 +125,11 @@ void Pass::SetIsSM3(bool enable)
     isSM3_ = enable;
     isSM3_ = enable;
 }
 }
 
 
+void Pass::SetIsDesktop(bool enable)
+{
+    isDesktop_ = enable;
+}
+
 void Pass::SetVertexShader(const String& name)
 void Pass::SetVertexShader(const String& name)
 {
 {
     vertexShaderName_ = name;
     vertexShaderName_ = name;
@@ -158,10 +168,20 @@ void Pass::MarkShadersLoaded(unsigned frameNumber)
 Technique::Technique(Context* context) :
 Technique::Technique(Context* context) :
     Resource(context),
     Resource(context),
     isSM3_(false),
     isSM3_(false),
+    isDesktop_(false),
     numPasses_(0)
     numPasses_(0)
 {
 {
     Graphics* graphics = GetSubsystem<Graphics>();
     Graphics* graphics = GetSubsystem<Graphics>();
     sm3Support_ = graphics ? graphics->GetSM3Support() : true;
     sm3Support_ = graphics ? graphics->GetSM3Support() : true;
+    
+    if (!desktopSupportChecked)
+    {
+        String platformString = GetPlatform();
+        desktopSupportResult = (platformString == "Windows" || platformString == "Mac OS X" || platformString == "Linux");
+        desktopSupportChecked = true;
+    }
+    
+    desktopSupport_ = desktopSupportResult;
 }
 }
 
 
 Technique::~Technique()
 Technique::~Technique()
@@ -187,6 +207,8 @@ bool Technique::BeginLoad(Deserializer& source)
     XMLElement rootElem = xml->GetRoot();
     XMLElement rootElem = xml->GetRoot();
     if (rootElem.HasAttribute("sm3"))
     if (rootElem.HasAttribute("sm3"))
         isSM3_ = rootElem.GetBool("sm3");
         isSM3_ = rootElem.GetBool("sm3");
+    if (rootElem.HasAttribute("desktop"))
+        isDesktop_ = rootElem.GetBool("desktop");
     
     
     String globalVS = rootElem.GetAttribute("vs");
     String globalVS = rootElem.GetAttribute("vs");
     String globalPS = rootElem.GetAttribute("ps");
     String globalPS = rootElem.GetAttribute("ps");
@@ -212,6 +234,8 @@ bool Technique::BeginLoad(Deserializer& source)
             
             
             if (passElem.HasAttribute("sm3"))
             if (passElem.HasAttribute("sm3"))
                 newPass->SetIsSM3(passElem.GetBool("sm3"));
                 newPass->SetIsSM3(passElem.GetBool("sm3"));
+            if (passElem.HasAttribute("desktop"))
+                newPass->SetIsDesktop(passElem.GetBool("desktop"));
             
             
             // Append global defines only when pass does not redefine the shader
             // Append global defines only when pass does not redefine the shader
             if (passElem.HasAttribute("vs"))
             if (passElem.HasAttribute("vs"))
@@ -279,6 +303,11 @@ void Technique::SetIsSM3(bool enable)
     isSM3_ = enable;
     isSM3_ = enable;
 }
 }
 
 
+void Technique::SetIsDesktop(bool enable)
+{
+    isDesktop_ = enable;
+}
+
 void Technique::ReleaseShaders()
 void Technique::ReleaseShaders()
 {
 {
     PODVector<SharedPtr<Pass>*> allPasses = passes_.Values();
     PODVector<SharedPtr<Pass>*> allPasses = passes_.Values();

+ 17 - 1
Source/Engine/Graphics/Technique.h

@@ -60,6 +60,8 @@ public:
     void SetAlphaMask(bool enable);
     void SetAlphaMask(bool enable);
     /// Set whether requires %Shader %Model 3.
     /// Set whether requires %Shader %Model 3.
     void SetIsSM3(bool enable);
     void SetIsSM3(bool enable);
+    /// Set whether requires desktop level hardware.
+    void SetIsDesktop(bool enable);
     /// Set vertex shader name.
     /// Set vertex shader name.
     void SetVertexShader(const String& name);
     void SetVertexShader(const String& name);
     /// Set pixel shader name.
     /// Set pixel shader name.
@@ -89,6 +91,8 @@ public:
     bool GetAlphaMask() const { return alphaMask_; }
     bool GetAlphaMask() const { return alphaMask_; }
     /// Return whether requires %Shader %Model 3.
     /// Return whether requires %Shader %Model 3.
     bool IsSM3() const { return isSM3_; }
     bool IsSM3() const { return isSM3_; }
+    /// Return whether requires desktop level hardware.
+    bool IsDesktop() const { return isDesktop_; }
     /// Return vertex shader name.
     /// Return vertex shader name.
     const String& GetVertexShader() const { return vertexShaderName_; }
     const String& GetVertexShader() const { return vertexShaderName_; }
     /// Return pixel shader name.
     /// Return pixel shader name.
@@ -119,6 +123,8 @@ private:
     bool alphaMask_;
     bool alphaMask_;
     /// Require %Shader %Model 3 flag.
     /// Require %Shader %Model 3 flag.
     bool isSM3_;
     bool isSM3_;
+    /// Require desktop level hardware flag.
+    bool isDesktop_;
     /// Vertex shader name.
     /// Vertex shader name.
     String vertexShaderName_;
     String vertexShaderName_;
     /// Pixel shader name.
     /// Pixel shader name.
@@ -153,6 +159,8 @@ public:
     
     
     /// Set whether requires %Shader %Model 3.
     /// Set whether requires %Shader %Model 3.
     void SetIsSM3(bool enable);
     void SetIsSM3(bool enable);
+    /// Set whether requires desktop level hardware.
+    void SetIsDesktop(bool enable);
     /// Create a new pass.
     /// Create a new pass.
     Pass* CreatePass(StringHash type);
     Pass* CreatePass(StringHash type);
     /// Remove a pass.
     /// Remove a pass.
@@ -162,6 +170,10 @@ public:
     
     
     /// Return whether requires %Shader %Model 3.
     /// Return whether requires %Shader %Model 3.
     bool IsSM3() const { return isSM3_; }
     bool IsSM3() const { return isSM3_; }
+    /// Return whether requires desktop level hardware.
+    bool IsDesktop() const { return isDesktop_; }
+    /// Return whether technique is supported by the current hardware.
+    bool IsSupported() const { return (!isSM3_ || sm3Support_) && (!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(StringHash type) const { return  passes_.Find(type.Value()) != 0; }
     
     
@@ -177,7 +189,7 @@ public:
     {
     {
         SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
         SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
         Pass* pass = passPtr ? passPtr->Get() : 0;
         Pass* pass = passPtr ? passPtr->Get() : 0;
-        return pass && (!pass->IsSM3() || sm3Support_) ? pass : 0;
+        return pass && (!pass->IsSM3() || sm3Support_) && (!pass->IsDesktop() || desktopSupport_) ? pass : 0;
     }
     }
     
     
     /// Return number of passes.
     /// Return number of passes.
@@ -192,6 +204,10 @@ private:
     bool isSM3_;
     bool isSM3_;
     /// Cached %Shader %Model 3 support flag.
     /// Cached %Shader %Model 3 support flag.
     bool sm3Support_;
     bool sm3Support_;
+    /// Require desktop GPU flag.
+    bool isDesktop_;
+    /// Cached desktop GPU support flag.
+    bool desktopSupport_;
     /// Passes.
     /// Passes.
     HashTable<SharedPtr<Pass>, 16> passes_;
     HashTable<SharedPtr<Pass>, 16> passes_;
     /// Number of passes.
     /// Number of passes.

+ 1 - 1
Source/Engine/Graphics/View.cpp

@@ -2617,7 +2617,7 @@ Technique* View::GetTechnique(Drawable* drawable, Material* material)
             const TechniqueEntry& entry = techniques[i];
             const TechniqueEntry& entry = techniques[i];
             Technique* tech = entry.technique_;
             Technique* tech = entry.technique_;
 
 
-            if (!tech || (tech->IsSM3() && !graphics_->GetSM3Support()) || materialQuality_ < entry.qualityLevel_)
+            if (!tech || (!tech->IsSupported()) || materialQuality_ < entry.qualityLevel_)
                 continue;
                 continue;
             if (lodDistance >= entry.lodDistance_)
             if (lodDistance >= entry.lodDistance_)
                 return tech;
                 return tech;

+ 1 - 1
Source/Engine/LuaScript/pkgs/Graphics/Graphics.pkg

@@ -77,7 +77,7 @@ class Graphics : public Object
     tolua_readonly tolua_property__get_set unsigned dummyColorFormat;
     tolua_readonly tolua_property__get_set unsigned dummyColorFormat;
     tolua_readonly tolua_property__get_set unsigned shadowMapFormat;
     tolua_readonly tolua_property__get_set unsigned shadowMapFormat;
     tolua_readonly tolua_property__get_set unsigned hiresShadowMapFormat;
     tolua_readonly tolua_property__get_set unsigned hiresShadowMapFormat;
-    tolua_readonly tolua_property__get_set bool sM3Support;
+    tolua_readonly tolua_property__get_set bool SM3Support;
     tolua_readonly tolua_property__get_set bool instancingSupport;
     tolua_readonly tolua_property__get_set bool instancingSupport;
     tolua_readonly tolua_property__get_set bool lightPrepassSupport;
     tolua_readonly tolua_property__get_set bool lightPrepassSupport;
     tolua_readonly tolua_property__get_set bool deferredSupport;
     tolua_readonly tolua_property__get_set bool deferredSupport;

+ 6 - 0
Source/Engine/LuaScript/pkgs/Graphics/Technique.pkg

@@ -10,10 +10,12 @@ enum PassLightingMode
 class Pass : public RefCounted
 class Pass : public RefCounted
 {
 {
     bool IsSM3() const;
     bool IsSM3() const;
+    bool IsDesktop() const;
     const String GetVertexShader() const;
     const String GetVertexShader() const;
     const String GetPixelShader() const;
     const String GetPixelShader() const;
 
 
     tolua_readonly tolua_property__is_set bool SM3;
     tolua_readonly tolua_property__is_set bool SM3;
+    tolua_readonly tolua_property__is_set bool desktop;
     tolua_readonly tolua_property__get_set const String vertexShader;
     tolua_readonly tolua_property__get_set const String vertexShader;
     tolua_readonly tolua_property__get_set const String pixelShader;
     tolua_readonly tolua_property__get_set const String pixelShader;
 };
 };
@@ -23,12 +25,16 @@ class Technique : public Resource
     bool HasPass(const StringHash type) const;
     bool HasPass(const StringHash type) const;
     Pass* GetPass(const StringHash type) const;
     Pass* GetPass(const StringHash type) const;
     Pass* GetSupportedPass(const StringHash type) const;
     Pass* GetSupportedPass(const StringHash type) const;
+    bool IsSupported() const;
     bool IsSM3() const;
     bool IsSM3() const;
+    bool IsDesktop() const;
     unsigned GetNumPasses() const;
     unsigned GetNumPasses() const;
     tolua_outside const Vector<StringHash>& TechniqueGetPassTypes @ GetPassTypes() const;
     tolua_outside const Vector<StringHash>& TechniqueGetPassTypes @ 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 SM3;
     tolua_readonly tolua_property__is_set bool SM3;
+    tolua_readonly tolua_property__is_set bool desktop;
     tolua_readonly tolua_property__get_set unsigned numPasses;
     tolua_readonly tolua_property__get_set unsigned numPasses;
 };
 };
 
 

+ 5 - 0
Source/Engine/Script/GraphicsAPI.cpp

@@ -617,6 +617,8 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_alphaMask() const", asMETHOD(Pass, GetAlphaMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pass", "void set_desktop(bool)", asMETHOD(Technique, SetIsDesktop), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Pass", "bool get_desktop() const", asMETHOD(Technique, IsDesktop), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_vertexShader(const String&in)", asMETHOD(Pass, SetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_vertexShader(const String&in)", asMETHOD(Pass, SetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_pixelShader(const String&in)", asMETHOD(Pass, SetPixelShader), asCALL_THISCALL);
     engine->RegisterObjectMethod("Pass", "void set_pixelShader(const String&in)", asMETHOD(Pass, SetPixelShader), asCALL_THISCALL);
@@ -632,8 +634,11 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Technique", "bool HasPass(StringHash) const", asMETHOD(Technique, HasPass), 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@+ GetPass(StringHash)", asMETHOD(Technique, GetPass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "Pass@+ GetSupportedPass(StringHash)", asMETHOD(Technique, GetSupportedPass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "Pass@+ GetSupportedPass(StringHash)", asMETHOD(Technique, GetSupportedPass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "bool get_supported() const", asMETHOD(Technique, IsSupported), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_sm3() const", asMETHOD(Technique, IsSM3), 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", "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<StringHash>@ get_passTypes() const", asFUNCTION(TechniqueGetPassTypes), 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);