Browse Source

Make shader cache location configurable, default "urho3d/shadercache" in app preferences, to avoid writing to write-protected installation directory by default. Instructions in porting notes to restore earlier behavior. ShaderCacheDir & PackageCacheDir parameters added to engine startup parameters. Fix GetResourceFileName() function to return the unmodified filename if it's absolute and exists. Remove unnecessary mutex lock from GetResourceFileName(). Remove some code duplication from Graphics class implementations. Closes #1610.

Lasse Öörni 9 years ago
parent
commit
a1e2bc9bd3

+ 2 - 0
Docs/Reference.dox

@@ -222,6 +222,8 @@ The full list of supported parameters, their datatypes and default values:
 - SoundStereo (bool) Stereo sound output mode. Default true.
 - SoundStereo (bool) Stereo sound output mode. Default true.
 - SoundInterpolation (bool) Interpolated sound output mode to improve quality. Default true.
 - SoundInterpolation (bool) Interpolated sound output mode to improve quality. Default true.
 - TouchEmulation (bool) %Touch emulation on desktop platform. Default false.
 - TouchEmulation (bool) %Touch emulation on desktop platform. Default false.
+- ShaderCacheDir (string) Shader binary cache directory for Direct3D. Default "urho3d/shadercache" within the user's application preferences directory.
+- PackageCacheDir (string) Package cache directory for Network subsystem. Not specified by default.
 
 
 \section MainLoop_Frame Main loop iteration
 \section MainLoop_Frame Main loop iteration
 
 

+ 3 - 0
Docs/Urho3D.dox

@@ -1044,6 +1044,9 @@ From 1.6 to master:
   Due to this change you must also manually define that a material should not take part in occlusion rendering, see Material::SetOcclusion(). 
   Due to this change you must also manually define that a material should not take part in occlusion rendering, see Material::SetOcclusion(). 
 - Techniques that existed just for shader defines like ALPHAMASK and PACKEDNORMAL have been removed. Replace by using techniques without those defines (e.g. DiffNormal instead of DiffNormalPacked), and adding the necessary defines to your materials instead.
 - Techniques that existed just for shader defines like ALPHAMASK and PACKEDNORMAL have been removed. Replace by using techniques without those defines (e.g. DiffNormal instead of DiffNormalPacked), and adding the necessary defines to your materials instead.
 - The Light class has gained a max extrusion distance parameter for directional light shadows. In case you use a large far clip distance, you can experience different shadow depth resolution and effect of bias parameters, as the far clip distance no longer alone determines the extrusion. Adjust with Light::SetShadowMaxExtrusion() as necessary.
 - The Light class has gained a max extrusion distance parameter for directional light shadows. In case you use a large far clip distance, you can experience different shadow depth resolution and effect of bias parameters, as the far clip distance no longer alone determines the extrusion. Adjust with Light::SetShadowMaxExtrusion() as necessary.
+- Direct3D binary shaders are now cached by default to the user preferences directory "urho3d/shadercache" to avoid writing into the application installation directory, to which the user may not have rights.
+  If you ship a prewarmed (read-only) cache with your application you can set the directory yourself from the engine startup parameter "ShaderCacheDir" or call Graphics::SetShaderCacheDir() on initialization.
+  Use the directory "Shaders/HLSL/Cache" to get the old behavior.
 */
 */
 
 
 }
 }

+ 2 - 0
Source/Urho3D/AngelScript/GraphicsAPI.cpp

@@ -1854,6 +1854,8 @@ static void RegisterGraphics(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Graphics", "bool get_flushGPU() const", asMETHOD(Graphics, GetFlushGPU), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_flushGPU() const", asMETHOD(Graphics, GetFlushGPU), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "void set_orientations(const String&in)", asMETHOD(Graphics, SetOrientations), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "void set_orientations(const String&in)", asMETHOD(Graphics, SetOrientations), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "const String& get_orientations() const", asMETHOD(Graphics, GetOrientations), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "const String& get_orientations() const", asMETHOD(Graphics, GetOrientations), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Graphics", "void set_shaderCacheDir(const String&in)", asMETHOD(Graphics, SetShaderCacheDir), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Graphics", "const String& get_shaderCacheDir() const", asMETHOD(Graphics, GetShaderCacheDir), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_width() const", asMETHOD(Graphics, GetWidth), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_width() const", asMETHOD(Graphics, GetWidth), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_height() const", asMETHOD(Graphics, GetHeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_height() const", asMETHOD(Graphics, GetHeight), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_multiSample() const", asMETHOD(Graphics, GetMultiSample), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "int get_multiSample() const", asMETHOD(Graphics, GetMultiSample), asCALL_THISCALL);

+ 8 - 0
Source/Urho3D/Engine/Engine.cpp

@@ -378,6 +378,8 @@ bool Engine::Initialize(const VariantMap& parameters)
         ))
         ))
             return false;
             return false;
 
 
+        graphics->SetShaderCacheDir(GetParameter(parameters, "ShaderCacheDir", fileSystem->GetAppPreferencesDir("urho3d", "shadercache")).GetString());
+
         if (HasParameter(parameters, "DumpShaders"))
         if (HasParameter(parameters, "DumpShaders"))
             graphics->BeginDumpShaders(GetParameter(parameters, "DumpShaders", String::EMPTY).GetString());
             graphics->BeginDumpShaders(GetParameter(parameters, "DumpShaders", String::EMPTY).GetString());
         if (HasParameter(parameters, "RenderPath"))
         if (HasParameter(parameters, "RenderPath"))
@@ -409,6 +411,12 @@ bool Engine::Initialize(const VariantMap& parameters)
     if (HasParameter(parameters, "TouchEmulation"))
     if (HasParameter(parameters, "TouchEmulation"))
         GetSubsystem<Input>()->SetTouchEmulation(GetParameter(parameters, "TouchEmulation").GetBool());
         GetSubsystem<Input>()->SetTouchEmulation(GetParameter(parameters, "TouchEmulation").GetBool());
 
 
+    // Initialize network
+#ifdef URHO3D_NETWORK
+    if (HasParameter(parameters, "PackageCacheDir"))
+        GetSubsystem<Network>()->SetPackageCacheDir(GetParameter(parameters, "PackageCacheDir").GetString());
+#endif
+
 #ifdef URHO3D_TESTING
 #ifdef URHO3D_TESTING
     if (HasParameter(parameters, "TimeOut"))
     if (HasParameter(parameters, "TimeOut"))
         timeOut_ = GetParameter(parameters, "TimeOut", 0).GetInt() * 1000000LL;
         timeOut_ = GetParameter(parameters, "TimeOut", 0).GetInt() * 1000000LL;

+ 0 - 17
Source/Urho3D/Graphics/Direct3D11/D3D11Graphics.cpp

@@ -1657,23 +1657,6 @@ void Graphics::SetClipPlane(bool enable, const Plane& clipPlane, const Matrix3x4
     }
     }
 }
 }
 
 
-void Graphics::BeginDumpShaders(const String& fileName)
-{
-    shaderPrecache_ = new ShaderPrecache(context_, fileName);
-}
-
-void Graphics::EndDumpShaders()
-{
-    shaderPrecache_.Reset();
-}
-
-void Graphics::PrecacheShaders(Deserializer& source)
-{
-    URHO3D_PROFILE(PrecacheShaders);
-
-    ShaderPrecache::LoadShaders(this, source);
-}
-
 bool Graphics::IsInitialized() const
 bool Graphics::IsInitialized() const
 {
 {
     return window_ != 0 && impl_->GetDevice() != 0;
     return window_ != 0 && impl_->GetDevice() != 0;

+ 12 - 3
Source/Urho3D/Graphics/Direct3D11/D3D11ShaderVariation.cpp

@@ -74,7 +74,7 @@ bool ShaderVariation::Create()
     SplitPath(owner_->GetName(), path, name, extension);
     SplitPath(owner_->GetName(), path, name, extension);
     extension = type_ == VS ? ".vs4" : ".ps4";
     extension = type_ == VS ? ".vs4" : ".ps4";
 
 
-    String binaryShaderName = path + "Cache/" + name + "_" + StringHash(defines_).ToString() + extension;
+    String binaryShaderName = graphics_->GetShaderCacheDir() + name + "_" + StringHash(defines_).ToString() + extension;
 
 
     if (!LoadByteCode(binaryShaderName))
     if (!LoadByteCode(binaryShaderName))
     {
     {
@@ -418,8 +418,17 @@ void ShaderVariation::SaveByteCode(const String& binaryShaderName)
     ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
     ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
     FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
     FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
 
 
-    String path = GetPath(cache->GetResourceFileName(owner_->GetName())) + "Cache/";
-    String fullName = path + GetFileNameAndExtension(binaryShaderName);
+    // Filename may or may not be inside the resource system
+    String fullName = binaryShaderName;
+    if (!IsAbsolutePath(fullName))
+    {
+        // If not absolute, use the resource dir of the shader
+        String shaderFileName = cache->GetResourceFileName(owner_->GetName());
+        if (shaderFileName.Empty())
+            return;
+        fullName = shaderFileName.Substring(0, shaderFileName.Find(owner_->GetName())) + binaryShaderName;
+    }
+    String path = GetPath(fullName);
     if (!fileSystem->DirExists(path))
     if (!fileSystem->DirExists(path))
         fileSystem->CreateDir(path);
         fileSystem->CreateDir(path);
 
 

+ 0 - 17
Source/Urho3D/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -1860,23 +1860,6 @@ void Graphics::SetClipPlane(bool enable, const Plane& clipPlane, const Matrix3x4
     }
     }
 }
 }
 
 
-void Graphics::BeginDumpShaders(const String& fileName)
-{
-    shaderPrecache_ = new ShaderPrecache(context_, fileName);
-}
-
-void Graphics::EndDumpShaders()
-{
-    shaderPrecache_.Reset();
-}
-
-void Graphics::PrecacheShaders(Deserializer& source)
-{
-    URHO3D_PROFILE(PrecacheShaders);
-
-    ShaderPrecache::LoadShaders(this, source);
-}
-
 bool Graphics::IsInitialized() const
 bool Graphics::IsInitialized() const
 {
 {
     return window_ != 0 && impl_->GetDevice() != 0;
     return window_ != 0 && impl_->GetDevice() != 0;

+ 12 - 3
Source/Urho3D/Graphics/Direct3D9/D3D9ShaderVariation.cpp

@@ -92,7 +92,7 @@ bool ShaderVariation::Create()
     SplitPath(owner_->GetName(), path, name, extension);
     SplitPath(owner_->GetName(), path, name, extension);
     extension = type_ == VS ? ".vs3" : ".ps3";
     extension = type_ == VS ? ".vs3" : ".ps3";
 
 
-    String binaryShaderName = path + "Cache/" + name + "_" + StringHash(defines_).ToString() + extension;
+    String binaryShaderName = graphics_->GetShaderCacheDir() + name + "_" + StringHash(defines_).ToString() + extension;
 
 
     if (!LoadByteCode(binaryShaderName))
     if (!LoadByteCode(binaryShaderName))
     {
     {
@@ -372,8 +372,17 @@ void ShaderVariation::SaveByteCode(const String& binaryShaderName)
     ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
     ResourceCache* cache = owner_->GetSubsystem<ResourceCache>();
     FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
     FileSystem* fileSystem = owner_->GetSubsystem<FileSystem>();
 
 
-    String path = GetPath(cache->GetResourceFileName(owner_->GetName())) + "Cache/";
-    String fullName = path + GetFileNameAndExtension(binaryShaderName);
+    // Filename may or may not be inside the resource system
+    String fullName = binaryShaderName;
+    if (!IsAbsolutePath(fullName))
+    {
+        // If not absolute, use the resource dir of the shader
+        String shaderFileName = cache->GetResourceFileName(owner_->GetName());
+        if (shaderFileName.Empty())
+            return;
+        fullName = shaderFileName.Substring(0, shaderFileName.Find(owner_->GetName())) + binaryShaderName;
+    }
+    String path = GetPath(fullName);
     if (!fileSystem->DirExists(path))
     if (!fileSystem->DirExists(path))
         fileSystem->CreateDir(path);
         fileSystem->CreateDir(path);
 
 

+ 27 - 0
Source/Urho3D/Graphics/Graphics.cpp

@@ -22,6 +22,7 @@
 
 
 #include "../Precompiled.h"
 #include "../Precompiled.h"
 
 
+#include "../Core/Profiler.h"
 #include "../Graphics/AnimatedModel.h"
 #include "../Graphics/AnimatedModel.h"
 #include "../Graphics/Animation.h"
 #include "../Graphics/Animation.h"
 #include "../Graphics/AnimationController.h"
 #include "../Graphics/AnimationController.h"
@@ -37,6 +38,7 @@
 #include "../Graphics/ParticleEmitter.h"
 #include "../Graphics/ParticleEmitter.h"
 #include "../Graphics/RibbonTrail.h"
 #include "../Graphics/RibbonTrail.h"
 #include "../Graphics/Shader.h"
 #include "../Graphics/Shader.h"
+#include "../Graphics/ShaderPrecache.h"
 #include "../Graphics/Skybox.h"
 #include "../Graphics/Skybox.h"
 #include "../Graphics/StaticModelGroup.h"
 #include "../Graphics/StaticModelGroup.h"
 #include "../Graphics/Technique.h"
 #include "../Graphics/Technique.h"
@@ -47,6 +49,7 @@
 #include "../Graphics/Texture3D.h"
 #include "../Graphics/Texture3D.h"
 #include "../Graphics/TextureCube.h"
 #include "../Graphics/TextureCube.h"
 #include "../Graphics/Zone.h"
 #include "../Graphics/Zone.h"
+#include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../IO/Log.h"
 
 
 #include <SDL/SDL.h>
 #include <SDL/SDL.h>
@@ -171,6 +174,30 @@ void Graphics::Minimize()
     SDL_MinimizeWindow(window_);
     SDL_MinimizeWindow(window_);
 }
 }
 
 
+void Graphics::BeginDumpShaders(const String& fileName)
+{
+    shaderPrecache_ = new ShaderPrecache(context_, fileName);
+}
+
+void Graphics::EndDumpShaders()
+{
+    shaderPrecache_.Reset();
+}
+
+void Graphics::PrecacheShaders(Deserializer& source)
+{
+    URHO3D_PROFILE(PrecacheShaders);
+
+    ShaderPrecache::LoadShaders(this, source);
+}
+
+void Graphics::SetShaderCacheDir(const String& path)
+{
+    String trimmedPath = path.Trimmed();
+    if (trimmedPath.Length())
+        shaderCacheDir_ = AddTrailingSlash(trimmedPath);
+}
+
 void Graphics::AddGPUObject(GPUObject* object)
 void Graphics::AddGPUObject(GPUObject* object)
 {
 {
     MutexLock lock(gpuObjectMutex_);
     MutexLock lock(gpuObjectMutex_);

+ 7 - 0
Source/Urho3D/Graphics/Graphics.h

@@ -241,6 +241,8 @@ public:
     void EndDumpShaders();
     void EndDumpShaders();
     /// Precache shader variations from an XML file generated with BeginDumpShaders().
     /// Precache shader variations from an XML file generated with BeginDumpShaders().
     void PrecacheShaders(Deserializer& source);
     void PrecacheShaders(Deserializer& source);
+    /// Set shader cache directory, Direct3D only. This can either be an absolute path or a path within the resource system.
+    void SetShaderCacheDir(const String& path);
 
 
     /// Return whether rendering initialized.
     /// Return whether rendering initialized.
     bool IsInitialized() const;
     bool IsInitialized() const;
@@ -456,6 +458,9 @@ public:
     /// Return whether a custom clipping plane is in use.
     /// Return whether a custom clipping plane is in use.
     bool GetUseClipPlane() const { return useClipPlane_; }
     bool GetUseClipPlane() const { return useClipPlane_; }
 
 
+    /// Return shader cache directory, Direct3D only.
+    const String& GetShaderCacheDir() const { return shaderCacheDir_; }
+
     /// Return current rendertarget width and height.
     /// Return current rendertarget width and height.
     IntVector2 GetRenderTargetDimensions() const;
     IntVector2 GetRenderTargetDimensions() const;
 
 
@@ -737,6 +742,8 @@ private:
     const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     /// Base directory for shaders.
     /// Base directory for shaders.
     String shaderPath_;
     String shaderPath_;
+    /// Cache directory for Direct3D binary shaders.
+    String shaderCacheDir_;
     /// File extension for shaders.
     /// File extension for shaders.
     String shaderExtension_;
     String shaderExtension_;
     /// Last used shader in shader variation query.
     /// Last used shader in shader variation query.

+ 0 - 17
Source/Urho3D/Graphics/OpenGL/OGLGraphics.cpp

@@ -1922,23 +1922,6 @@ void Graphics::SetStencilTest(bool enable, CompareMode mode, StencilOp pass, Ste
 #endif
 #endif
 }
 }
 
 
-void Graphics::BeginDumpShaders(const String& fileName)
-{
-    shaderPrecache_ = new ShaderPrecache(context_, fileName);
-}
-
-void Graphics::EndDumpShaders()
-{
-    shaderPrecache_.Reset();
-}
-
-void Graphics::PrecacheShaders(Deserializer& source)
-{
-    URHO3D_PROFILE(PrecacheShaders);
-
-    ShaderPrecache::LoadShaders(this, source);
-}
-
 bool Graphics::IsInitialized() const
 bool Graphics::IsInitialized() const
 {
 {
     return window_ != 0;
     return window_ != 0;

+ 3 - 0
Source/Urho3D/LuaScript/pkgs/Graphics/Graphics.pkg

@@ -24,6 +24,7 @@ class Graphics : public Object
     void EndDumpShaders();
     void EndDumpShaders();
     void PrecacheShaders(Deserializer& source);
     void PrecacheShaders(Deserializer& source);
     tolua_outside void GraphicsPrecacheShaders @ PrecacheShaders(const String fileName);
     tolua_outside void GraphicsPrecacheShaders @ PrecacheShaders(const String fileName);
+    void SetShaderCacheDir(const String path);
 
 
     bool IsInitialized() const;
     bool IsInitialized() const;
     void* GetExternalWindow() const;
     void* GetExternalWindow() const;
@@ -56,6 +57,7 @@ class Graphics : public Object
     bool GetSRGBSupport() const;
     bool GetSRGBSupport() const;
     bool GetSRGBWriteSupport() const;
     bool GetSRGBWriteSupport() const;
     IntVector2 GetDesktopResolution() const;
     IntVector2 GetDesktopResolution() const;
+    const String GetShaderCacheDir() const;
 
 
     static unsigned GetAlphaFormat();
     static unsigned GetAlphaFormat();
     static unsigned GetLuminanceFormat();
     static unsigned GetLuminanceFormat();
@@ -106,6 +108,7 @@ class Graphics : public Object
     tolua_readonly tolua_property__get_set bool sRGBSupport;
     tolua_readonly tolua_property__get_set bool sRGBSupport;
     tolua_readonly tolua_property__get_set bool sRGBWriteSupport;
     tolua_readonly tolua_property__get_set bool sRGBWriteSupport;
     tolua_readonly tolua_property__get_set IntVector2 desktopResolution;
     tolua_readonly tolua_property__get_set IntVector2 desktopResolution;
+    tolua_property__get_set String shaderCacheDir;
 };
 };
 
 
 Graphics* GetGraphics();
 Graphics* GetGraphics();

+ 4 - 3
Source/Urho3D/Resource/ResourceCache.cpp

@@ -784,8 +784,6 @@ unsigned long long ResourceCache::GetTotalMemoryUse() const
 
 
 String ResourceCache::GetResourceFileName(const String& name) const
 String ResourceCache::GetResourceFileName(const String& name) const
 {
 {
-    MutexLock lock(resourceMutex_);
-
     FileSystem* fileSystem = GetSubsystem<FileSystem>();
     FileSystem* fileSystem = GetSubsystem<FileSystem>();
     for (unsigned i = 0; i < resourceDirs_.Size(); ++i)
     for (unsigned i = 0; i < resourceDirs_.Size(); ++i)
     {
     {
@@ -793,7 +791,10 @@ String ResourceCache::GetResourceFileName(const String& name) const
             return resourceDirs_[i] + name;
             return resourceDirs_[i] + name;
     }
     }
 
 
-    return String();
+    if (IsAbsolutePath(name) && fileSystem->FileExists(name))
+        return name;
+    else
+        return String();
 }
 }
 
 
 ResourceRouter* ResourceCache::GetResourceRouter(unsigned index) const
 ResourceRouter* ResourceCache::GetResourceRouter(unsigned index) const

+ 1 - 1
Source/Urho3D/Resource/ResourceCache.h

@@ -178,7 +178,7 @@ public:
     unsigned long long GetMemoryUse(StringHash type) const;
     unsigned long long GetMemoryUse(StringHash type) const;
     /// Return total memory use for all resources.
     /// Return total memory use for all resources.
     unsigned long long GetTotalMemoryUse() const;
     unsigned long long GetTotalMemoryUse() const;
-    /// Return full absolute file name of resource if possible.
+    /// Return full absolute file name of resource if possible, or empty if not found.
     String GetResourceFileName(const String& name) const;
     String GetResourceFileName(const String& name) const;
 
 
     /// Return whether automatic resource reloading is enabled.
     /// Return whether automatic resource reloading is enabled.