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:
 
 \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"
         lighting="unlit|pervertex|perpixel"
         blend="replace|add|multiply|alpha|addalpha|premulalpha|invdestalpha|subtract|subtractalpha"
@@ -1000,7 +1000,9 @@ A technique definition looks like this:
 </technique>
 \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.
 

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

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

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

@@ -60,6 +60,8 @@ public:
     void SetAlphaMask(bool enable);
     /// Set whether requires %Shader %Model 3.
     void SetIsSM3(bool enable);
+    /// Set whether requires desktop level hardware.
+    void SetIsDesktop(bool enable);
     /// Set vertex shader name.
     void SetVertexShader(const String& name);
     /// Set pixel shader name.
@@ -89,6 +91,8 @@ public:
     bool GetAlphaMask() const { return alphaMask_; }
     /// Return whether requires %Shader %Model 3.
     bool IsSM3() const { return isSM3_; }
+    /// Return whether requires desktop level hardware.
+    bool IsDesktop() const { return isDesktop_; }
     /// Return vertex shader name.
     const String& GetVertexShader() const { return vertexShaderName_; }
     /// Return pixel shader name.
@@ -119,6 +123,8 @@ private:
     bool alphaMask_;
     /// Require %Shader %Model 3 flag.
     bool isSM3_;
+    /// Require desktop level hardware flag.
+    bool isDesktop_;
     /// Vertex shader name.
     String vertexShaderName_;
     /// Pixel shader name.
@@ -153,6 +159,8 @@ public:
     
     /// Set whether requires %Shader %Model 3.
     void SetIsSM3(bool enable);
+    /// Set whether requires desktop level hardware.
+    void SetIsDesktop(bool enable);
     /// Create a new pass.
     Pass* CreatePass(StringHash type);
     /// Remove a pass.
@@ -162,6 +170,10 @@ public:
     
     /// Return whether requires %Shader %Model 3.
     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.
     bool HasPass(StringHash type) const { return  passes_.Find(type.Value()) != 0; }
     
@@ -177,7 +189,7 @@ public:
     {
         SharedPtr<Pass>* passPtr = passes_.Find(type.Value());
         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.
@@ -192,6 +204,10 @@ private:
     bool isSM3_;
     /// Cached %Shader %Model 3 support flag.
     bool sm3Support_;
+    /// Require desktop GPU flag.
+    bool isDesktop_;
+    /// Cached desktop GPU support flag.
+    bool desktopSupport_;
     /// Passes.
     HashTable<SharedPtr<Pass>, 16> 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];
             Technique* tech = entry.technique_;
 
-            if (!tech || (tech->IsSM3() && !graphics_->GetSM3Support()) || materialQuality_ < entry.qualityLevel_)
+            if (!tech || (!tech->IsSupported()) || materialQuality_ < entry.qualityLevel_)
                 continue;
             if (lodDistance >= entry.lodDistance_)
                 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 shadowMapFormat;
     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 lightPrepassSupport;
     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
 {
     bool IsSM3() const;
+    bool IsDesktop() const;
     const String GetVertexShader() const;
     const String GetPixelShader() const;
 
     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 pixelShader;
 };
@@ -23,12 +25,16 @@ class Technique : public Resource
     bool HasPass(const StringHash type) const;
     Pass* GetPass(const StringHash type) const;
     Pass* GetSupportedPass(const StringHash type) const;
+    bool IsSupported() const;
     bool IsSM3() const;
+    bool IsDesktop() const;
     unsigned GetNumPasses() const;
     tolua_outside const Vector<StringHash>& TechniqueGetPassTypes @ GetPassTypes() 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 desktop;
     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", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), 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", "const String& get_vertexShader() const", asMETHOD(Pass, GetVertexShader), 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", "Pass@+ GetPass(StringHash)", asMETHOD(Technique, GetPass), 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", "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", "Array<StringHash>@ get_passTypes() const", asFUNCTION(TechniqueGetPassTypes), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Technique", "Array<Pass@>@ get_passes() const", asFUNCTION(TechniqueGetPasses), asCALL_CDECL_OBJLAST);