From: <re...@us...> - 2008-07-04 14:25:04
|
Revision: 30207 http://crystal.svn.sourceforge.net/crystal/?rev=30207&view=rev Author: res2002 Date: 2008-07-04 07:25:01 -0700 (Fri, 04 Jul 2008) Log Message: ----------- Shader precaching: infrastructure to cache stuff down to individual shader programs; caching support in Cg shader plugin; tool to prewarm a cache Modified Paths: -------------- CS/trunk/apps/tools/Jamfile CS/trunk/data/config-plugins/shadermgr.cfg CS/trunk/include/csplugincommon/opengl/shaderplugin.h CS/trunk/include/csplugincommon/shader/shaderplugin.h CS/trunk/include/ivideo/shader/shader.h CS/trunk/libs/csplugincommon/opengl/shaderplugin.cpp CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.cpp CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.h CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.cpp CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.h CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.cpp CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.h CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shadertech.cpp CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shadertech.h CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/xmlshader.cpp CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/xmlshader.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_arb/glshader_arb.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_arb/glshader_arb.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cg.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cg.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgcommon.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgcommon.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgcommon_params.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgfp.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgfp.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgvp.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/glshader_cgvp.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/profile_limits.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/profile_limits.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_fixed/glshader_fixed.cpp CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_fixed/glshader_fixed.h CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_ps1/glshader_ps1.h CS/trunk/plugins/video/render3d/shader/shaderplugins/softshader/softshader.h CS/trunk/plugins/video/render3d/shader/shaderplugins/vproc_std/vproc_std.h Added Paths: ----------- CS/trunk/apps/tools/shagnetron/ CS/trunk/apps/tools/shagnetron/Jamfile CS/trunk/apps/tools/shagnetron/shagnetron.cpp CS/trunk/apps/tools/shagnetron/shagnetron.h Removed Paths: ------------- CS/trunk/plugins/video/render3d/shader/shaderplugins/glshader_cg/profile_limits.inc Modified: CS/trunk/apps/tools/Jamfile =================================================================== --- CS/trunk/apps/tools/Jamfile 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/apps/tools/Jamfile 2008-07-04 14:25:01 UTC (rev 30207) @@ -11,6 +11,7 @@ SubInclude TOP apps tools levtool ; SubInclude TOP apps tools lighter2 ; SubInclude TOP apps tools partconv ; +SubInclude TOP apps tools shagnetron ; SubInclude TOP apps tools startme ; SubInclude TOP apps tools viewmesh ; SubInclude TOP apps tools vsh ; Added: CS/trunk/apps/tools/shagnetron/Jamfile =================================================================== --- CS/trunk/apps/tools/shagnetron/Jamfile (rev 0) +++ CS/trunk/apps/tools/shagnetron/Jamfile 2008-07-04 14:25:01 UTC (rev 30207) @@ -0,0 +1,5 @@ +SubDir TOP apps tools shagnetron ; + +Description shagnetron : "Shader cache warming utility" ; +Application shagnetron : [ Wildcard *.cpp *.h ] : console ; +LinkWith shagnetron : crystalspace ; Property changes on: CS/trunk/apps/tools/shagnetron/Jamfile ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: CS/trunk/apps/tools/shagnetron/shagnetron.cpp =================================================================== --- CS/trunk/apps/tools/shagnetron/shagnetron.cpp (rev 0) +++ CS/trunk/apps/tools/shagnetron/shagnetron.cpp 2008-07-04 14:25:01 UTC (rev 30207) @@ -0,0 +1,209 @@ +/* + Copyright (C) 2008 by Frank Richter + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "shagnetron.h" + +CS_IMPLEMENT_APPLICATION + +//----------------------------------------------------------------------------- + +Shagnetron::Shagnetron (iObjectRegistry* object_reg) : object_reg (object_reg), + doVerbose (false) +{ +} + +bool Shagnetron::Initialize () +{ + csRef<iCommandLineParser> cmdline = csQueryRegistry<iCommandLineParser> (object_reg); + + csRef<iVerbosityManager> verbose = csQueryRegistry<iVerbosityManager> (object_reg); + doVerbose = verbose->Enabled ("shagnetron"); + // Implicitly enable verboseness for shaders. + verbose->Parse ("+renderer.shader"); + + if (!csInitializer::RequestPlugins (object_reg, + CS_REQUEST_VFS, + CS_REQUEST_REPORTER, + CS_REQUEST_REPORTERLISTENER, + CS_REQUEST_PLUGIN("crystalspace.graphics3d.shadermanager", + iShaderManager), + CS_REQUEST_PLUGIN("crystalspace.documentsystem.multiplexer", + iDocumentSystem), + CS_REQUEST_END)) + { + csReport (object_reg, CS_REPORTER_SEVERITY_ERROR, + "crystalspace.application.shagnetron", + "Can't initialize plugins!"); + return false; + } + + // Check for commandline help. + if (csCommandLineHelper::CheckHelp (object_reg)) + { + PrintHelp (); + return false; + } + + return true; +} + +bool Shagnetron::FileBlacklisted (const char* file) +{ + size_t fileLen = strlen (file); + if ((fileLen >= 5) && (strcmp (file+fileLen - 5, ".svn/") == 0)) + return true; + if (file[fileLen-1] == '~') return true; + return false; +} + +bool Shagnetron::PrecacheShaderFile (const char* file) +{ + if (doVerbose) + csPrintf ("%s ... ", file); + + csRef<iFile> fileObj = vfs->Open (file, VFS_FILE_READ); + if (!fileObj.IsValid()) + { + if (doVerbose) csPrintf ("can't open\n"); + return false; + } + + csRef<iDocument> doc (docsys->CreateDocument()); + const char* err = doc->Parse (fileObj); + if (err != 0) + { + if (doVerbose) csPrintf ("parse error: %s\n", err); + return false; + } + + csRef<iDocumentNode> shaderNode = doc->GetRoot()->GetNode ("shader"); + if (!shaderNode.IsValid()) + { + if (doVerbose) csPrintf ("not a shader\n"); + return false; + } + + if (!doVerbose) + csPrintf ("%s ... ", file); + fflush (stdout); + + const char* type = shaderNode->GetAttributeValue ("compiler"); + if (type == 0) + type = shaderNode->GetAttributeValue ("type"); + if (type == 0) + { + csPrintf ("'compiler' attribute is missing!\n"); + return false; + } + csRef<iShaderCompiler> shcom = shaderMgr->GetCompiler (type); + if (!shcom.IsValid()) + { + csPrintf ("Could not get shader compiler '%s'", type); + return false; + } + + bool result; + { + csVfsDirectoryChanger dirChanger (vfs); + dirChanger.ChangeTo (file); + + result = shcom->PrecacheShader (shaderNode, + shaderMgr->GetShaderCache()); + } + + csPrintf ("%s\n", result ? "ok" : "failed"); + + return result; +} + +bool Shagnetron::Run () +{ + csRef<iCommandLineParser> cmdline = csQueryRegistry<iCommandLineParser> (object_reg); + + csFIFO<csString> dirsToScan; + for (size_t i = 0; ; i++) + { + csString dir (cmdline->GetName (i)); + if (dir.IsEmpty()) break; + + if (dir[dir.Length()-1] != '/') + dir += "/"; + dirsToScan.Push (dir); + } + if (dirsToScan.GetSize() == 0) + { + PrintHelp (); + return false; + } + + docsys = csQueryRegistry<iDocumentSystem> (object_reg); + vfs = csQueryRegistry<iVFS> (object_reg); + shaderMgr = csQueryRegistry<iShaderManager> (object_reg); + while (dirsToScan.GetSize() > 0) + { + csString dir (dirsToScan.PopTop()); + + csRef<iStringArray> vfsFiles (vfs->FindFiles (dir)); + for (size_t i = 0; i < vfsFiles->GetSize(); i++) + { + const char* file = vfsFiles->Get (i); + + if (FileBlacklisted (file)) continue; + + if (file[strlen(file)-1] == '/') + dirsToScan.Push (file); + else + PrecacheShaderFile (file); + } + } + + return true; +} + +void Shagnetron::PrintHelp () +{ + const char* appname = "shagnetron"; + + csPrintf ("Usage: %s <VFS directory> <VFS directory> <...>\n", appname); + csPrintf ("\n"); + csPrintf ("Pre-warms a shader cache with all the shaders from the given directories.\n"); + csPrintf ("\n"); + csPrintf ("The name is a portmanteau of 'shader' and 'magnetron'.\n"); + csPrintf ("\n"); + //csPrintf ("Options:\n"); +} + +/*---------------------------------------------------------------------* + * Main function + *---------------------------------------------------------------------*/ +int main (int argc, char* argv[]) +{ + iObjectRegistry* object_reg = csInitializer::CreateEnvironment (argc, argv); + if (!object_reg) return -1; + + int res = 1; + { + CS::Utility::ScopedDelete<Shagnetron> app (new Shagnetron (object_reg)); + + if (app->Initialize ()) + res = app->Run () ? 0 : 1; + } + + csInitializer::DestroyApplication (object_reg); + return res; +} Property changes on: CS/trunk/apps/tools/shagnetron/shagnetron.cpp ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Added: CS/trunk/apps/tools/shagnetron/shagnetron.h =================================================================== --- CS/trunk/apps/tools/shagnetron/shagnetron.h (rev 0) +++ CS/trunk/apps/tools/shagnetron/shagnetron.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -0,0 +1,46 @@ +/* + Copyright (C) 2008 by Frank Richter + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __SHAGNETRON_H__ +#define __SHAGNETRON_H__ + +#include "crystalspace.h" + +class Shagnetron +{ +private: + iObjectRegistry* object_reg; + bool doVerbose; + + csRef<iDocumentSystem> docsys; + csRef<iVFS> vfs; + csRef<iShaderManager> shaderMgr; + + bool FileBlacklisted (const char* file); + bool PrecacheShaderFile (const char* file); +public: + Shagnetron (iObjectRegistry* object_reg); + + bool Initialize (); + bool Run (); + + void PrintHelp(); +}; + +#endif // __SHAGNETRON_H__ + Property changes on: CS/trunk/apps/tools/shagnetron/shagnetron.h ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:eol-style + native Modified: CS/trunk/data/config-plugins/shadermgr.cfg =================================================================== --- CS/trunk/data/config-plugins/shadermgr.cfg 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/data/config-plugins/shadermgr.cfg 2008-07-04 14:25:01 UTC (rev 30207) @@ -16,7 +16,7 @@ Video.ShaderManager.EnableShaderCache = true ; Cg general compiler options -;Video.OpenGL.Shader.Cg.CompilerOptions = +Video.OpenGL.Shader.Cg.CompilerOptions = -O3 ; Cg compiler options for vertex programs ;Video.OpenGL.Shader.Cg.CompilerOptions.Vertex = ; Cg compiler options for fragment programs @@ -53,3 +53,109 @@ ;Video.ShaderWeaver.DumpWeavedXML = true ; Shader weaver: annotate the combined output ;Video.ShaderWeaver.AnnotateOutput = true + + +;; CG SHADER PRECACHING RESOURCE LIMITS +; Available limits: +; MaxAddressRegs (arbvp1, vp40) +; MaxInstructions (arbvp1, vp40) +; MaxLocalParams (arbfp1, arbvp1, vp20, vp30, vp40, fp40) +; MaxTexIndirections (arbfp1) +; NumInstructionSlots (arbfp1, fp30, fp40) +; NumMathInstructionSlots (arbfp1) +; NumTemps (arbfp1, arbvp1, vp40, fp30, fp40) +; NumTexInstructionSlots (arbfp1) + +; Minimal limits as dictated by ARB_v_p spec +Video.OpenGL.Shader.Cg.Precache.Vertex.minimalavp1.Profile = arbvp1 +Video.OpenGL.Shader.Cg.Precache.Vertex.minimalavp1.MaxAddressRegs = 1 +Video.OpenGL.Shader.Cg.Precache.Vertex.minimalavp1.MaxInstructions = 128 +Video.OpenGL.Shader.Cg.Precache.Vertex.minimalavp1.MaxLocalParams = 96 +Video.OpenGL.Shader.Cg.Precache.Vertex.minimalavp1.NumTemps = 12 +; Minimal limits as dictated by ARB_f_p spec +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.Profile = arbfp1 +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.MaxLocalParams = 24 +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.MaxTexIndirections = 4 +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.NumInstructionSlots = 72 +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.NumMathInstructionSlots = 48 +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.NumTemps = 16 +Video.OpenGL.Shader.Cg.Precache.Fragment.minimalafp1.NumTexInstructionSlots = 24 + +; GF 3/4 +; Use ps_* profiles instead of fp20 to allow reuse on old Radeons. +Video.OpenGL.Shader.Cg.Precache.Fragment.gf3.Profile = ps_1_1 +Video.OpenGL.Shader.Cg.Precache.Fragment.gf4.Profile = ps_1_3 + +; GeForce FX limits +; see eg http://delphi3d.net/hardware/viewreport.php?report=1583 +Video.OpenGL.Shader.Cg.Precache.Vertex.gffx.Profile = vp30 +Video.OpenGL.Shader.Cg.Precache.Vertex.gffx.MaxLocalParams = 256 +Video.OpenGL.Shader.Cg.Precache.Fragment.gffx.Profile = fp30 +; @@@ Correct? Cg defaults to 256 here +Video.OpenGL.Shader.Cg.Precache.Fragment.gffx.NumInstructionSlots = 1024 +Video.OpenGL.Shader.Cg.Precache.Fragment.gffx.NumTemps = 32 + +; GeForce 6 limits +; see eg http://delphi3d.net/hardware/viewreport.php?report=1613 +Video.OpenGL.Shader.Cg.Precache.Vertex.gf6.Profile = vp40 +Video.OpenGL.Shader.Cg.Precache.Vertex.gf6.MaxAddressRegs = 2 +Video.OpenGL.Shader.Cg.Precache.Vertex.gf6.MaxLocalParams = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.gf6.MaxInstructions = 512 +Video.OpenGL.Shader.Cg.Precache.Vertex.gf6.NumTemps = 48 +Video.OpenGL.Shader.Cg.Precache.Fragment.gf6.Profile = fp40 +Video.OpenGL.Shader.Cg.Precache.Fragment.gf6.MaxLocalParams = 512 +Video.OpenGL.Shader.Cg.Precache.Fragment.gf6.NumInstructionSlots = 4096 +Video.OpenGL.Shader.Cg.Precache.Fragment.gf6.NumTemps = 32 + +; GeForce 7 limits - are pretty much the same as GF6 ones + +; GeForce 8 limits +Video.OpenGL.Shader.Cg.Precache.Vertex.gf8.Profile = gp4vp +Video.OpenGL.Shader.Cg.Precache.Fragment.gf8.Profile = gp4fp + + +; Radeon 9500 limits +; see eg http://delphi3d.net/hardware/viewreport.php?report=762 +Video.OpenGL.Shader.Cg.Precache.Vertex.r300.Profile = arbvp1 +Video.OpenGL.Shader.Cg.Precache.Vertex.r300.MaxAddressRegs = 1 +Video.OpenGL.Shader.Cg.Precache.Vertex.r300.MaxInstructions = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.r300.MaxLocalParams = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.r300.NumTemps = 32 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.Profile = arbfp1 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.MaxLocalParams = 32 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.MaxTexIndirections = 4 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.NumInstructionSlots = 96 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.NumMathInstructionSlots = 64 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.NumTemps = 32 +Video.OpenGL.Shader.Cg.Precache.Fragment.r300.NumTexInstructionSlots = 32 + +; Radeon X800 limits +; see eg http://delphi3d.net/hardware/viewreport.php?report=1485 +Video.OpenGL.Shader.Cg.Precache.Vertex.r420.Profile = arbvp1 +Video.OpenGL.Shader.Cg.Precache.Vertex.r420.MaxAddressRegs = 1 +Video.OpenGL.Shader.Cg.Precache.Vertex.r420.MaxInstructions = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.r420.MaxLocalParams = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.r420.NumTemps = 32 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.Profile = arbfp1 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.MaxLocalParams = 64 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.MaxTexIndirections = 4 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.NumInstructionSlots = 1024 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.NumMathInstructionSlots = 512 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.NumTemps = 64 +Video.OpenGL.Shader.Cg.Precache.Fragment.r420.NumTexInstructionSlots = 512 + +; Radeon X1650 limits +; see eg http://delphi3d.net/hardware/viewreport.php?report=1485 +Video.OpenGL.Shader.Cg.Precache.Vertex.r520.Profile = arbvp1 +Video.OpenGL.Shader.Cg.Precache.Vertex.r520.MaxAddressRegs = 1 +Video.OpenGL.Shader.Cg.Precache.Vertex.r520.MaxInstructions = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.r520.MaxLocalParams = 256 +Video.OpenGL.Shader.Cg.Precache.Vertex.r520.NumTemps = 32 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.Profile = arbfp1 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.MaxLocalParams = 64 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.MaxTexIndirections = 512 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.NumInstructionSlots = 1024 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.NumMathInstructionSlots = 512 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.NumTemps = 64 +Video.OpenGL.Shader.Cg.Precache.Fragment.r520.NumTexInstructionSlots = 512 + Modified: CS/trunk/include/csplugincommon/opengl/shaderplugin.h =================================================================== --- CS/trunk/include/csplugincommon/opengl/shaderplugin.h 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/include/csplugincommon/opengl/shaderplugin.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -40,7 +40,7 @@ public: enum HardwareVendor { - ATI = 0, NVIDIA = 1, Other = 2 + Invalid = -1, ATI = 0, NVIDIA = 1, Other = 2 }; protected: /** Modified: CS/trunk/include/csplugincommon/shader/shaderplugin.h =================================================================== --- CS/trunk/include/csplugincommon/shader/shaderplugin.h 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/include/csplugincommon/shader/shaderplugin.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -130,9 +130,17 @@ */ struct iShaderProgramPlugin : public virtual iBase { - SCF_INTERFACE(iShaderProgramPlugin,2,0,0); - virtual csPtr<iShaderProgram> CreateProgram(const char* type) = 0; - virtual bool SupportType(const char* type) = 0; + SCF_INTERFACE(iShaderProgramPlugin,2,0,1); + virtual csPtr<iShaderProgram> CreateProgram (const char* type) = 0; + virtual bool SupportType (const char* type) = 0; + + /** + * Warm the given cache with the program specified in \a node. + * \a outObj can return an object which exposes iShaderDestinationResolver. + */ + virtual bool Precache (const char* type, + iShaderDestinationResolver* resolve, iDocumentNode* node, + iHierarchicalCache* cacheTo,csRef<iBase>* outObj = 0) = 0; }; /** @} */ Modified: CS/trunk/include/ivideo/shader/shader.h =================================================================== --- CS/trunk/include/ivideo/shader/shader.h 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/include/ivideo/shader/shader.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -301,7 +301,7 @@ */ struct iShaderManager : public virtual iShaderVariableContext { - SCF_INTERFACE (iShaderManager, 3, 0, 0); + SCF_INTERFACE (iShaderManager, 3, 0, 1); /** * Register a shader to the shadermanager. * Compiler should register all shaders @@ -515,7 +515,7 @@ */ struct iShaderCompiler : public virtual iBase { - SCF_INTERFACE (iShaderCompiler, 0,0,1); + SCF_INTERFACE (iShaderCompiler, 0,0,2); /// Get a name identifying this compiler virtual const char* GetName() = 0; @@ -544,6 +544,9 @@ */ virtual csPtr<iShaderPriorityList> GetPriorities ( iDocumentNode* templ) = 0; + + virtual bool PrecacheShader (iDocumentNode* node, + iHierarchicalCache* cacheTo) = 0; }; #endif // __CS_IVIDEO_SHADER_H__ Modified: CS/trunk/libs/csplugincommon/opengl/shaderplugin.cpp =================================================================== --- CS/trunk/libs/csplugincommon/opengl/shaderplugin.cpp 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/libs/csplugincommon/opengl/shaderplugin.cpp 2008-07-04 14:25:01 UTC (rev 30207) @@ -37,8 +37,8 @@ { ShaderProgramPluginGL::ShaderProgramPluginGL (iBase* parent) - : scfImplementationType (this, parent), isOpen (false), object_reg (0), - ext (0), doVerbose (false) + : scfImplementationType (this, parent), vendor (Invalid), isOpen (false), + object_reg (0), ext (0), doVerbose (false) { } @@ -59,16 +59,17 @@ bool ShaderProgramPluginGL::Open() { if (isOpen) return true; + isOpen = true; csRef<iGraphics3D> r = csQueryRegistry<iGraphics3D> (object_reg); // Sanity check - csRef<iFactory> f = scfQueryInterface<iFactory> (r); - if (f != 0 && strcmp ("crystalspace.graphics3d.opengl", + csRef<iFactory> f = scfQueryInterfaceSafe<iFactory> (r); + if (f == 0 || strcmp ("crystalspace.graphics3d.opengl", f->QueryClassID ()) != 0) return false; - r->GetDriver2D()->PerformExtension ("getextmanager", &ext); + if (r) r->GetDriver2D()->PerformExtension ("getextmanager", &ext); if (ext == 0) return false; @@ -90,7 +91,6 @@ clipPlanes.Initialize (object_reg); - isOpen = true; return true; } Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.cpp =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.cpp 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.cpp 2008-07-04 14:25:01 UTC (rev 30207) @@ -187,7 +187,6 @@ csRef<iDocument> WeaverShader::LoadTechsFromDoc (const csArray<TechniqueKeeper>& techniques, const FileAliases& aliases, - iLoaderContext* ldr_context, iDocumentNode* docSource, const char* cacheID, const char* cacheTag, @@ -332,8 +331,7 @@ return synthesizedDoc; } - csRef<iDocument> WeaverShader::LoadTechsFromCache (iLoaderContext* ldr_context, - iFile* cacheFile, + csRef<iDocument> WeaverShader::LoadTechsFromCache (iFile* cacheFile, const char* cacheFailReason) { size_t read; @@ -376,8 +374,10 @@ return cacheDoc; } - bool WeaverShader::Load (iLoaderContext* ldr_context, iDocumentNode* source, - int forcepriority) + csRef<iDocument> WeaverShader::DoSynthesis (iDocumentNode* source, + iHierarchicalCache* shaderCache, + int forcepriority, + bool noCacheRead) { FileAliases aliases; csArray<TechniqueKeeper> techniques; @@ -386,7 +386,6 @@ CS::PluginCommon::ShaderCacheHelper::ShaderDocHasher hasher ( compiler->objectreg, source); - iHierarchicalCache* shaderCache = shadermgr->GetShaderCache(); csString shaderName (source->GetAttributeValue ("name")); csString cacheID_base; csString cacheID_header; @@ -406,48 +405,51 @@ { useShaderCache = false; csRef<iFile> cacheFile; - csRef<iDataBuffer> cacheData; - cacheData = shaderCache->ReadCache (csString().Format ("/%s/%s", - shaderName.GetData(), cacheID_header.GetData())); - if (cacheData.IsValid()) + if (!noCacheRead) { - cacheFile.AttachNew (new csMemFile (cacheData, true)); - } - if (cacheFile.IsValid()) - { - do + csRef<iDataBuffer> cacheData; + cacheData = shaderCache->ReadCache (csString().Format ("/%s/%s", + shaderName.GetData(), cacheID_header.GetData())); + if (cacheData.IsValid()) { - // Read magic header - uint32 diskMagic; - size_t read = cacheFile->Read ((char*)&diskMagic, sizeof (diskMagic)); - if (read != sizeof (diskMagic)) + cacheFile.AttachNew (new csMemFile (cacheData, true)); + } + if (cacheFile.IsValid()) + { + do { - cacheFailReason = "Read error"; - break; + // Read magic header + uint32 diskMagic; + size_t read = cacheFile->Read ((char*)&diskMagic, sizeof (diskMagic)); + if (read != sizeof (diskMagic)) + { + cacheFailReason = "Read error"; + break; + } + if (csLittleEndian::UInt32 (diskMagic) != cacheFileMagic) + { + cacheFailReason = "Out of date (magic)"; + break; + } + + // Extract hash stream + csRef<iDataBuffer> hashStream = + CS::PluginCommon::ShaderCacheHelper::ReadDataBuffer (cacheFile); + if (!hashStream.IsValid()) + { + cacheFailReason = "Read error"; + break; + } + + useShaderCache = hasher.ValidateHashStream (hashStream); + if (!useShaderCache) + { + cacheFailReason = "Out of date (hash)"; + break; + } } - if (csLittleEndian::UInt32 (diskMagic) != cacheFileMagic) - { - cacheFailReason = "Out of date (magic)"; - break; - } - - // Extract hash stream - csRef<iDataBuffer> hashStream = - CS::PluginCommon::ShaderCacheHelper::ReadDataBuffer (cacheFile); - if (!hashStream.IsValid()) - { - cacheFailReason = "Read error"; - break; - } - - useShaderCache = hasher.ValidateHashStream (hashStream); - if (!useShaderCache) - { - cacheFailReason = "Out of date (hash)"; - break; - } + while (false); } - while (false); } if (!useShaderCache) { @@ -472,14 +474,14 @@ csRef<iDocument> synthShader; csRef<iDataBuffer> cacheData; - if (useShaderCache) + if (useShaderCache && !noCacheRead) cacheData = shaderCache->ReadCache (csString().Format ("/%s/%s", shaderName.GetData(), cacheID_tech.GetData())); if (cacheData.IsValid()) { csMemFile cacheFile (cacheData, true); const char* techCacheFailReason = 0; - synthShader = LoadTechsFromCache (ldr_context, &cacheFile, techCacheFailReason); + synthShader = LoadTechsFromCache (&cacheFile, techCacheFailReason); if (techCacheFailReason != 0) cacheFailReason.Format ("Could not get cached techniques: %s", techCacheFailReason); @@ -492,7 +494,7 @@ bool cacheState; csMemFile cacheFile; - synthShader = LoadTechsFromDoc (techniques, aliases, ldr_context, + synthShader = LoadTechsFromDoc (techniques, aliases, source, cacheID_base, cacheTag, cacheValid ? &cacheFile : 0, cacheState); if (cacheValid && cacheState) @@ -523,12 +525,6 @@ shaderName.GetData())); } - csRef<iDocumentNode> shaderNode = - synthShader->GetRoot()->GetNode ("shader"); - - realShader = compiler->xmlshader->CompileShader (ldr_context, - shaderNode); - if (compiler->do_verbose && (!cacheFailReason.IsEmpty())) { compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, @@ -536,9 +532,37 @@ shaderName.GetData(), cacheFailReason.GetData()); } + return synthShader; + } + + bool WeaverShader::Load (iLoaderContext* ldr_context, iDocumentNode* source, + int forcepriority) + { + iHierarchicalCache* shaderCache = shadermgr->GetShaderCache(); + + csRef<iDocument> synthShader (DoSynthesis (source, shaderCache, + forcepriority, false)); + + csRef<iDocumentNode> shaderNode = + synthShader->GetRoot()->GetNode ("shader"); + + realShader = compiler->xmlshader->CompileShader (ldr_context, + shaderNode); + return realShader.IsValid(); } + bool WeaverShader::Precache (iDocumentNode* source, + iHierarchicalCache* cacheTo) + { + csRef<iDocument> synthShader (DoSynthesis (source, cacheTo, -1, true)); + + csRef<iDocumentNode> shaderNode = + synthShader->GetRoot()->GetNode ("shader"); + + return compiler->xmlshader->PrecacheShader (shaderNode, cacheTo); + } + void WeaverShader::SelfDestruct () { if (shadermgr) Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.h =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.h 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/shader.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -79,13 +79,15 @@ csPDelArray<Snippet>& passSnippets); csRef<iDocument> LoadTechsFromDoc (const csArray<TechniqueKeeper>& techniques, - const FileAliases& aliases, - iLoaderContext* ldr_context, iDocumentNode* docSource, + const FileAliases& aliases, iDocumentNode* docSource, const char* cacheID, const char* cacheTag, iFile* cacheFile, bool& cacheState); - csRef<iDocument> LoadTechsFromCache (iLoaderContext* ldr_context, iFile* cacheFile, + csRef<iDocument> LoadTechsFromCache (iFile* cacheFile, const char* cacheFailReason); - + + csRef<iDocument> DoSynthesis (iDocumentNode* source, + iHierarchicalCache* cacheTo, int forcepriority, + bool noCacheRead); public: CS_LEAKGUARD_DECLARE (WeaverShader); @@ -94,6 +96,7 @@ bool Load (iLoaderContext* ldr_context, iDocumentNode* source, int forcepriority); + bool Precache (iDocumentNode* source, iHierarchicalCache* cacheTo); virtual iObject* QueryObject () { return static_cast<iObject*> (static_cast<csObject*> (this)); } Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.cpp =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.cpp 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.cpp 2008-07-04 14:25:01 UTC (rev 30207) @@ -269,5 +269,33 @@ return true; } +bool WeaverCompiler::PrecacheShader (iDocumentNode* templ, + iHierarchicalCache* cache) +{ + const char* shaderName = templ->GetAttributeValue ("name"); + csRef<WeaverShader> shader; + + csTicks startTime = 0, endTime = 0; + // Create a shader. The actual loading happens later. + if (do_verbose) startTime = csGetTicks(); + shader.AttachNew (new WeaverShader (this)); + bool loadRet = shader->Precache (templ, cache); + autoDocRoot.Invalidate (); + if (!loadRet) + return false; + if (do_verbose) + { + endTime = csGetTicks(); + + csString str; + //shader->DumpStats (str); + Report(CS_REPORTER_SEVERITY_NOTIFY, + "Shader %s: %s weaved in %u ms", shaderName, str.GetData (), + endTime - startTime); + } + + return true; } + +} CS_PLUGIN_NAMESPACE_END(ShaderWeaver) Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.h =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.h 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/weaver/weaver.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -65,6 +65,8 @@ /// Get a list of priorities for a given shader. virtual csPtr<iShaderPriorityList> GetPriorities ( iDocumentNode* templ); + + bool PrecacheShader(iDocumentNode*, iHierarchicalCache*); void Report (int severity, const char* msg, ...) const; void Report (int severity, iDocumentNode* node, const char* msg, ...) const; Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.cpp =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.cpp 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.cpp 2008-07-04 14:25:01 UTC (rev 30207) @@ -28,6 +28,7 @@ #include "csplugincommon/shader/shadercachehelper.h" #include "csutil/csendian.h" +#include "csutil/cspmeter.h" #include "csutil/documenthelper.h" #include "csutil/parasiticdatabuffer.h" #include "csutil/scfarray.h" @@ -410,9 +411,32 @@ CS_ASSERT (shadermgr); // Should be present - loads us, after all vfsStartDir = CS::StrDup (compiler->vfs->GetCwd ()); - Load (source); + shaderCache = shadermgr->GetShaderCache(); + Load (source, false); } +csXMLShader::csXMLShader (csXMLShaderCompiler* compiler) + : scfImplementationType (this), techsResolver (0), + sharedEvaluator (compiler->sharedEvaluator), + fallbackTried (false) +{ + InitTokenTable (xmltokens); + + csXMLShader::ldr_context = ldr_context; + + activeTech = 0; + filename = 0; + csXMLShader::compiler = compiler; + g3d = compiler->g3d; + csXMLShader::forcepriority = forcepriority; + useFallbackContext = false; + + shadermgr = csQueryRegistry<iShaderManager> (compiler->objectreg); + CS_ASSERT (shadermgr); // Should be present - loads us, after all + + vfsStartDir = CS::StrDup (compiler->vfs->GetCwd ()); +} + csXMLShader::~csXMLShader () { for (size_t i = 0; i < techVariants.GetSize (); i++) @@ -431,14 +455,13 @@ * cache file format changes. */ static const uint32 cacheFileMagic = 0x06737863; -void csXMLShader::Load (iDocumentNode* source) +void csXMLShader::Load (iDocumentNode* source, bool noCacheRead) { techsResolver = new csShaderConditionResolver (*sharedEvaluator); CS::PluginCommon::ShaderCacheHelper::ShaderDocHasher hasher ( compiler->objectreg, source); - shaderCache = shadermgr->GetShaderCache(); csString cacheType = source->GetAttributeValue ("name"); cacheTag = source->GetAttributeValue ("_cachetag"); csString cacheID_header; @@ -457,14 +480,16 @@ csString().Format ("/%s", cacheType.GetData())); bool cacheValid = (shaderCache != 0) && !cacheType.IsEmpty() && !cacheID_header.IsEmpty(); - bool useShaderCache = cacheValid; + if (!cacheValid) shaderCache.Invalidate(); + bool readFromCache = cacheValid && !noCacheRead; csRef<iFile> cacheFile; - if (useShaderCache) + if (cacheValid) { - useShaderCache = false; + readFromCache = false; csRef<iDataBuffer> cacheData; - cacheData = shaderCache->ReadCache (csString().Format ("/%s", cacheID_header.GetData())); + if (readFromCache) + cacheData = shaderCache->ReadCache (csString().Format ("/%s", cacheID_header.GetData())); if (cacheData.IsValid()) { cacheFile.AttachNew (new csMemFile (cacheData, true)); @@ -488,11 +513,11 @@ CS::PluginCommon::ShaderCacheHelper::ReadDataBuffer (cacheFile); if (!hashStream.IsValid()) break; - useShaderCache = hasher.ValidateHashStream (hashStream); + readFromCache = hasher.ValidateHashStream (hashStream); } while (false); } - if (!useShaderCache) + if (!readFromCache) { // Getting from cache failed, so prep for writing to cache cacheFile.AttachNew (new csMemFile ()); @@ -509,31 +534,31 @@ } ConditionsReader* condReader = 0; - if (useShaderCache) + if (readFromCache) { do { - useShaderCache = false; + readFromCache = false; csRef<iDataBuffer> conditionsBuf = CS::PluginCommon::ShaderCacheHelper::ReadDataBuffer (cacheFile); if (!conditionsBuf.IsValid()) break;; condReader = new ConditionsReader (*sharedEvaluator, conditionsBuf); - useShaderCache = true; + readFromCache = true; } while (false); - if (useShaderCache) + if (readFromCache) { // Read condition tree from cache - useShaderCache = techsResolver->ReadFromCache (cacheFile, *condReader); + readFromCache = techsResolver->ReadFromCache (cacheFile, *condReader); } - if (useShaderCache) + if (readFromCache) { csRef<iDocumentNode> wrappedNode; wrappedNode.AttachNew (compiler->wrapperFact->CreateWrapperFromCache ( cacheFile, techsResolver, techsResolver->evaluator, *condReader)); - useShaderCache = wrappedNode.IsValid (); + readFromCache = wrappedNode.IsValid (); shaderRoot = wrappedNode; if (compiler->doDumpConds) @@ -554,7 +579,7 @@ } } - if (!useShaderCache) + if (!readFromCache) { csRefArray<iDocumentNode> extraNodes; csRef<csWrappedDocumentNode> wrappedNode; @@ -602,7 +627,6 @@ } } } - if (!useShaderCache) shaderCache.Invalidate (); //Load global shadervars block csRef<iDocumentNode> varNode = shaderRoot->GetNode( @@ -613,6 +637,136 @@ delete condReader; } + +bool csXMLShader::Precache (iDocumentNode* source, iHierarchicalCache* cacheTo) +{ + shaderCache = cacheTo; + Load (source, true); + if (!shaderCache.IsValid()) return false; + + bool result = true; + size_t tvc = techsResolver->GetVariantCount(); + if (tvc == 0) tvc = 1; + + size_t totalTechs = 0; + + for (size_t tvi = 0; tvi < tvc; tvi++) + { + ShaderTechVariant& techVar = techVariants.GetExtend (tvi); + PrepareTechVar (techVar, -1); + + for (size_t t = 0; t < techVar.techniques.GetSize(); t++) + { + ShaderTechVariant::Technique& tech = techVar.techniques[t]; + + csRef<iHierarchicalCache> techCache; + techCache = shaderCache->GetRootedCache ( + csString().Format ("/%s/%zu/%zu", cacheScope_tech.GetData(), tvi, t)); + + LoadTechnique (tech, techCache, tvi); + + if (compiler->do_verbose) + compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, + "Shader '%s'<%zu>: priority %d: %zu variations", + GetName(), tvi, tech.priority, tech.resolver->GetVariantCount()); + + totalTechs += tech.resolver->GetVariantCount(); + } + } + + size_t techsHandled = 0; + csTicks startTime = csGetTicks(); + csTextProgressMeter* progress = 0; + for (size_t tvi = 0; tvi < tvc; tvi++) + { + ShaderTechVariant& techVar = techVariants[tvi]; + for (size_t t = 0; t < techVar.techniques.GetSize(); t++) + { + ShaderTechVariant::Technique& tech = techVar.techniques[t]; + + csRef<iHierarchicalCache> techCache; + techCache = shaderCache->GetRootedCache ( + csString().Format ("/%s/%zu/%zu", cacheScope_tech.GetData(), tvi, t)); + + size_t vc = tech.resolver->GetVariantCount(); + for (size_t vi = 0; vi < vc; vi++) + { + ShaderVariant var; + size_t ticket = ((vi*techVar.techniques.GetSize() + t) * (tvc+1) + (tvi+1)); + + if (compiler->doDumpXML) + { + csRef<iDocumentSystem> docsys; + docsys.AttachNew (new csTinyDocumentSystem); + csRef<iDocument> newdoc = docsys->CreateDocument(); + CS::DocSystem::CloneNode (tech.techNode, newdoc->CreateRoot()); + newdoc->Write (compiler->vfs, csString().Format ("/tmp/shader/%s_%zu_%zu.xml", + GetName(), tvi, vi)); + } + + csRef<iHierarchicalCache> varCache; + varCache = techCache->GetRootedCache ( + csString().Format ("/%zu", vi)); + + // So external files are found correctly + csVfsDirectoryChanger dirChange (compiler->vfs); + dirChange.ChangeTo (vfsStartDir); + + var.tech = new csXMLShaderTech (this); + bool result = var.tech->Precache (tech.techNode, ticket, varCache); + delete var.tech; + if (!result) + { + if (compiler->do_verbose) + { + compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, + "Shader '%s'<%zu/%zu>: Technique with priority %d fails. Reason: %s.", + GetName(), tvi, vi, tech.priority, var.tech->GetFailReason()); + } + result = false; + } + techsHandled++; + if (progress) + progress->Step (1); + else if (csGetTicks() - startTime > 1000) + { + progress = new csTextProgressMeter (0, totalTechs); + progress->Step (techsHandled); + } + } + } + } + + /* If the "fallback" node lacks a 'file' attribute it's probably an inline + * shader, precache as well */ + csRef<iDocumentNodeIterator> fallbackNodes = source->GetNodes ("fallbackshader"); + while (fallbackNodes->HasNext()) + { + csRef<iDocumentNode> fallbackNode (fallbackNodes->Next()); + + // So external files are found correctly + csVfsDirectoryChanger chdir (compiler->vfs); + chdir.ChangeTo (vfsStartDir); + + const char* fileStr = fallbackNode->GetAttributeValue ("file"); + if (fileStr == 0) + { + const char* type = fallbackNode->GetAttributeValue ("compiler"); + if (type == 0) + type = fallbackNode->GetAttributeValue ("type"); + if (type != 0) + { + csRef<iShaderCompiler> shcom = shadermgr->GetCompiler (type); + if (shcom.IsValid()) + { + result &= shcom->PrecacheShader (fallbackNode, cacheTo); + } + } + } + } + delete progress; + return result; +} void csXMLShader::SelfDestruct () { @@ -759,30 +913,8 @@ { // Get the techniques variant ShaderTechVariant& techVar = techVariants.GetExtend (tvi); + PrepareTechVar (techVar, forcepriority); - if (!techVar.prepared) - { - csArray<TechniqueKeeper> techniquesTmp; - ScanForTechniques (shaderRoot, techniquesTmp, forcepriority); - - /* Find a suitable technique - * (Note that a wrapper is created for each technique node individually, - * not the whole shader) */ - csArray<TechniqueKeeper>::Iterator techIt = techniquesTmp.GetIterator (); - while (techIt.HasNext ()) - { - const TechniqueKeeper& tk = techIt.Next(); - ShaderTechVariant::Technique newTech; - newTech.priority = tk.priority; - csRef<iWrappedDocumentNode> wrappedNode = - scfQueryInterface<iWrappedDocumentNode> (tk.node); - newTech.srcNode = static_cast<csWrappedDocumentNode*> ( - (iWrappedDocumentNode*)wrappedNode); - - techVar.techniques.Push (newTech); - } - } - csXMLShaderTech* usedTech = 0; for (size_t t = 0; t < techVar.techniques.GetSize(); t++) { @@ -791,9 +923,8 @@ csRef<iHierarchicalCache> techCache; if (shaderCache) { - uint cacheID = (t * (tvc)) + tvi; techCache = shaderCache->GetRootedCache ( - csString().Format ("/%s/%u", cacheScope_tech.GetData(), cacheID)); + csString().Format ("/%s/%zu/%zu", cacheScope_tech.GetData(), tvi, t)); } if (tech.resolver == 0) { @@ -822,6 +953,13 @@ { ShaderVariant& var = tech.variants.GetExtend (vi); ticket = ((vi*techVar.techniques.GetSize() + t) * (tvc+1) + (tvi+1)); + + csRef<iHierarchicalCache> varCache; + if (techCache) + { + varCache = techCache->GetRootedCache ( + csString().Format ("/%zu", vi)); + } if (!var.prepared) { @@ -835,30 +973,47 @@ GetName(), tvi, vi)); } + iShaderProgram::CacheLoadResult loadResult = iShaderProgram::loadFail; var.tech = 0; if (techCache.IsValid()) { var.tech = new csXMLShaderTech (this); - if (var.tech->LoadFromCache (ldr_context, techCache, shaderRoot, ticket)) + loadResult = var.tech->LoadFromCache (ldr_context, varCache, shaderRoot, ticket); + if (compiler->do_verbose) { - if (compiler->do_verbose) - compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, - "Shader '%s'<%zu/%zu>: Technique with priority %d succeeds (from cache)!", - GetName(), tvi, vi, tech.priority); + switch (loadResult) + { + case iShaderProgram::loadFail: + { + compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, + "Shader '%s'<%zu/%zu>: Technique with priority %d fails (from cache). Reason: %s.", + GetName(), tvi, vi, tech.priority, var.tech->GetFailReason()); + } + break; + case iShaderProgram::loadSuccessShaderInvalid: + { + compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, + "Shader '%s'<%zu/%zu>: Technique with priority %d succeeds (from cache) but shader is invalid.", + GetName(), tvi, vi, tech.priority); + } + break; + case iShaderProgram::loadSuccessShaderValid: + { + compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, + "Shader '%s'<%zu/%zu>: Technique with priority %d succeeds (from cache).", + GetName(), tvi, vi, tech.priority); + } + break; + } } - else + if (loadResult != iShaderProgram::loadSuccessShaderValid) { - if (compiler->do_verbose) - { - compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, - "Shader '%s'<%zu/%zu>: Technique with priority %d fails (from cache). Reason: %s.", - GetName(), tvi, vi, tech.priority, var.tech->GetFailReason()); - } delete var.tech; var.tech = 0; } } - if (var.tech == 0) + if ((var.tech == 0) + && (loadResult == iShaderProgram::loadFail)) { // So external files are found correctly csVfsDirectoryChanger dirChange (compiler->vfs); @@ -866,7 +1021,7 @@ var.tech = new csXMLShaderTech (this); if (var.tech->Load (ldr_context, tech.techNode, shaderRoot, ticket, - techCache)) + varCache)) { if (compiler->do_verbose) compiler->Report (CS_REPORTER_SEVERITY_NOTIFY, @@ -926,6 +1081,33 @@ return ticket; } + +void csXMLShader::PrepareTechVar (ShaderTechVariant& techVar, + int forcepriority) +{ + if (!techVar.prepared) + { + csArray<TechniqueKeeper> techniquesTmp; + ScanForTechniques (shaderRoot, techniquesTmp, forcepriority); + + /* Find a suitable technique + * (Note that a wrapper is created for each technique node individually, + * not the whole shader) */ + csArray<TechniqueKeeper>::Iterator techIt = techniquesTmp.GetIterator (); + while (techIt.HasNext ()) + { + const TechniqueKeeper& tk = techIt.Next(); + ShaderTechVariant::Technique newTech; + newTech.priority = tk.priority; + csRef<iWrappedDocumentNode> wrappedNode = + scfQueryInterface<iWrappedDocumentNode> (tk.node); + newTech.srcNode = static_cast<csWrappedDocumentNode*> ( + (iWrappedDocumentNode*)wrappedNode); + + techVar.techniques.Push (newTech); + } + } +} bool csXMLShader::LoadTechniqueFromCache (ShaderTechVariant::Technique& tech, iHierarchicalCache* cache) Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.h =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.h 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shader.h 2008-07-04 14:25:01 UTC (rev 30207) @@ -265,7 +265,10 @@ protected: void InternalRemove() { SelfDestruct(); } - void Load (iDocumentNode* source); + void Load (iDocumentNode* source, bool noCacheRead); + + void PrepareTechVar (ShaderTechVariant& techVar, + int forcepriority); bool LoadTechniqueFromCache (ShaderTechVariant::Technique& tech, iHierarchicalCache* cache); @@ -277,7 +280,10 @@ csXMLShader (csXMLShaderCompiler* compiler, iLoaderContext* ldr_context, iDocumentNode* source, int forcepriority); + csXMLShader (csXMLShaderCompiler* compiler); virtual ~csXMLShader(); + + bool Precache (iDocumentNode* source, iHierarchicalCache* cacheTo); virtual iObject* QueryObject () { return (iObject*)(csObject*)this; } Modified: CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shadertech.cpp =================================================================== --- CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shadertech.cpp 2008-07-04 02:55:28 UTC (rev 30206) +++ CS/trunk/plugins/video/render3d/shader/shadercompiler/xmlshader/shadertech.cpp 2008-07-04 14:25:01 UTC (rev 30207) @@ -81,13 +81,21 @@ return (mode == CS_FX_DESTALPHAADD); } +struct csXMLShaderTech::LoadHelpers +{ + iSyntaxService* synldr; + iStringSet* strings; + iShaderVarStringSet* stringsSvName; +}; + bool csXMLShaderTech::LoadPass (iDocumentNode *node, ShaderPass* pass, size_t variant, iFile* cacheFile, iHierarchicalCache* cacheTo) { - iSyntaxService* synldr = parent->compiler->synldr; - iStringSet* strings = parent->compiler->strings; - iShaderVarStringSet* stringsSvName = parent->compiler->stringsSvName; + LoadHelpers hlp; + hlp.synldr = parent->compiler->synldr; + hlp.strings = parent->compiler->strings; + hlp.stringsSvName = parent->compiler->stringsSvName; CachedPlugins cachedPlugins; @@ -171,13 +179,7 @@ } { - csRef<iDocumentNode> nodeMixMode = node->GetNode ("mixmode"); - if (nodeMixMode != 0) - { - uint mm; - if (synldr->ParseMixmode (nodeMixMode, mm, true)) - pass->mixMode = mm; - } + if (!ParseModes (pass, node, hlp)) return false; const csGraphics3DCaps* caps = parent->g3d->GetCaps(); if (IsDestalphaMixmode (pass->mixMode) && !caps->DestinationAlpha) @@ -186,73 +188,195 @@ SetFailReason ("destination alpha not supported by renderer"); return false; } + } - csRef<iDocumentNode> nodeAlphaMode = node->GetNode ("alphamode"); - if (nodeAlphaMode != 0) + //if we got this far, load buffermappings + if (!ParseBuffers (pass, node, hlp, resolveFP, resolveVP)) return false; + + //get texturemappings + if (!ParseTextures (pass, node, hlp, resolveFP)) return false; + + WritePass (pass, cachedPlugins, cacheFile); + + return true; +} + +bool csXMLShaderTech::PrecachePass (iDocumentNode *node, ShaderPass* pass, + size_t variant, iFile* cacheFile, + iHierarchicalCache* cacheTo) +{ + LoadHelpers hlp; + hlp.synldr = parent->compiler->synldr; + hlp.strings = parent->compiler->strings; + hlp.stringsSvName = parent->compiler->stringsSvName; + + CachedPlugins cachedPlugins; + + csRef<iDocumentNode> programNode; + csRef<iShaderProgram> program; + // load fp + /* This is done before VP loading b/c the VP could query for TU bindings + * which are currently handled by the FP. */ + programNode = node->GetNode (xmltokens.Request ( + csXMLShaderCompiler::XMLTOKEN_FP)); + + csRef<iBase> fp; + if (programNode) + { + csRef<iHierarchicalCache> fpCache; + fpCache = cacheTo->GetRootedCache (csString().Format ( + "/pass%dfp", GetPassNumber (pass))); + if (!PrecacheProgram (0, programNode, pass, variant, fpCache, + cachedPlugins.fp, fp)) { - csAlphaMode am; - if (synldr->ParseAlphaMode (nodeAlphaMode, strings, am)) - { - pass->alphaMode = am; - } + if (do_verbose) + SetFailReason ("fragment program failed to precache"); + return false; } + } - csRef<iDocumentNode> nodeZmode = node->GetNode ("zmode"); - if (nodeZmode != 0) + csRef<iShaderDestinationResolver> resolveFP ( + scfQueryInterfaceSafe<iShaderDestinationResolver> (fp)); + + //load vp + programNode = node->GetNode(xmltokens.Request ( + csXMLShaderCompiler::XMLTOKEN_VP)); + + csRef<iBase> vp; + if (programNode) + { + csRef<iHierarchicalCache> vpCache; + vpCache = cacheTo->GetRootedCache (csString().Format ( + "/pass%dvp", GetPassNumber (pass))); + if (!PrecacheProgram (resolveFP, programNode, pass, variant, vpCache, + cachedPlugins.vp, vp)) { - csRef<iDocumentNode> node; - csRef<iDocumentNodeIterator> it; - it = nodeZmode->GetNodes (); - while (it->HasNext ()) - { - csRef<iDocumentNode> child = it->Next (); - if (child->GetType () != CS_NODE_ELEMENT) continue; - node = child; - break; - } + if (do_verbose) + SetFailReason ("vertex program failed to precache"); + return false; + } + } - if (synldr->ParseZMode (node, pass->zMode, true)) - { - pass->overrideZmode = true; - } - else - { - synldr->ReportBadToken (node); - } + csRef<iShaderDestinationResolver> resolveVP ( + scfQueryInterfaceSafe<iShaderDestinationResolver> (vp)); + + //load vproc + programNode = node->GetNode(xmltokens.Request ( + csXMLShaderCompiler::XMLTOKEN_VPROC)); + + if (programNode) + { + csRef<iBase> vpr; + csRef<iHierarchicalCache> vprCache; + vprCache = cacheTo->GetRootedCache (csString().Format ( + "/pass%dvpr", GetPassNumber (pass))); + if (!PrecacheProgram (resolveFP, programNode, pass, variant, vprCache, + cachedPlugins.vproc, vpr)) + { + if (do_verbose) + SetFailReason ("vertex preprocessor failed to precache"); + return false; } + } - csRef<iDocumentNode> nodeFlipCulling = node->GetNode ("flipculling"); - if (nodeFlipCulling) + if (!ParseModes (pass, node, hlp)) return false; + + //if we got this far, load buffermappings + if (!ParseBuffers (pass, node, hlp, resolveFP, resolveVP)) return false; + + //get texturemappings + if (!ParseTextures (pass, node, hlp, resolveFP)) return false; + + WritePass (pass, cachedPlugins, cacheFile); + + return true; +} + +bool csXMLShaderTech::ParseModes (ShaderPass* pass, + iDocumentNode* node, + LoadHelpers& h) +{ + csRef<iDocumentNode> nodeMixMode = node->GetNode ("mixmode"); + if (nodeMixMode != 0) + { + uint mm; + if (h.synldr->ParseMixmode (nodeMixMode, mm, true)) + pass->mixMode = mm; + } + + csRef<iDocumentNode> nodeAlphaMode = node->GetNode ("alphamode"); + if (nodeAlphaMode != 0) + { + csAlphaMode am; + if (h.synldr->ParseAlphaMode (nodeAlphaMode, h.strings, am)) { - synldr->ParseBool(nodeFlipCulling, pass->flipCulling, false); + pass->alphaMode = am; } + } - csRef<iDocumentNode> nodeZOffset = node->GetNode ("zoffset"); - if (nodeZOffset) + csRef<iDocumentNode> nodeZmode = node->GetNode ("zmode"); + if (nodeZmode != 0) + { + csRef<iDocumentNode> node; + csRef<iDocumentNodeIterator> it; + it = nodeZmode->GetNodes (); + while (it->HasNext ()) { - synldr->ParseBool (nodeZOffset, pass->zoffset, false); + csRef<iDocumentNode> child = it->Next (); + if (child->GetType () != CS_NODE_ELEMENT) continue; + node = child; + break; } - - pass->wmRed = true; - pass->wmGreen = true; - pass->wmBlue = true; - pass->wmAlpha = true; - csRef<iDocumentNode> nodeWM = node->GetNode ("writemask"); - if (nodeWM != 0) + if (h.synldr->ParseZMode (node, pass->zMode, true)) { - if (nodeWM->GetAttributeValue ("r") != 0) - pass->wmRed = !strcasecmp (nodeWM->GetAttributeValue ("r"), "true"); - if (nodeWM->GetAttributeValue ("g") != 0) - pass->wmGreen = !strcasecmp (nodeWM->GetAttributeValue ("g"), "true"); - if (nodeWM->GetAttributeValue ("b") != 0) - pass->wmBlue = !strcasecmp (nodeWM->GetAttributeValue ("b"), "true"); - if (nodeWM->GetAttributeValue ("a") != 0) - pass->wmAlpha = !strcasecmp (nodeWM->GetAttributeValue ("a"), "true"); + pass->overrideZmode = true; } + else + { + h.synldr->ReportBadToken (node); + } } - //if we got this far, load buffermappings + csRef<iDocumentNode> nodeFlipCulling = node->GetNode ("flipculling"); + if (nodeFlipCulling) + { + h.synldr->ParseBool(nodeFlipCulling, pass->flipCulling, false); + } + + csRef<iDocumentNode> nodeZOffset = node->GetNode ("zoffset"); + if (nodeZOffset) + { + h.synldr->ParseBool (nodeZOffset, pass->zoffset, false); + } + + + pass->wmRed = true; + pass->wmGreen = true; + pass->wmBlue = true; + pass->wmAlpha = true; + csRef<iDocumentNode> nodeWM = node->GetNode ("writemask"); + if (nodeWM != 0) + { + if (nodeWM->GetAttributeValue ("r") != 0) + pass->wmRed = !strcasecmp (nodeWM->GetAttributeValue ("r"), "true"); + if (nodeWM->GetAttributeValue ("g") != 0) + pass->wmGreen = !strcasecmp (nodeWM->GetAttributeValue ("g"), "true"); + if (nodeWM->GetAttributeValue ("b") != 0) + pass->wmBlue = !strcasecmp (nodeWM->GetAttributeValue ("b"), "true"); + if (nodeWM->GetAttributeValue ("a") != 0) + pass->wmAlpha = !strcasecmp (nodeWM->GetAttributeValue ("a"), "true"); + } + + return true; +} + +bool csXMLShaderTech::ParseBuffers (ShaderPass* pass, + iDocumentNode* node, + LoadHelpers& h, + iShaderDestinationResolver* resolveFP, + iShaderDestinationResolver* resolveVP) +{ csRef<iDocumentNodeIterator> it; it = node->GetNodes (xmltokens.Request (csXMLShaderCompiler::XMLTOKEN_BUFFER)); while(it->HasNext ()) @@ -360,7 +484,7 @@ if (cname == 0) cname = source; - CS::ShaderVarStringID varID = stringsSvName->Request (cname); + CS::ShaderVarStringID varID = h.stringsSvName->Request (cname); pass->custommapping_id.Push (varID); //pass->bufferGeneric[pass->bufferCount] = CS_VATTRIB_IS_GENERIC (attrib); @@ -403,9 +527,15 @@ } } } + return true; +} - - //get texturemappings +bool csXMLShaderTech::ParseTextures (ShaderPass* pass, + iDocumentNode* node, + LoadHelpers& h, + iShaderDestinationResolver* resolveFP) +{ + csRef<iDocumentNodeIterator> it; it = node->GetNodes (xmltokens.Request ( csXMLShaderCompiler::XMLTOKEN_TEXTURE)); while(it->HasNext ()) @@ -460,15 +590,12 @@ CS::Graphics::ShaderVarNameParser parser ( mapping->GetAttributeValue("name")); - texMap.id = stringsSvName->Request (parser.GetShaderVarName ()); + texMap.id = h.stringsSvName->Request (parser.GetShaderVarName ()); parser.FillArrayWithIndices (texMap.indices); texMap.textureUnit = texUnit; pass->textures.Push (texMap); } } - - WritePass (pass, cachedPlugins, cacheFile); - return true; } @@ -636,22 +763,23 @@ return true; } -bool csXMLShaderTech::LoadPassFromCache (ShaderPass* pass, size_t variant, - iFile* cacheFile, - iHierarchicalCache* cache) +iShaderProgram::CacheLoadResult csXMLShaderTech::LoadPassFromCache ( + ShaderPass* pass, size_t variant, iFile* cacheFile, + iHierarchicalCache* cache) { - if (!cacheFile) return false; + if (!cacheFile) return iShaderProgram::loadFail; CachedPlugins plugins; - if (!ReadPass (pass, cacheFile, plugins)) return false; + if (!ReadPass (pass, cacheFile, plugins)) return iShaderProgram::loadFail; + iShaderProgram::CacheLoadResult loadRes; if (plugins.fp.available) { csRef<iHierarchicalCache> fpCache; if (cache) fpCache = cache->GetRootedCache (csString().Format ( "/pass%dfp", GetPassNumber (pass))); - pass->fp = LoadProgramFromCache (pass, variant, fpCache, plugins.fp); - if (!pass->fp.IsValid()) return false; + loadR... [truncated message content] |