Shader Compile.cpp 102 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #include "../Shaders/!Header CPU.h"
  4. /******************************************************************************
  5. If in the future compilation no longer is based on D3DX9 then remove:
  6. ThirdPartyLibs\D3DX9
  7. ThirdPartyLibs\D3DX11
  8. /******************************************************************************/
  9. #if WINDOWS
  10. #define THIS void
  11. #undef MAX_FVF_DECL_SIZE
  12. #include "../../../ThirdPartyLibs/begin.h"
  13. #if WINDOWS_OLD
  14. #include "../../../ThirdPartyLibs/D3DX9/d3dx9shader.h"
  15. #endif
  16. #include "../../../ThirdPartyLibs/D3DX11/inc/d3dx11effect.h"
  17. #include "../../../ThirdPartyLibs/end.h"
  18. #endif
  19. namespace EE{
  20. /******************************************************************************/
  21. #define CC4_SHDR CC4('S','H','D','R')
  22. /******************************************************************************/
  23. enum SHADER_TYPE
  24. {
  25. SHADER_GL ,
  26. SHADER_DX9 ,
  27. SHADER_DX11,
  28. };
  29. /******************************************************************************/
  30. #define FLAGS_DX9 (1 ? (D3DXSHADER_OPTIMIZATION_LEVEL3|D3DXSHADER_NO_PRESHADER|D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY) : (D3DXSHADER_OPTIMIZATION_LEVEL0|D3DXSHADER_NO_PRESHADER|D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY)) // D3DXSHADER_SKIPOPTIMIZATION made "Ambient Occlusion" shader don't compile
  31. #define FLAGS_DX11 (D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY|D3DCOMPILE_OPTIMIZATION_LEVEL3|D3DCOMPILE_NO_PRESHADER)
  32. #define SHOW_GLSL_SRC 0
  33. #if 0 // Test #1: shader size 6.61 MB, engine load+render 1 frame = 0.40s on Windows, decompression 10x faster
  34. #define COMPRESS_GL COMPRESS_LZ4
  35. #define COMPRESS_GL_LEVEL 11
  36. #elif 0 // Test #2: Shaders compiled in: 50.527s, load+draw 1 frame: 0.86s, Main size 346 KB
  37. #define COMPRESS_GL COMPRESS_ZSTD
  38. #define COMPRESS_GL_LEVEL 99
  39. #elif 1 // Test #1: shader size 5.15 MB, engine load+render 1 frame = 0.45s on Windows, decompression 10x slower, Test #2: Shaders compiled in: 50.791s, load+draw 1 frame: 0.88s, Main size 337 KB
  40. #define COMPRESS_GL COMPRESS_LZMA
  41. #define COMPRESS_GL_LEVEL 9 // shader files are small, so we can use high compression level and still get small dictionary size / memory usage
  42. #else // shader size was slightly bigger than LZMA, and loading all shader techs was bit slower
  43. #define COMPRESS_GL COMPRESS_LZHAM
  44. #define COMPRESS_GL_LEVEL 5
  45. #endif
  46. #define COMPRESS_GL_MT true
  47. /******************************************************************************/
  48. #pragma pack(push, 1)
  49. struct ConstantIndex9
  50. {
  51. Byte count;
  52. UShort start, offset, src_index;
  53. void set(Int start, Int count, Int offset, Int src_index) {_Unaligned(T.start, start); _Unaligned(T.count, count); _Unaligned(T.offset, offset); _Unaligned(T.src_index, src_index); DYNAMIC_ASSERT(T.start==start && T.count==count && T.offset==offset && T.src_index==src_index, S+"Constant index out of range: "+start+", "+count+", "+offset+", "+src_index);}
  54. ConstantIndex9(Int start, Int count, Int offset, Int src_index) {set(start, count, offset, src_index);}
  55. ConstantIndex9() {}
  56. };
  57. struct TextureIndex9
  58. {
  59. UShort bind_index, src_index;
  60. void set(Int bind_index, Int src_index) {_Unaligned(T.bind_index, bind_index); _Unaligned(T.src_index, src_index); DYNAMIC_ASSERT(T.bind_index==bind_index && T.src_index==src_index, "Constant index out of range");}
  61. TextureIndex9(Int bind_index, Int src_index) {set(bind_index, src_index);}
  62. TextureIndex9() {}
  63. };
  64. struct ConstantIndex
  65. {
  66. Byte bind_index;
  67. UShort src_index;
  68. void set(Int bind_index, Int src_index) {_Unaligned(T.bind_index, bind_index); _Unaligned(T.src_index, src_index); DYNAMIC_ASSERT(T.bind_index==bind_index && T.src_index==src_index, "Constant index out of range");}
  69. ConstantIndex(Int bind_index, Int src_index) {set(bind_index, src_index);}
  70. ConstantIndex() {}
  71. };
  72. #pragma pack(pop)
  73. #if WINDOWS_OLD
  74. static Int Compare(C Shader9::Constant &a, C Shader9::Constant &b) {return Compare(a.start, b.start);}
  75. #endif
  76. static Int Compare(C ShaderBufferParams &a, C ShaderBufferParams &b) {return ComparePtr(a.buffer, b.buffer);} // sort by buffer pointer, because that's the only thing we can access from 'Shader.Constant'
  77. static Int Compare(C ShaderBufferParams &a, ShaderBuffer*C &b) {return ComparePtr(a.buffer, b );} // sort by buffer pointer, because that's the only thing we can access from 'Shader.Constant'
  78. static Int Compare( ShaderImage*C &a, ShaderImage*C &b) {return ComparePtr(a , b );} // sort by image pointer, because that's the only thing we can access from 'Shader.Texture'
  79. static Int GetIndex(C Memc<ShaderImage* > & images, ShaderImage *image ) {Int index; if(! images.binarySearch(image , index, Compare))Exit("Image not found in Shader" ); return index;}
  80. static Int GetIndex(C Map <Str8, ShaderParam > & params, ShaderParam *param ) {Int index = params. dataToIndex(param ); if(index<0)Exit("Param not found in Shader" ); return index;}
  81. static Int GetIndex(C Memc<ShaderBufferParams> &buffers, ShaderBuffer *buffer) {Int index; if(!buffers.binarySearch(buffer, index, Compare))Exit("Buffer not found in Shader"); return index;}
  82. static UShort AsUShort(Int i) {DYNAMIC_ASSERT(InRange(i, USHORT_MAX+1), "Value too big to be represented as UShort"); return i;}
  83. static ShaderImage * Get(Int i, C MemtN<ShaderImage *, 256> &images ) {if(!InRange(i, images ))Exit("Invalid ShaderImage index" ); return images[i];}
  84. static ShaderParam * Get(Int i, C MemtN<ShaderParam *, 256> &params ) {if(!InRange(i, params ))Exit("Invalid ShaderParam index" ); return params[i];}
  85. static ShaderBuffer* Get(Int i, C MemtN<ShaderBuffer*, 256> &buffers) {if(!InRange(i, buffers))Exit("Invalid ShaderBuffer index"); return buffers[i];}
  86. #if DEBUG
  87. static C Str8& Name(ShaderImage &image ) {C Str8 *name=ShaderImages .dataToKey(&image ); if(!name)Exit("Can't find ShaderImage name" ); return *name;}
  88. static C Str8& Name(ShaderParam &param, C Map<Str8, ShaderParam> &params) {C Str8 *name= params .dataToKey(&param ); if(!name)Exit("Can't find ShaderParam name" ); return *name;}
  89. static C Str8& Name(ShaderBuffer &buffer ) {C Str8 *name=ShaderBuffers.dataToKey(&buffer); if(!name)Exit("Can't find ShaderBuffer name"); return *name;}
  90. #else
  91. static C Str8& Name(ShaderImage &image ) {return ShaderImages .dataInMapToKey(image );}
  92. static C Str8& Name(ShaderParam &param, C Map<Str8, ShaderParam> &params) {return params .dataInMapToKey(param );}
  93. static C Str8& Name(ShaderBuffer &buffer ) {return ShaderBuffers.dataInMapToKey(buffer);}
  94. #endif
  95. /******************************************************************************/
  96. // INCLUDE
  97. /******************************************************************************/
  98. #if WINDOWS
  99. struct ShaderPath
  100. {
  101. Char path[MAX_LONG_PATH];
  102. };
  103. /******************************************************************************/
  104. #if WINDOWS_OLD
  105. struct Include9 : ID3DXInclude // 'Include9' should not have 'root' because unlike DX10 we're loading first file from path, and not from memory, also on DX9 'pParentData' is buggy and sometimes gives null
  106. {
  107. Memc<Str> paths; // use this because 'pParentData' can be null
  108. HRESULT __stdcall Open(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes)
  109. {
  110. *ppData=null;
  111. *pBytes=0;
  112. File f;
  113. Str path=GetPath(pFileName);
  114. if(!FullPath(path))
  115. if(ShaderPath *parent=(pParentData ? (ShaderPath*)pParentData-1 : null))
  116. path=NormalizePath(Str(parent->path).tailSlash(true)+path);
  117. else // if DX9 fails to provide 'pParentData' we must use previously detected paths
  118. {
  119. REPA(paths)if(f.readStdTry(paths[i]+pFileName)){path=GetPath(paths[i]+pFileName); break;}
  120. }
  121. if(f.is() || f.readStdTry(path.tailSlash(true)+GetBase(pFileName)))
  122. {
  123. Byte *data=Alloc<Byte>(SIZEU(ShaderPath)+f.size());
  124. Set(((ShaderPath*)data)->path, path);
  125. paths.include(path.tailSlash(true));
  126. data+=SIZE(ShaderPath);
  127. f.get(data, f.size());
  128. *ppData=data;
  129. *pBytes=f.size();
  130. return S_OK;
  131. }
  132. return -1;
  133. }
  134. HRESULT __stdcall Close(LPCVOID pData)
  135. {
  136. if(pData)
  137. {
  138. Byte *data=((Byte*)pData)-SIZE(ShaderPath);
  139. Free( data);
  140. }
  141. return S_OK;
  142. }
  143. Include9(C Str &src) {}
  144. };
  145. #endif
  146. /******************************************************************************/
  147. struct Include11 : ID3DInclude
  148. {
  149. ShaderPath root;
  150. HRESULT __stdcall Open(D3D_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pBytes)
  151. {
  152. *ppData=null;
  153. *pBytes=0;
  154. Str path=GetPath(pFileName);
  155. if(!FullPath(path))
  156. if(ShaderPath *parent=(pParentData ? (ShaderPath*)pParentData-1 : &root))
  157. path=NormalizePath(Str(parent->path).tailSlash(true)+path);
  158. File f; if(f.readStdTry(path.tailSlash(true)+GetBase(pFileName)))
  159. {
  160. Byte *data=Alloc<Byte>(SIZEU(ShaderPath)+f.size());
  161. Set(((ShaderPath*)data)->path, path);
  162. data+=SIZE(ShaderPath);
  163. f.get(data, f.size());
  164. *ppData=data;
  165. *pBytes=f.size();
  166. return S_OK;
  167. }
  168. return -1;
  169. }
  170. HRESULT __stdcall Close(LPCVOID pData)
  171. {
  172. if(pData)
  173. {
  174. Byte *data=((Byte*)pData)-SIZE(ShaderPath);
  175. Free( data);
  176. }
  177. return S_OK;
  178. }
  179. Include11(C Str &src)
  180. {
  181. Set(root.path, GetPath(src));
  182. }
  183. };
  184. #endif
  185. /******************************************************************************/
  186. // ERRORS
  187. /******************************************************************************/
  188. #if WINDOWS_OLD
  189. static void Error(ID3DXBuffer* &error, Str *messages)
  190. {
  191. if(error)
  192. {
  193. if(messages)messages->line()+=(Char8*)error->GetBufferPointer();
  194. RELEASE(error);
  195. }
  196. }
  197. #endif
  198. #if WINDOWS
  199. static void Error(ID3D10Blob* &error, Str *messages)
  200. {
  201. if(error)
  202. {
  203. if(messages)messages->line()+=(Char8*)error->GetBufferPointer();
  204. RELEASE(error);
  205. }
  206. }
  207. #endif
  208. /******************************************************************************/
  209. // EFFECT CREATION
  210. /******************************************************************************/
  211. #if WINDOWS_OLD
  212. static ID3DXEffect* CreateEffect9(C Str &src, C MemPtr<ShaderMacro> &macros, Str *messages)
  213. {
  214. #if DX9
  215. ID3DXEffect *effect =null;
  216. ID3DXBuffer *buffer =null, *error=null;
  217. ID3DXEffectCompiler *compiler=null;
  218. if(messages)messages->clear();
  219. Mems<D3DXMACRO> d3d_macros; d3d_macros.setNum(macros.elms()+1);
  220. FREPA(macros){D3DXMACRO &m=d3d_macros[i]; m.Name=macros[i].name; m.Definition=macros[i].definition;} Zero(d3d_macros.last());
  221. Include9 include(src); // let this exist in case 'CompileEffect' uses it
  222. D3DXCreateEffectCompilerFromFile(src, d3d_macros.data(), &include, FLAGS_DX9, &compiler, &error); Error(error, messages);
  223. if(compiler)
  224. {
  225. compiler->CompileEffect(FLAGS_DX9, &buffer, &error); Error(error, messages);
  226. RELEASE(compiler);
  227. }
  228. if(buffer)
  229. {
  230. {
  231. SyncLocker lock(D._lock);
  232. D3DXCreateEffect(GetD3D9(), buffer->GetBufferPointer(), buffer->GetBufferSize(), null, null, 0, null, &effect, &error); Error(error, messages);
  233. }
  234. RELEASE(buffer);
  235. if(!effect && messages)messages->line()+="Compilation succeeded but creating effect (D3DXCreateEffect) failed.";
  236. }
  237. return effect;
  238. #elif DX11
  239. if(messages)messages->clear();
  240. File f; if(!f.readTry(src)){if(messages)messages->line()+="Failed to open file."; return false;}
  241. Mems<Byte> data; data.setNum(f.size()); if(!f.get(data.data(), f.size())){if(messages)messages->line()+="Failed to read from file."; return false;} f.del(); // release the file handle after reading
  242. Mems<D3D_SHADER_MACRO> d3d_macros; d3d_macros.setNum(macros.elms()+1);
  243. FREPA(macros){D3D_SHADER_MACRO &m=d3d_macros[i]; m.Name=macros[i].name; m.Definition=macros[i].definition;} Zero(d3d_macros.last());
  244. ID3D10Blob *buffer=null, *error=null;
  245. D3DCompile(data.data(), data.elms(), null, d3d_macros.data(), &Include11(src), null, "fx_2_0", FLAGS_DX11, 0, &buffer, &error); Error(error, messages);
  246. ID3DXEffect *effect=null;
  247. if(buffer)
  248. {
  249. {
  250. ID3DXBuffer *error=null;
  251. SyncLocker lock(D._lock);
  252. D3DXCreateEffect(GetD3D9(), buffer->GetBufferPointer(), buffer->GetBufferSize(), null, null, 0, null, &effect, &error); Error(error, messages);
  253. }
  254. RELEASE(buffer);
  255. if(!effect && messages)messages->line()+="Compilation succeeded but creating effect (D3DXCreateEffect) failed.";
  256. }
  257. return effect;
  258. #else
  259. return null;
  260. #endif
  261. }
  262. #endif
  263. /******************************************************************************/
  264. // TRANSLATION
  265. /******************************************************************************/
  266. #if WINDOWS_OLD
  267. static void AddTranslation9(ShaderParam &sp, ID3DXEffect *effect, D3DXHANDLE par, C D3DXPARAMETER_DESC &par_desc)
  268. {
  269. if(par_desc.Class==D3DXPC_SCALAR || par_desc.Class==D3DXPC_VECTOR) // for example Flt f,f[]; Vec2 v,v[]; Vec v,v[]; Vec4 v,v[];
  270. {
  271. if(par_desc.Rows!=1)Exit("Shader Param Rows!=1");
  272. if(par_desc.Type==D3DXPT_FLOAT)// || par_desc.Type==D3DXPT_INT || par_desc.Type==D3DXPT_BOOL)
  273. {
  274. FREP(Max(1, par_desc.Elements)) // array size
  275. {
  276. sp._full_translation.New().set(sp._cpu_data_size, sp._gpu_data_size, SIZE(Flt)*par_desc.Columns);
  277. sp._cpu_data_size+=SIZE(Flt )*par_desc.Columns;
  278. sp._gpu_data_size+=SIZE(Vec4);
  279. }
  280. }else Exit(S+"Unhandled Shader Parameter Type for \""+par_desc.Name+'"');
  281. }else
  282. if(par_desc.Class==D3DXPC_MATRIX_COLUMNS)
  283. {
  284. Exit("Need to test D3DXPC_MATRIX_COLUMNS translation");
  285. if(par_desc.Rows >4)Exit("Shader Param Matrix Rows>4");
  286. if(par_desc.Columns>4)Exit("Shader Param Matrix Cols>4");
  287. if(par_desc.Type!=D3DXPT_FLOAT)Exit(S+"Unhandled Shader Parameter Type for \""+par_desc.Name+'"');
  288. FREP(Max(1, par_desc.Elements)) // array size
  289. {
  290. FREPD(y, par_desc.Columns)
  291. FREPD(x, par_desc.Rows )sp._full_translation.New().set(sp._cpu_data_size+SIZE(Flt)*(y+x*par_desc.Columns), sp._gpu_data_size+SIZE(Flt)*(x+y*4), SIZE(Flt));
  292. sp._cpu_data_size+=SIZE(Flt)*par_desc.Rows*par_desc.Columns;
  293. sp._gpu_data_size+=SIZE(Flt)* 4*par_desc.Columns;
  294. }
  295. }else
  296. if(par_desc.Class==D3DXPC_MATRIX_ROWS)
  297. {
  298. if(par_desc.Rows >4)Exit("Shader Param Matrix Rows>4");
  299. if(par_desc.Columns>4)Exit("Shader Param Matrix Cols>4");
  300. if(par_desc.Type!=D3DXPT_FLOAT)Exit(S+"Unhandled Shader Parameter Type for \""+par_desc.Name+'"');
  301. FREP(Max(1, par_desc.Elements)) // array size
  302. {
  303. FREPD(y, par_desc.Columns)
  304. FREPD(x, par_desc.Rows )sp._full_translation.New().set(sp._cpu_data_size+SIZE(Flt)*(y+x*par_desc.Columns), sp._gpu_data_size+SIZE(Flt)*(x+y*4), SIZE(Flt));
  305. sp._cpu_data_size+=SIZE(Flt)*par_desc.Rows*par_desc.Columns;
  306. sp._gpu_data_size+=SIZE(Flt)* 4*par_desc.Columns;
  307. }
  308. }else
  309. if(par_desc.Class==D3DXPC_STRUCT)
  310. {
  311. FREP(Max(1, par_desc.Elements)) // array size
  312. {
  313. D3DXHANDLE elm=(par_desc.Elements ? effect->GetParameterElement(par, i) : par);
  314. FREP(par_desc.StructMembers) // number of members
  315. {
  316. D3DXHANDLE child=effect->GetParameter(elm, i);
  317. D3DXPARAMETER_DESC par_desc;
  318. effect->GetParameterDesc(child, &par_desc);
  319. AddTranslation9(sp, effect, child, par_desc);
  320. }
  321. }
  322. }else
  323. {
  324. Exit("Unrecognized Shader Parameter Class");
  325. }
  326. }
  327. #endif
  328. /******************************************************************************/
  329. #if DX11
  330. static void AddTranslation11(ShaderParam &sp, ID3DX11EffectVariable *par, C D3DX11_EFFECT_VARIABLE_DESC &var_desc, C D3DX11_EFFECT_TYPE_DESC &par_desc)
  331. {
  332. if(par_desc.Elements<=1) // array size
  333. {
  334. if(par_desc.Class==D3D10_SVC_SCALAR || par_desc.Class==D3D10_SVC_VECTOR) // for example: Flt f,f[]; Vec2 v,v[]; Vec v,v[]; Vec4 v,v[];
  335. {
  336. if(par_desc.Rows!=1)Exit("Shader Param Rows!=1");
  337. if(par_desc.Type==D3D10_SVT_FLOAT)
  338. {
  339. sp._full_translation.New().set(sp._cpu_data_size, var_desc.BufferOffset, SIZE(Flt)*par_desc.Columns);
  340. sp._cpu_data_size+=SIZE(Flt)*par_desc.Columns;
  341. }else Exit(S+"Unhandled Shader Parameter Type for \""+var_desc.Name+'"');
  342. }else
  343. if(par_desc.Class==D3D10_SVC_MATRIX_COLUMNS)
  344. {
  345. if(par_desc.Rows >4)Exit("Shader Param Matrix Rows>4");
  346. if(par_desc.Columns>4)Exit("Shader Param Matrix Cols>4");
  347. if(par_desc.Type!=D3D10_SVT_FLOAT)Exit(S+"Unhandled Shader Parameter Type for \""+var_desc.Name+'"');
  348. FREPD(y, par_desc.Columns)
  349. FREPD(x, par_desc.Rows )sp._full_translation.New().set(sp._cpu_data_size+SIZE(Flt)*(y+x*par_desc.Columns), var_desc.BufferOffset+SIZE(Flt)*(x+y*4), SIZE(Flt));
  350. sp._cpu_data_size+=SIZE(Flt)*par_desc.Rows*par_desc.Columns;
  351. }else
  352. if(par_desc.Class==D3D10_SVC_STRUCT)
  353. {
  354. FREP(par_desc.Members) // number of members
  355. {
  356. ID3DX11EffectVariable *member=par->GetMemberByIndex(i);
  357. D3DX11_EFFECT_VARIABLE_DESC var_desc; member->GetDesc(&var_desc);
  358. D3DX11_EFFECT_TYPE_DESC par_desc; member->GetType()->GetDesc(&par_desc);
  359. AddTranslation11(sp, member, var_desc, par_desc);
  360. RELEASE(member);
  361. }
  362. }
  363. }else
  364. {
  365. FREP(par_desc.Elements)
  366. {
  367. ID3DX11EffectVariable *elm=par->GetElement(i);
  368. D3DX11_EFFECT_VARIABLE_DESC var_desc; elm->GetDesc(&var_desc);
  369. D3DX11_EFFECT_TYPE_DESC par_desc; elm->GetType()->GetDesc(&par_desc);
  370. AddTranslation11(sp, elm, var_desc, par_desc);
  371. RELEASE(elm);
  372. }
  373. }
  374. }
  375. #endif
  376. /******************************************************************************/
  377. #if WINDOWS_OLD
  378. static void AddRegisters(Mems<Shader9::Constant> &constants, ShaderParam &sp, LPD3DXCONSTANTTABLE ct, D3DXHANDLE constant, C D3DXCONSTANT_DESC &desc, Int &gpu_data_offset)
  379. {
  380. if(desc.Class==D3DXPC_SCALAR || desc.Class==D3DXPC_VECTOR) // for example: Flt f,f[]; Vec2 v,v[]; Vec v,v[]; Vec4 v,v[];
  381. {
  382. if(desc.RegisterCount)constants.New().set(desc.RegisterIndex, desc.RegisterCount, sp._data+gpu_data_offset, sp);
  383. gpu_data_offset+=desc.Elements*SIZE(Vec4); // array size
  384. }else
  385. if(desc.Class==D3DXPC_MATRIX_COLUMNS)
  386. {
  387. if(desc.RegisterCount)constants.New().set(desc.RegisterIndex, desc.RegisterCount, sp._data+gpu_data_offset, sp);
  388. gpu_data_offset+=desc.Elements*SIZE(Vec4)*desc.Columns; // array size
  389. }else
  390. if(desc.Class==D3DXPC_STRUCT)
  391. {
  392. FREP(desc.Elements) // array size
  393. {
  394. D3DXHANDLE elm=ct->GetConstantElement(constant, i);
  395. FREP(desc.StructMembers) // members count
  396. {
  397. D3DXHANDLE child=ct->GetConstant(elm, i);
  398. D3DXCONSTANT_DESC desc[16];
  399. UINT count=Elms(desc);
  400. ct->GetConstantDesc(child, desc, &count); if(count!=1)Exit("count!=1");
  401. AddRegisters(constants, sp, ct, child, desc[0], gpu_data_offset);
  402. }
  403. }
  404. }else
  405. {
  406. Exit("Unrecognized Shader Parameter Class");
  407. }
  408. }
  409. #endif
  410. /******************************************************************************/
  411. // SAVE
  412. /******************************************************************************/
  413. #if WINDOWS_OLD
  414. static Bool ShaderSave(C Str &name, C Map<Str8, ShaderParam> &params, C Memc<ShaderImage*> &images, C Memc<ShaderVS9> &vs, C Memc<ShaderPS9> &ps, C Memc<Shader9> &techs)
  415. {
  416. File f; if(f.writeTry(name))
  417. {
  418. f.putUInt (CC4_SHDR ); // cc4
  419. f.putByte (SHADER_DX9); // type
  420. f.cmpUIntV(0 ); // version
  421. // params
  422. f.cmpUIntV(params.elms());
  423. FREPAO( params).save(f, params.key(i));
  424. // images
  425. f.cmpUIntV(images.elms());
  426. FREPA(images)f.putStr(Name(*images[i]));
  427. if(vs .save(f)) // shaders
  428. if(ps .save(f))
  429. if(techs .save(f, params, images)) // techniques
  430. if(f.flushOK())return true;
  431. f.del(); FDelFile(name);
  432. }
  433. return false;
  434. }
  435. #endif
  436. #if DX11
  437. static Bool ShaderSave(C Str &name, C Memc<ShaderBufferParams> &buffers, C Memc<ShaderImage*> &images, C Memc<ShaderVS11> &vs, C Memc<ShaderHS11> &hs, C Memc<ShaderDS11> &ds, C Memc<ShaderPS11> &ps, C Memc<Shader11> &techs)
  438. {
  439. File f; if(f.writeTry(name))
  440. {
  441. f.putUInt (CC4_SHDR ); // cc4
  442. f.putByte (SHADER_DX11); // type
  443. f.cmpUIntV(0 ); // version
  444. // constants
  445. f.cmpUIntV(buffers.elms()); FREPA(buffers)
  446. {
  447. C ShaderBufferParams &buf=buffers[i];
  448. // constant buffer
  449. f.putStr(Name(*buf.buffer)).cmpUIntV(buf.buffer->size()).putSByte(buf.index); DYNAMIC_ASSERT(buf.index>=-1 && buf.index<=127, "buf.index out of range");
  450. // params
  451. if(!buf.params.save(f))return false;
  452. }
  453. // images
  454. f.cmpUIntV(images.elms());
  455. FREPA(images)f.putStr(Name(*images[i]));
  456. if(vs .save(f)) // shaders
  457. if(hs .save(f))
  458. if(ds .save(f))
  459. if(ps .save(f))
  460. if(techs.save(f, buffers, images)) // techniques
  461. if(f.flushOK())return true;
  462. f.del(); FDelFile(name);
  463. }
  464. return false;
  465. }
  466. #endif
  467. static Bool ShaderSave(C Str &name, C Map<Str8, ShaderParam> &params, C Memc<ShaderImage*> &images, C Memc<ShaderVSGL> &vs, C Memc<ShaderPSGL> &ps, C Memc<ShaderGL> &techs)
  468. {
  469. File f; if(f.writeTry(name))
  470. {
  471. f.putUInt (CC4_SHDR ); // cc4
  472. f.putByte (SHADER_GL); // type
  473. f.cmpUIntV(0 ); // version
  474. // params
  475. f.cmpUIntV(params.elms());
  476. FREPAO( params).save(f, params.key(i));
  477. // images
  478. f.cmpUIntV(images.elms());
  479. FREPA(images)f.putStr(Name(*images[i]));
  480. if(vs .save(f)) // shaders
  481. if(ps .save(f))
  482. if(techs .save(f, params, images)) // techniques
  483. if(f.flushOK())return true;
  484. f.del(); FDelFile(name);
  485. }
  486. return false;
  487. }
  488. /******************************************************************************/
  489. // COMPILE
  490. /******************************************************************************/
  491. #if WINDOWS_OLD
  492. static Int Compare(C Shader9 &a, C Shader9 &b) {return CompareCS(a.name, b.name);}
  493. #endif
  494. #if WINDOWS
  495. static Int Compare(C Shader11 &a, C Shader11 &b) {return CompareCS(a.name, b.name);}
  496. #endif
  497. static Int Compare(C ShaderGL &a, C ShaderGL &b) {return CompareCS(a.name, b.name);}
  498. static Int Compare(C ShaderGL &a, C Str8 &b) {return CompareCS(a.name, b );}
  499. /******************************************************************************/
  500. static Bool ShaderCompile9(C Str &src, C Str &dest, C MemPtr<ShaderMacro> &macros, Str *messages)
  501. {
  502. #if WINDOWS_OLD
  503. if(ID3DXEffect *effect=CreateEffect9(src, macros, messages))
  504. {
  505. ShaderFile shader;
  506. Map<Str8, ShaderParam> params(CompareCS);
  507. Memc<ShaderImage*> images;
  508. Memc<ShaderVS9> vs ;
  509. Memc<ShaderPS9> ps ;
  510. Memc<Shader9> techs ;
  511. D3DXEFFECT_DESC desc; effect->GetDesc(&desc);
  512. // build list of images and parameters
  513. FREP(desc.Parameters)if(D3DXHANDLE par=effect->GetParameter(null, i))
  514. {
  515. D3DXPARAMETER_DESC par_desc; effect->GetParameterDesc(par, &par_desc);
  516. if(par_desc.Class==D3DXPC_OBJECT)
  517. {
  518. switch(par_desc.Type)
  519. {
  520. //case D3DXPT_TEXTURE: break;
  521. case D3DXPT_SAMPLER:
  522. case D3DXPT_SAMPLER1D:
  523. case D3DXPT_SAMPLER2D:
  524. case D3DXPT_SAMPLER3D:
  525. case D3DXPT_SAMPLERCUBE:
  526. images.add(ShaderImages(Str8Temp(par_desc.Name))); break;
  527. }
  528. }else
  529. {
  530. ShaderParam &sp=*params(Str8Temp(par_desc.Name));
  531. if(sp.is())Exit(S+"Shader parameter \""+par_desc.Name+"\" listed more than once");else // if wasn't yet created
  532. {
  533. sp._owns_data=true;
  534. sp._elements =par_desc.Elements;
  535. AddTranslation9(sp, effect, par, par_desc);
  536. sp.optimize(); // required for setting default value
  537. if(sp._cpu_data_size!=par_desc.Bytes)Exit("Incorrect Shader Param Size.\nPlease contact Developer.");
  538. if(sp._gpu_data_size<SIZE(Vec4))Exit("Shader Param Size < SIZE(Vec4)"); // some functions assume that '_gpu_data_size' is at least as big as 'Vec4' to set values without checking for size
  539. // alloc data
  540. AllocZero(sp._data, sp._gpu_data_size);
  541. *Alloc (sp._changed)=true;
  542. sp._constant_count=sp.fullConstantCount();
  543. // set default value
  544. Vec4 temp[1024]; if(OK(effect->GetValue(par, temp, SIZE(temp))))sp.set(Ptr(temp), sp._cpu_data_size);
  545. }
  546. }
  547. }
  548. images.sort(Compare); // once we have all images for this file, sort them, so we can use binary search later while saving techniques when looking for image indexes
  549. // build list of techniques
  550. IDirect3DDevice9 *d3d=GetD3D9();
  551. FREP(desc.Techniques)
  552. {
  553. D3DXHANDLE tech_handle=effect->GetTechnique (i);
  554. D3DXTECHNIQUE_DESC tech_desc; effect->GetTechniqueDesc( tech_handle , &tech_desc); if(tech_desc.Passes!=1)Exit("Technique pass count!=1");
  555. D3DXPASS_DESC pass_desc; effect->GetPassDesc (effect->GetPass(tech_handle, 0), &pass_desc);
  556. Mems<Byte> vs_data, ps_data;
  557. Shader9 &tech=techs.New(); tech.name=tech_desc.Name;
  558. // get shader data
  559. {
  560. SyncLocker lock(D._lock);
  561. UInt size;
  562. IDirect3DVertexShader9 *vs=null; if(!OK(d3d->CreateVertexShader(pass_desc.pVertexShaderFunction, &vs)))Exit(S+"Can't create Vertex Shader from Shader file \""+src+"\" to file \""+dest+"\"");
  563. IDirect3DPixelShader9 *ps=null; if(!OK(d3d->CreatePixelShader (pass_desc. pPixelShaderFunction, &ps)))Exit(S+ "Can't create Pixel Shader from Shader file \""+src+"\" to file \""+dest+"\"");
  564. vs->GetFunction(null, &size); vs->GetFunction(vs_data.setNum(size).data(), &size); RELEASE(vs);
  565. ps->GetFunction(null, &size); ps->GetFunction(ps_data.setNum(size).data(), &size); RELEASE(ps);
  566. }
  567. // store shaders
  568. if(vs_data.elms()){FREPA(vs)if(vs[i].data.elms()==vs_data.elms() && EqualMem(vs[i].data.data(), vs_data.data(), vs_data.elms())){tech.vs_index=i; break;} if(tech.vs_index<0){tech.vs_index=vs.elms(); Swap(vs.New().data, vs_data);}}
  569. if(ps_data.elms()){FREPA(ps)if(ps[i].data.elms()==ps_data.elms() && EqualMem(ps[i].data.data(), ps_data.data(), ps_data.elms())){tech.ps_index=i; break;} if(tech.ps_index<0){tech.ps_index=ps.elms(); Swap(ps.New().data, ps_data);}}
  570. FREPD(shader, 2) // vs + ps
  571. {
  572. LPD3DXCONSTANTTABLE ct=null; D3DXGetShaderConstantTable(shader ? pass_desc.pPixelShaderFunction : pass_desc.pVertexShaderFunction, &ct);
  573. if(ct)
  574. {
  575. Mems<Shader9::Constant> &constants=(shader ? tech.ps_constants : tech.vs_constants);
  576. D3DXCONSTANTTABLE_DESC desc; ct->GetDesc(&desc);
  577. FREP(desc.Constants)
  578. {
  579. D3DXHANDLE constant=ct->GetConstant(null, i);
  580. D3DXCONSTANT_DESC const_desc[16];
  581. UINT count=Elms(const_desc);
  582. ct->GetConstantDesc(constant, const_desc, &count); if(count!=1)Exit("count!=1");
  583. switch(const_desc[0].RegisterSet)
  584. {
  585. case D3DXRS_SAMPLER:
  586. {
  587. Int index=(shader ? const_desc[0].RegisterIndex : D3DVERTEXTEXTURESAMPLER0+const_desc[0].RegisterIndex);
  588. if(!InRange(index, MAX_DX9_TEXTURES))Exit(S+"Texture index: "+index+", is too big");
  589. tech.textures.New().set(index, *ShaderImages(Str8Temp(const_desc[0].Name)));
  590. }break;
  591. case D3DXRS_FLOAT4:
  592. {
  593. if(ShaderParam *sp=params.find(Str8Temp(const_desc[0].Name)))
  594. {
  595. Int gpu_data_offset=0;
  596. AddRegisters(constants, *sp, ct, constant, const_desc[0], gpu_data_offset);
  597. }else
  598. {
  599. Exit(S+"Technique \""+tech_desc.Name+"\" uses \""+const_desc[0].Name+"\" parameter which was not found in the parameter list.");
  600. }
  601. }break;
  602. default: Exit(S+"Shader Param \""+const_desc[0].Name+"\"is of unsupported type.\nPlease change to float based."); break;
  603. }
  604. }
  605. RELEASE(ct);
  606. // join registers
  607. constants.sort(Compare);
  608. REPA(constants)if(i)
  609. {
  610. Shader9::Constant &p=constants[i-1],
  611. &n=constants[i ];
  612. if(p.start+p.count==n.start && (Vec4*)p.data+p.count==n.data && p.changed==n.changed) {p.count+=n.count; constants.remove(i, true);}
  613. }
  614. }
  615. }
  616. }
  617. {SyncLocker lock(D._lock); RELEASE(effect);}
  618. techs.sort(Compare);
  619. return ShaderSave(dest, params, images, vs, ps, techs);
  620. }
  621. #endif
  622. return false;
  623. }
  624. /******************************************************************************/
  625. static Bool ShaderCompile11(C Str &src, C Str &dest, C MemPtr<ShaderMacro> &macros, Str *messages)
  626. {
  627. #if DX11
  628. if(messages)messages->clear();
  629. File f; if(!f.readTry(src)){if(messages)messages->line()+="Failed to open file."; return false;}
  630. Mems<Byte> data; data.setNum(f.size()); if(!f.get(data.data(), f.size())){if(messages)messages->line()+="Failed to read from file."; return false;} f.del(); // release the file handle after reading
  631. ID3D10Blob *buffer=null, *error=null;
  632. Mems<D3D_SHADER_MACRO> d3d_macros; d3d_macros.setNum(macros.elms()+1); FREPA(macros){D3D_SHADER_MACRO &m=d3d_macros[i]; m.Name=macros[i].name; m.Definition=macros[i].definition;} Zero(d3d_macros.last());
  633. D3DCompile(data.data(), data.elms(), null, d3d_macros.data(), &Include11(src), null, "fx_5_0", FLAGS_DX11, 0, &buffer, &error); Error(error, messages);
  634. ID3DX11Effect *effect=null;
  635. if(buffer)
  636. {
  637. //SyncLocker lock(D._lock); lock not needed for DX11 'D3D'
  638. D3DX11CreateEffectFromMemory(buffer->GetBufferPointer(), buffer->GetBufferSize(), 0, D3D, &effect);
  639. }
  640. if(effect)
  641. {
  642. ShaderFile shader;
  643. Memc<ShaderBufferParams> buffers;
  644. Memc<ShaderImage*> images;
  645. Memc<ShaderVS11> vs;
  646. Memc<ShaderHS11> hs;
  647. Memc<ShaderDS11> ds;
  648. Memc<ShaderPS11> ps;
  649. Memc<Shader11> techs;
  650. D3DX11_EFFECT_DESC desc; effect->GetDesc(&desc);
  651. // build list of parameters
  652. FREP(desc.ConstantBuffers)if(ID3DX11EffectConstantBuffer *cb=effect->GetConstantBufferByIndex(i))
  653. {
  654. ID3D11Buffer *buffer=null; cb ->GetConstantBuffer(&buffer);
  655. D3D11_BUFFER_DESC bd ; buffer->GetDesc(&bd);
  656. D3DX11_EFFECT_VARIABLE_DESC desc ; cb ->GetDesc(&desc);
  657. RELEASE(buffer);
  658. // create Constant Buffer
  659. ShaderBuffers.lock();
  660. ShaderBuffer &buf =*ShaderBuffers(Str8Temp(desc.Name));
  661. ShaderBufferParams &buf_params=buffers.New(); buf_params.buffer=&buf; buf_params.index=((desc.Flags&D3DX11_EFFECT_VARIABLE_EXPLICIT_BIND_POINT) ? desc.ExplicitBindPoint : -1);
  662. if(!buf.is()) // not yet initialized
  663. {
  664. buf.create(bd.ByteWidth);
  665. cb->GetRawValue(buf.data, 0, buf.size()); buf.changed=true; // set default value
  666. if(buf_params.index>=0){SyncLocker lock(D._lock); buf.bind(buf_params.index);}
  667. }else
  668. {
  669. if(buf.size()!=bd.ByteWidth)Exit(S+"Constant Buffer \""+desc.Name+"\" already exists in constant buffer Map however with different size");
  670. buf.bindCheck(buf_params.index);
  671. }
  672. ShaderBuffers.unlock();
  673. // set all members
  674. D3DX11_EFFECT_TYPE_DESC type; cb->GetType()->GetDesc(&type);
  675. FREP(type.Members)
  676. {
  677. ID3DX11EffectVariable *member=cb->GetMemberByIndex(i);
  678. D3DX11_EFFECT_VARIABLE_DESC desc; member->GetDesc(&desc);
  679. D3DX11_EFFECT_TYPE_DESC type; member->GetType()->GetDesc(&type);
  680. ShaderParamName &sp=buf_params.params.New();
  681. if(sp.is())Exit(S+"Shader parameter \""+desc.Name+"\" listed more than once");else // if wasn't yet created
  682. {
  683. sp. name = desc.Name;
  684. sp._owns_data= false;
  685. sp._changed =&buf .changed;
  686. sp._data = buf .data; // not yet offsetted
  687. sp._elements = type.Elements;
  688. AddTranslation11(sp, member, desc, type);
  689. sp._gpu_data_size=type.UnpackedSize;
  690. //sp._constant_count= unused on DX10+
  691. if(sp._cpu_data_size!=type. PackedSize
  692. || sp._gpu_data_size!=type.UnpackedSize)Exit("Incorrect Shader Param size.\nPlease contact Developer.");
  693. if(sp._gpu_data_size+sp._full_translation[0].gpu_offset>buf.size())Exit("Shader Param does not fit in Constant Buffer.\nPlease contact Developer.");
  694. //if(SIZE(Vec4) +sp._full_translation[0].gpu_offset>buf.size())Exit("Shader Param does not fit in Constant Buffer.\nPlease contact Developer."); some functions assume that '_gpu_data_size' is at least as big as 'Vec4' to set values without checking for size, !! this is not needed and shouldn't be called because in DX10+ Shader Params are stored in Shader Buffers, and 'ShaderBuffer' already allocates padding for Vec4
  695. }
  696. }
  697. RELEASE(cb);
  698. }
  699. buffers.sort(Compare); // once we have all buffers for this file, sort them, so we can use binary search later while saving techniques when looking for buffer indexes
  700. // build list of textures/samplers
  701. FREP(desc.GlobalVariables)if(ID3DX11EffectVariable *var=effect->GetVariableByIndex(i))
  702. {
  703. D3DX11_EFFECT_VARIABLE_DESC desc; var->GetDesc(&desc);
  704. D3DX11_EFFECT_TYPE_DESC type; var->GetType()->GetDesc(&type);
  705. if(type.Type==D3D10_SVT_TEXTURE2D || type.Type==D3D10_SVT_TEXTURE3D || type.Type==D3D10_SVT_TEXTURECUBE || type.Type==D3D10_SVT_TEXTURE2DMS)
  706. images.add(ShaderImages(Str8Temp(desc.Name)));
  707. RELEASE(var);
  708. }
  709. images.sort(Compare); // once we have all images for this file, sort them, so we can use binary search later while saving techniques when looking for image indexes
  710. // build list of techniques
  711. FREP(desc.Techniques)if(ID3DX11EffectTechnique *tech_handle=effect->GetTechniqueByIndex(i))
  712. {
  713. D3DX11_TECHNIQUE_DESC tech_desc; tech_handle->GetDesc (&tech_desc); if(tech_desc.Passes!=1)Exit("Technique pass count!=1"); ID3DX11EffectPass *pass=tech_handle->GetPassByIndex(0);
  714. D3DX11_PASS_DESC pass_desc; pass ->GetDesc (&pass_desc);
  715. D3DX11_PASS_SHADER_DESC vs_desc; pass ->GetVertexShaderDesc(& vs_desc); D3DX11_EFFECT_SHADER_DESC vsd; Zero(vsd); if(vs_desc.pShaderVariable)vs_desc.pShaderVariable->GetShaderDesc(0, &vsd);
  716. D3DX11_PASS_SHADER_DESC hs_desc; pass ->GetHullShaderDesc (& hs_desc); D3DX11_EFFECT_SHADER_DESC hsd; Zero(hsd); if(hs_desc.pShaderVariable)hs_desc.pShaderVariable->GetShaderDesc(0, &hsd);
  717. D3DX11_PASS_SHADER_DESC ds_desc; pass ->GetDomainShaderDesc(& ds_desc); D3DX11_EFFECT_SHADER_DESC dsd; Zero(dsd); if(ds_desc.pShaderVariable)ds_desc.pShaderVariable->GetShaderDesc(0, &dsd);
  718. D3DX11_PASS_SHADER_DESC ps_desc; pass ->GetPixelShaderDesc (& ps_desc); D3DX11_EFFECT_SHADER_DESC psd; Zero(psd); if(ps_desc.pShaderVariable)ps_desc.pShaderVariable->GetShaderDesc(0, &psd);
  719. Shader11 &tech=techs.New(); tech.name=tech_desc.Name;
  720. // get shader data
  721. Mems<Byte> vs_data; vs_data.setNum(vsd.BytecodeLength).copyFrom(vsd.pBytecode);
  722. Mems<Byte> hs_data; hs_data.setNum(hsd.BytecodeLength).copyFrom(hsd.pBytecode);
  723. Mems<Byte> ds_data; ds_data.setNum(dsd.BytecodeLength).copyFrom(dsd.pBytecode);
  724. Mems<Byte> ps_data; ps_data.setNum(psd.BytecodeLength).copyFrom(psd.pBytecode);
  725. #if DEBUG && 0 // use this for generation of a basic Vertex Shader which can be used for Input Layout creation (see 'DX10_INPUT_LAYOUT' and 'VS_Code')
  726. Str t=S+"static Byte VS_Code["+vs_data.elms()+"]={";
  727. FREPA(vs_data){if(i)t+=','; t+=vs_data[i];}
  728. t+="};\n";
  729. ClipSet(t);
  730. Exit(t);
  731. #endif
  732. // store shaders
  733. if(vs_data.elms()){FREPA(vs)if(vs[i].data.elms()==vs_data.elms() && EqualMem(vs[i].data.data(), vs_data.data(), vs_data.elms())){tech.vs_index=i; break;} if(tech.vs_index<0){tech.vs_index=vs.elms(); Swap(vs.New().data, vs_data);}}
  734. if(hs_data.elms()){FREPA(hs)if(hs[i].data.elms()==hs_data.elms() && EqualMem(hs[i].data.data(), hs_data.data(), hs_data.elms())){tech.hs_index=i; break;} if(tech.hs_index<0){tech.hs_index=hs.elms(); Swap(hs.New().data, hs_data);}}
  735. if(ds_data.elms()){FREPA(ds)if(ds[i].data.elms()==ds_data.elms() && EqualMem(ds[i].data.data(), ds_data.data(), ds_data.elms())){tech.ds_index=i; break;} if(tech.ds_index<0){tech.ds_index=ds.elms(); Swap(ds.New().data, ds_data);}}
  736. if(ps_data.elms()){FREPA(ps)if(ps[i].data.elms()==ps_data.elms() && EqualMem(ps[i].data.data(), ps_data.data(), ps_data.elms())){tech.ps_index=i; break;} if(tech.ps_index<0){tech.ps_index=ps.elms(); Swap(ps.New().data, ps_data);}}
  737. FREPD(shader, 4) // vs, hs, ds, ps
  738. {
  739. Mems<Shader11::Buffer > & buffers=((shader==0) ? tech.vs_buffers : (shader==1) ? tech.hs_buffers : (shader==2) ? tech.ds_buffers : tech.ps_buffers );
  740. Mems<Shader11::Texture> &textures=((shader==0) ? tech.vs_textures : (shader==1) ? tech.hs_textures : (shader==2) ? tech.ds_textures : tech.ps_textures);
  741. D3DX11_EFFECT_SHADER_DESC &sd =((shader==0) ? vsd : (shader==1) ? hsd : (shader==2) ? dsd : psd );
  742. if(sd.pBytecode)
  743. {
  744. ID3D11ShaderReflection *reflection=null; D3DReflect(sd.pBytecode, sd.BytecodeLength, IID_ID3D11ShaderReflection, (Ptr*)&reflection); if(!reflection)Exit("Failed to get reflection");
  745. D3D11_SHADER_DESC desc; reflection->GetDesc(&desc);
  746. FREP(desc.BoundResources)
  747. {
  748. D3D11_SHADER_INPUT_BIND_DESC desc; reflection->GetResourceBindingDesc(i, &desc);
  749. switch(desc.Type)
  750. {
  751. case D3D10_SIT_CBUFFER: if(!InRange(desc.BindPoint, MAX_SHADER_BUFFERS))Exit(S+"Constant Buffer index: "+desc.BindPoint+", is too big"); buffers.New().set(desc.BindPoint, *ShaderBuffers(Str8Temp(desc.Name))); break;
  752. case D3D10_SIT_TEXTURE: if(!InRange(desc.BindPoint, MAX_TEXTURES ))Exit(S+"Texture index: " +desc.BindPoint+", is too big"); textures.New().set(desc.BindPoint, *ShaderImages (Str8Temp(desc.Name))); break;
  753. }
  754. }
  755. RELEASE(reflection);
  756. }
  757. }
  758. RELEASE(tech_handle);
  759. }
  760. {SyncLocker lock(D._lock); RELEASE(effect);}
  761. techs.sort(Compare);
  762. return ShaderSave(dest, buffers, images, vs, hs, ds, ps, techs);
  763. }
  764. #endif
  765. return false;
  766. }
  767. /******************************************************************************/
  768. #if GL && !GL_ES && WINDOWS
  769. static Str8 RemoveR (CChar8 *text) {return Replace(text, '\r', '\0');}
  770. static Str8 RemoveComments(CChar8 *text)
  771. {
  772. Str8 s; s.reserve(Length(text));
  773. if(text)for(Int in_comment=0; ; ) // 0=no, 1=in line "//", 2=in big "/* */"
  774. {
  775. Char8 c=*text++; if(!c)break;
  776. switch(in_comment)
  777. {
  778. default:
  779. {
  780. if(c=='/')
  781. {
  782. if(text[0]=='/'){in_comment=1; text++; break;} // don't process '/' again
  783. if(text[0]=='*'){in_comment=2; text++; break;} // don't process '*' again, important to treat /*/ not as closure
  784. }
  785. s+=c;
  786. }break;
  787. case 1: if(c=='\n' ){in_comment=0; s.line();} break;
  788. case 2: if(c=='*' && text[0]=='/'){in_comment=0; text++;} break; // don't process '*' again, important to treat /*..*/* not as new comment
  789. }
  790. }
  791. return s;
  792. }
  793. static Str8 GetToken(CChar8* &text)
  794. {
  795. Str8 s;
  796. if(text)for(;;)
  797. {
  798. Char8 c=*text;
  799. if(CharType(c)==CHART_CHAR){s+=c; text++;}else // append name
  800. if(!s.is() && c>32){text++; return c;}else // return operator
  801. if( s.is() || c>32 || c==0)break;else text++; // continue
  802. }
  803. return s;
  804. }
  805. static Str8 RemoveUnusedStructs(CChar8 *text)
  806. {
  807. Str8 s; s.reserve(Length(text));
  808. if(text)for(;;)
  809. {
  810. if(Starts(text, "struct", true, true))
  811. {
  812. CChar8 *token=text+6; // Length("struct") -> 6
  813. Str8 name =GetToken(token);
  814. if(name.is() && !Contains(token, name, true, true))
  815. {
  816. for(Int level=0; ; )
  817. {
  818. Char8 c=*token++; if(!c)break;
  819. if(c=='{') ++level;
  820. if(c=='}')if(--level<=0)
  821. {
  822. if(GetToken(token)==';'){text=token; goto next;}
  823. break;
  824. }
  825. }
  826. }
  827. }
  828. {
  829. Char8 c=*text++; if(!c)break;
  830. s+=c;
  831. }
  832. next:;
  833. }
  834. return s;
  835. }
  836. static Str8 RemoveSpaces(CChar8 *text)
  837. {
  838. Str8 s; s.reserve(Length(text));
  839. Bool possible_preproc=true, preproc=false;
  840. if(text && text[0])for(Char8 last=0;;)
  841. {
  842. if(text[0]==' '
  843. && (CharType(last)!=CHART_CHAR || CharType(text[1])!=CHART_CHAR)
  844. && (preproc ? last!=')' && text[1]!='(' : true) // don't remove spaces around brackets when in preprocessor mode "#define X(a) a" would turn into "#define X(a)a", same thing for "#define X (X+1)" would turn into "#define X(X+1)"
  845. && (last!='/' || text[1]!='*') // don't remove spaces around / * because this could trigger comment mode
  846. && (last!='*' || text[1]!='/') // don't remove spaces around * / because this could trigger comment mode
  847. )
  848. {
  849. text+=1;
  850. last =s.last();
  851. }else
  852. {
  853. last=*text++; if(!last)break;
  854. s+=last;
  855. if(last=='\n'){possible_preproc=true; preproc=false;}else
  856. if(last!=' ' && last!='\t' && last!='#')possible_preproc=false;else
  857. if(last=='#' && possible_preproc)preproc=true;
  858. }
  859. }
  860. return s;
  861. }
  862. static Str8 RemoveEmptyLines(CChar8 *text)
  863. {
  864. Str8 s; s.reserve(Length(text));
  865. if(text)for(Char8 last='\n'; ; )
  866. {
  867. Char8 c=*text++; if(!c)break;
  868. if(c=='\n' && (last=='\n' || !*text))continue;
  869. s+=c; last=c;
  870. }
  871. return s;
  872. }
  873. static Str8 Clean(C Str8 &text)
  874. {
  875. return RemoveEmptyLines(RemoveSpaces(RemoveUnusedStructs(RemoveComments(RemoveR(text)))));
  876. }
  877. /******************************************************************************/
  878. static struct Varyings
  879. {
  880. CChar8 *from, *to;
  881. }varyings[]=
  882. {
  883. // vertex shader
  884. {"gl_FrontColor" , "GL_Col" },
  885. {"gl_FrontSecondaryColor", "GL_Col1"},
  886. // pixel shader
  887. {"gl_Color" , "GL_Col" },
  888. {"gl_SecondaryColor", "GL_Col1"},
  889. // both
  890. {"gl_TexCoord[0]", "GL_Tex0"},
  891. {"gl_TexCoord[1]", "GL_Tex1"},
  892. {"gl_TexCoord[2]", "GL_Tex2"},
  893. {"gl_TexCoord[3]", "GL_Tex3"},
  894. {"gl_TexCoord[4]", "GL_Tex4"},
  895. {"gl_TexCoord[5]", "GL_Tex5"},
  896. {"gl_TexCoord[6]", "GL_Tex6"},
  897. {"gl_TexCoord[7]", "GL_Tex7"},
  898. {"gl_TexCoord[8]", "GL_Tex8"},
  899. };
  900. static Str8 CleanCGShader(CChar8 *shader)
  901. {
  902. Int length=Length(shader);
  903. Str8 cleaned; cleaned.reserve(length);
  904. FileText f; f.readMem(shader, length);
  905. for(Str8 line; !f.end(); )
  906. {
  907. f.getLine(line);
  908. if(line.is() && !Starts(line, "//") && !Starts(line, "#extension GL_NV_fragdepth") && line!="attribute ivec4 ATTR15;")
  909. {
  910. cleaned+=line;
  911. cleaned+='\n';
  912. }
  913. }
  914. Char8 temp[256], dest[256];
  915. // rename CG style samplers, example "//var sampler2DSHADOW ShdMap : : _TMP214 : -1 : 1"
  916. for(CChar8 *t=shader; t=TextPos(t, "//var sampler2DSHADOW ", true, true); )
  917. {
  918. t+=22;
  919. if(CChar8 *cg=TextPos(t, " : : "))
  920. {
  921. Int name_length=cg-t+1; if(name_length>=Elms(dest))Exit("name too long");
  922. Set(dest, t, name_length);
  923. if(t=_SkipWhiteChars(cg+6))
  924. {
  925. Int i=0; for(;;)
  926. {
  927. Char8 c=*t++;
  928. if(i>=Elms(temp)-1)Exit(S+"Uniform name too long"); // leave room for '\0'
  929. if(!c || c=='[' || c==',' || c==':' || c==';' || c=='=' || WhiteChar(c))break;
  930. temp[i++]=c;
  931. }
  932. if(i)
  933. {
  934. temp[i]='\0';
  935. cleaned=Replace(cleaned, temp, dest, true, true);
  936. }
  937. }
  938. }
  939. }
  940. // rename CG style uniforms "_name" to "name"
  941. for(CChar8 *t=shader; t=TextPos(t, "uniform ", true, true); )
  942. if(t=_SkipWhiteChars(TextPos(_SkipWhiteChars(t+8), ' ')))
  943. {
  944. Int i=0; for(;;)
  945. {
  946. Char8 c=*t++;
  947. if(i>=Elms(temp)-1)Exit(S+"Uniform name too long"); // leave room for '\0'
  948. if(!c || c=='[' || c==',' || c==':' || c==';' || c=='=' || WhiteChar(c))break;
  949. temp[i++]=c;
  950. }
  951. temp[i]='\0';
  952. if(temp[0]!='_')Exit(S+"Uniform \""+temp+"\" doesn't start with '_'");
  953. cleaned=Replace(cleaned, temp, temp+1, true, true);
  954. }
  955. // user clip plane, CG doesn't support 'gl_ClipDistance', so instead 'gl_BackSecondaryColor' is used, after CG compiles successfully, 'gl_BackSecondaryColor' is replaced with 'gl_ClipDistance'
  956. cleaned=Replace(cleaned, "gl_BackSecondaryColor.x", "gl_ClipDistance[0]", true, true); // replace dummy "gl_BackSecondaryColor" with "gl_ClipDistance[0]"
  957. // vtx.instance() is hardcoded as "uint _instance:ATTR15", because CG doesn't support "gl_InstanceID" or "SV_InstanceID" semantics
  958. cleaned=Replace(cleaned, "int(ATTR15.x)", "gl_InstanceID", true);
  959. // replace built-in varyings, and keep only those that are used
  960. REPA(varyings)if(Contains(cleaned, varyings[i].from))cleaned=S+"varying vec4 "+varyings[i].to+";\n"+Replace(cleaned, varyings[i].from, varyings[i].to); // "varying vec4 GL_Col;"
  961. return Clean(cleaned);
  962. }
  963. static Str StrInclude(FileText &f, C Str &parent)
  964. {
  965. Str out;
  966. for(; !f.end(); )
  967. {
  968. C Str &line=f.fullLine();
  969. if(Starts(line, "#include"))
  970. {
  971. Str file=StrInside(line, '"', '"', true, true);
  972. if(!FullPath(file))file=GetPath(parent).tailSlash(true)+file; file=NormalizePath(file);
  973. FileText f; if(!f.read(file))Exit(S+"Error opening file: \""+file+"\"");
  974. out+=StrInclude(f, file);
  975. }else
  976. {
  977. out+=line;
  978. }
  979. out+='\n';
  980. }
  981. return out;
  982. }
  983. static Str StrInclude(C Str &str, C Str &parent)
  984. {
  985. return StrInclude(FileText().writeMem().putText(str).rewind(), parent);
  986. }
  987. static struct FromTo
  988. {
  989. CChar8 *from, *to;
  990. }ee_glsl[]=
  991. {
  992. {"inline ", "" },
  993. {"in out" , "inout"},
  994. {"Bool" , "bool" },
  995. {"Int" , "int" },
  996. {"UInt" , "uint" },
  997. {"Flt" , "float"},
  998. {"VecI2", "ivec2"},
  999. {"VecI" , "ivec3"},
  1000. {"VecI4", "ivec4"},
  1001. {"Vec2" , "vec2" },
  1002. {"Vec" , "vec3" },
  1003. {"Vec4" , "vec4" },
  1004. {"Dot" , "dot"},
  1005. {"Cross" , "cross"},
  1006. {"Sign" , "sign"},
  1007. {"Abs" , "abs"},
  1008. {"Min" , "min"},
  1009. {"Max" , "max"},
  1010. {"Mid" , "clamp"},
  1011. {"Frac" , "fract"},
  1012. {"Round" , "round"},
  1013. {"Trunc" , "trunc"},
  1014. {"Floor" , "floor"},
  1015. {"Ceil" , "ceil"},
  1016. {"Sqrt" , "sqrt"},
  1017. {"Normalize", "normalize"},
  1018. {"Pow" , "pow"},
  1019. {"Sin" , "sin"},
  1020. {"Cos" , "cos"},
  1021. {"Lerp" , "mix"},
  1022. {"Length" , "length"},
  1023. {"Image" , "sampler2D"},
  1024. {"Image3D" , "sampler3D"},
  1025. {"ImageCube", "samplerCube"},
  1026. {"Tex" , "texture2D"},
  1027. {"Tex3D" , "texture3D"},
  1028. {"TexCube", "textureCube"},
  1029. {"O_vtx", "gl_Position"},
  1030. };
  1031. /*
  1032. "= MP Vec(..)" code is not supported on Mali (Samsung Galaxy S2)
  1033. LP, MP, HP always point to lowp, mediump, highp
  1034. https://github.com/mattdesl/lwjgl-basics/wiki/GLSL-Versions
  1035. GL GLSL
  1036. 2.0 110
  1037. 2.1 120
  1038. 3.0 130
  1039. 3.1 140
  1040. 3.2 150
  1041. 3.3 330
  1042. 4.0 400
  1043. 2.0ES 100 es
  1044. 3.0ES 300 es
  1045. */
  1046. static Str8 GLSLVSShader(Str8 code)
  1047. {
  1048. Bool texture2DLod=Contains(code, "texture2DLod", true, true),
  1049. texture3DLod=Contains(code, "texture3DLod", true, true);
  1050. return S
  1051. +"#ifdef GL_ES\n" // GLSL may not support "#if GL_ES" if GL_ES is not defined
  1052. + "#define LP lowp\n"
  1053. + "#define MP mediump\n"
  1054. + "#define HP highp\n"
  1055. + "precision HP float;\n"
  1056. + "precision HP int;\n"
  1057. +"#else\n"
  1058. + "#define LP\n"
  1059. + "#define MP\n"
  1060. + "#define HP\n"
  1061. +"#endif\n"
  1062. +"#if __VERSION__>=300\n" // this includes desktop GL3.3(330) and GLES3(300)
  1063. + (texture2DLod ? "#define texture2DLod textureLod\n" : "") // 'texture2DLod' is actually 'textureLod' on GL3
  1064. + (texture3DLod ? "#define texture3DLod textureLod\n" : "") // 'texture3DLod' is actually 'textureLod' on GL3
  1065. + "#define attribute in\n"
  1066. + "#define varying out\n"
  1067. +"#else\n"
  1068. + "#define gl_InstanceID 0\n" // instancing not supported on <GL3
  1069. +"#endif\n"
  1070. +code;
  1071. }
  1072. static Str8 GLSLPSShader(Str8 code, Bool force_hp)
  1073. {
  1074. // replace "shadow2DProj(..).x" with "shadow2DProj(..)"
  1075. for(Int offset=0; ; )
  1076. {
  1077. again:
  1078. Int i=TextPosI(code()+offset, "shadow2DProj(", true, true); if(i<0)break; offset+=i+12; // 12=Length("shadow2DProj")
  1079. for(Int level=0; offset<code.length(); offset++)switch(code[offset])
  1080. {
  1081. case '(': ++level; break;
  1082. case ')': if(!--level)
  1083. {
  1084. offset++;
  1085. if(code[offset]=='.')code.remove(offset, 2); // remove ".x"
  1086. goto again;
  1087. }break;
  1088. }
  1089. }
  1090. Bool dd=(Contains(code, "dFdx", true, true) // detect if uses 'ddx/ddy' functions
  1091. || Contains(code, "dFdy", true, true)),
  1092. mrt= Contains(code, "#extension GL_ARB_draw_buffers:require", true, true), // detect if uses MRT
  1093. rt0=(Contains(code, "gl_FragData[0]", true, true) || Contains(code, "gl_FragColor", true, true)),
  1094. rt1= Contains(code, "gl_FragData[1]", true, true),
  1095. rt2= Contains(code, "gl_FragData[2]", true, true),
  1096. rt3= Contains(code, "gl_FragData[3]", true, true),
  1097. sampler2DShadow=Contains(code, "sampler2DShadow", true, true),
  1098. sampler3D =Contains(code, "sampler3D" , true, true), texture2D =Contains(code, "texture2D" , true, true),
  1099. texture2DLod =Contains(code, "texture2DLod" , true, true),
  1100. texture3D =Contains(code, "texture3D" , true, true),
  1101. texture3DLod =Contains(code, "texture3DLod" , true, true),
  1102. textureCube =Contains(code, "textureCube" , true, true),
  1103. shadow2D =Contains(code, "shadow2D" , true, true),
  1104. shadow2DProj =Contains(code, "shadow2DProj" , true, true);
  1105. if(mrt)code=Replace(code, "#extension GL_ARB_draw_buffers:require\n", S, true, true); // CG may generate this after some other commands, however compiling on Radeon will fail, because it needs to be at start "syntax error: #extension must always be before any non-preprocessor tokens", so remove it and place at the start manually
  1106. if(rt0)code=Replace(Replace(code, "gl_FragData[0]", "RT0", true, true), "gl_FragColor", "RT0", true, true);
  1107. if(rt1)code= Replace(code, "gl_FragData[1]", "RT1", true, true);
  1108. if(rt2)code= Replace(code, "gl_FragData[2]", "RT2", true, true);
  1109. if(rt3)code= Replace(code, "gl_FragData[3]", "RT3", true, true);
  1110. return S // extensions must be listed before any non-preprocessor codes or compilation will fail on Samsung Galaxy S3 with error "Extension directive must occur before any non-preprocessor tokens"
  1111. + "#extension GL_EXT_shader_texture_lod:enable\n" // without this, pixel/fragment shaders using TexLod will not work on Mobile GLES2
  1112. + "#extension GL_EXT_shadow_samplers:enable\n" // without this, pixel/fragment shaders using shadows will not work on Mobile GLES2
  1113. +(dd ? "#extension GL_OES_standard_derivatives:enable\n" : "") // without this, pixel/fragment shaders using ddx/ddy will not work on Mobile GLES2
  1114. // set things after extensions
  1115. +"#ifdef GL_ES\n" // GLSL may not support "#if GL_ES" if GL_ES is not defined
  1116. + "#define LP lowp\n"
  1117. + "#define MP mediump\n"
  1118. + "#define HP highp\n"
  1119. + (force_hp ? "precision HP float;\n" : "precision MP float;\n")
  1120. + (force_hp ? "precision HP int;\n" : "precision MP int;\n")
  1121. + (force_hp ? "precision HP sampler2D;\n" : "") // may be needed for depth textures
  1122. + (sampler2DShadow ? "precision LP sampler2DShadow;\n" : "")
  1123. + (sampler3D ? "precision LP sampler3D;\n" : "")
  1124. + "#if __VERSION__<300\n"
  1125. + (texture2DLod ? "#define texture2DLod texture2DLodEXT\n" : "") // 'texture2DLod' is actually 'texture2DLodEXT' on GLES2
  1126. + (shadow2DProj ? "#define shadow2DProj shadow2DProjEXT\n" : "") // 'shadow2DProj' is actually 'shadow2DProjEXT' on GLES2
  1127. + "#endif\n"
  1128. +"#else\n"
  1129. + "#define LP\n"
  1130. + "#define MP\n"
  1131. + "#define HP\n"
  1132. +"#endif\n"
  1133. +"#if __VERSION__>=300\n" // this includes desktop GL3.3(330) and GLES3(300)
  1134. + (texture2D ? "#define texture2D texture\n" : "") // 'texture2D' is actually 'texture' on GL3
  1135. + (texture2DLod ? "#define texture2DLod textureLod\n" : "") // 'texture2DLod' is actually 'textureLod' on GL3
  1136. + (texture3D ? "#define texture3D texture\n" : "") // 'texture3D' is actually 'texture' on GL3
  1137. + (texture3DLod ? "#define texture3DLod textureLod\n" : "") // 'texture3DLod' is actually 'textureLod' on GL3
  1138. + (textureCube ? "#define textureCube texture\n" : "") // 'textureCube' is actually 'texture' on GL3
  1139. + (shadow2D ? "#define shadow2D texture\n" : "") // 'shadow2D' is actually 'texture' on GL3
  1140. + (shadow2DProj ? "#define shadow2DProj textureProj\n" : "") // 'shadow2DProj' is actually 'textureProj' on GL3
  1141. + (rt0 ? "layout(location=0) out HP vec4 RT0;\n" : "")
  1142. + (rt1 ? "layout(location=1) out HP vec4 RT1;\n" : "")
  1143. + (rt2 ? "layout(location=2) out HP vec4 RT2;\n" : "")
  1144. + (rt3 ? "layout(location=3) out HP vec4 RT3;\n" : "")
  1145. + "#define varying in\n"
  1146. +"#else\n"
  1147. + (rt0 ? "#define RT0 gl_FragData[0]\n" : "")
  1148. + (rt1 ? "#define RT1 gl_FragData[1]\n" : "")
  1149. + (rt2 ? "#define RT2 gl_FragData[2]\n" : "")
  1150. + (rt3 ? "#define RT3 gl_FragData[3]\n" : "")
  1151. + "#define gl_InstanceID 0\n" // instancing not supported on <GL3
  1152. +"#endif\n"
  1153. +code;
  1154. }
  1155. static Str8 GetVarName(C Str8 &text, Int offset)
  1156. {
  1157. Str8 name;
  1158. for(Int i=offset; i<text.length(); i++)
  1159. {
  1160. Char8 c=text[i]; if(!c || c==',' || c==';' || c=='[' || c==' ' || c=='}')break; // "variable;", "var1, var2;", "var[100];", ..
  1161. name+=c;
  1162. }
  1163. return name;
  1164. }
  1165. static void SpecifyCGPrecisionModifiers(Str8 &vs_code, Str8 &ps_code, Bool vs_hp, Bool ps_hp) // OpenGL ES will fail if vertex and pixel shaders both use the same uniforms but with different precision modifiers, that's why we need to make sure that if same uniform or class is used between shaders then they have the same precision specified
  1166. {
  1167. Bool max_hp=(vs_hp || ps_hp); // maximum precision of shaders
  1168. if(vs_hp!=ps_hp) // shaders operate on different precisions
  1169. FREPD(s, 2) // shader (0=vertex, 1=pixel)
  1170. {
  1171. Str8 &code =(s ? ps_code : vs_code), // current code
  1172. &code2=(s ? vs_code : ps_code); // other code
  1173. Bool hp =(s ? ps_hp : vs_hp ), // current precision
  1174. hp2 =(s ? vs_hp : ps_hp ); // other precision
  1175. for(Int uniform_index=0; ; uniform_index++)
  1176. {
  1177. Int uniform_pos =TextPosIN(code, "uniform", uniform_index, true, true); if(uniform_pos<0)break; // find all "uniform" occurences (like "uniform float Var", "uniform MaterialClass Material")
  1178. Int uniform_type=uniform_pos+8; // Length("uniform ")->8
  1179. if(!Starts(code()+uniform_type, "HP" , true, true)
  1180. && !Starts(code()+uniform_type, "MP" , true, true)
  1181. && !Starts(code()+uniform_type, "LP" , true, true) // if precision was not yet specified
  1182. && !Starts(code()+uniform_type, "sampler1D", true, true)
  1183. && !Starts(code()+uniform_type, "sampler2D", true, true)
  1184. && !Starts(code()+uniform_type, "sampler3D", true, true)) // not a sampler
  1185. {
  1186. Int uniform_name=TextPosI (code()+uniform_type, ' '); if(uniform_name<0)continue; uniform_name+=1+uniform_type; // space + type offset
  1187. Str8 var_name=GetVarName(code, uniform_name);
  1188. if(Starts(code()+uniform_type, "float", true, true)
  1189. || Starts(code()+uniform_type, "vec2" , true, true)
  1190. || Starts(code()+uniform_type, "vec3" , true, true)
  1191. || Starts(code()+uniform_type, "vec4" , true, true)) // basic type
  1192. {
  1193. Str8 var_def; for(Int i=uniform_pos; i<uniform_name+var_name.length(); i++)var_def+=code[i];
  1194. Int code2_var_def_pos=TextPosI(code2, var_def, true, true); // find "uniform type name" string in other shader
  1195. if( code2_var_def_pos>=0) // if other shader also uses this variable
  1196. {
  1197. code .insert(uniform_type , max_hp ? "HP " : "MP "); // add precision modifier "uniform precision type name"
  1198. code2.insert(code2_var_def_pos+(uniform_type-uniform_pos), max_hp ? "HP " : "MP "); // add precision modifier "uniform precision type name"
  1199. }
  1200. }else
  1201. {
  1202. Str8 type_name=GetVarName(code, uniform_type), // struct, for example "MaterialClass"
  1203. type_def =S8+"struct "+type_name;
  1204. Int code2_struct_pos=TextPosI(code2, type_def, true, true); // find "struct MaterialClass" in other shader
  1205. if( code2_struct_pos>=0) // if other shader also uses this class
  1206. {
  1207. Int code2_struct_end=TextPosI(code2()+code2_struct_pos, '}'); if(code2_struct_end<0)continue; code2_struct_end+=code2_struct_pos;
  1208. Str8 struct_def; for(Int i=code2_struct_pos; i<=code2_struct_end; i++)struct_def+=code2[i]; // 'struct_def' now contains "struct MaterialClass{..}"
  1209. Int code_struct_pos=TextPosI(code, struct_def, true, true); if(code_struct_pos<0)continue; // proceed only if first code has exact same struct definition
  1210. Bool changed=false;
  1211. for(Int member_start=0; member_start<struct_def.length(); member_start++)
  1212. if(Starts(struct_def()+member_start, "\nfloat", true, true)
  1213. || Starts(struct_def()+member_start, "\nvec2" , true, true)
  1214. || Starts(struct_def()+member_start, "\nvec3" , true, true)
  1215. || Starts(struct_def()+member_start, "\nvec4" , true, true)) // basic type (include '\n' character to skip those with specified precision)
  1216. {
  1217. Int member_name= TextPosI (struct_def()+member_start, ' '); if(member_name<0)continue; member_name+=1+member_start; // space + start offset
  1218. Str8 var_name=S8+'.'+GetVarName(struct_def, member_name); // ".member"
  1219. Bool used =Contains(code , var_name, true, true), // if used in code
  1220. used2=Contains(code2, var_name, true, true); // if used in other code
  1221. Bool var_hp=((used && used2) ? (hp || hp2) // used by both shaders
  1222. : used ? hp // used by first
  1223. : used2 ? hp2 // used by second
  1224. : true); // used by none
  1225. struct_def.insert(member_start+1, var_hp ? "HP " : "MP "); // add precision modifier "\nprecision type name"
  1226. changed=true;
  1227. }
  1228. if(changed)
  1229. {
  1230. code .remove(code_struct_pos , code2_struct_end-code2_struct_pos+1).insert(code_struct_pos , struct_def);
  1231. code2.remove(code2_struct_pos, code2_struct_end-code2_struct_pos+1).insert(code2_struct_pos, struct_def);
  1232. }
  1233. }
  1234. }
  1235. }
  1236. }
  1237. }
  1238. }
  1239. T1(TYPE) static Int StoreShader(C Str8 &code, Memc<TYPE> &shaders, File &src, File &temp)
  1240. {
  1241. src.reset().putStr(code).pos(0);
  1242. if(!Compress(src, temp.reset(), COMPRESS_GL, COMPRESS_GL_LEVEL, COMPRESS_GL_MT))Exit("Can't compress shader");
  1243. REPA(shaders)
  1244. {
  1245. Mems<Byte> &shader_data=shaders[i].data;
  1246. if(shader_data.elms()==temp.size())
  1247. {
  1248. File data; data.readMem(shader_data.data(), shader_data.elms());
  1249. temp.pos(0); if(temp.equal(data))return i;
  1250. }
  1251. }
  1252. Mems<Byte> &data=shaders.New().data;
  1253. temp.pos(0); temp.get(data.setNum(temp.size()).data(), temp.size());
  1254. return shaders.elms()-1;
  1255. }
  1256. struct ParamMember
  1257. {
  1258. Int gpu_offset;
  1259. Str8 name;
  1260. ShaderParam *sp;
  1261. void set(C Str8 &name, ShaderParam &sp, Int gpu_offset) {T.name=name; T.sp=&sp; T.gpu_offset=gpu_offset;}
  1262. ParamMember() {sp=null; gpu_offset=0;}
  1263. };
  1264. static C ParamMember* Find(C Memc<ParamMember> &pm, CChar8 *name)
  1265. {
  1266. REPA(pm)if(Equal(pm[i].name, name, true))return &pm[i];
  1267. return null;
  1268. }
  1269. static Bool FindNameReplacement(Char8 (&temp)[1024], CChar8 *glsl_name, CChar8 *code)
  1270. {
  1271. Set(temp, " : : _"); Append(temp, glsl_name);
  1272. if(CChar8 *t=TextPos(code, temp, true, true))for(CChar8 *name=t-1; name>code; name--)if(*name==' ')
  1273. {
  1274. Set(temp, name+1, t-name);
  1275. return true;
  1276. }
  1277. return false;
  1278. }
  1279. #include <Cg/cg.h>
  1280. #include <Cg/cgGL.h>
  1281. static void AddTranslationGL(ShaderParam &sp, CGparameter par, Memc<ParamMember> &pm)
  1282. {
  1283. CChar8 *pname=cgGetParameterName(par);
  1284. if(cgGetArraySize(par, 0)<=1) // array size
  1285. {
  1286. CGparameterclass pclass=cgGetParameterClass (par);
  1287. CGtype type =cgGetParameterType (par);
  1288. #if 0
  1289. Int rsize =cgGetParameterResourceSize (par);
  1290. CChar8 *sem =cgGetParameterSemantic (par);
  1291. CGresource bres =cgGetParameterBaseResource (par);
  1292. CGresource res =cgGetParameterResource (par);
  1293. CChar8 *rname =cgGetParameterResourceName (par);
  1294. Int resi =cgGetParameterResourceIndex(par);
  1295. CGtype rtype =cgGetParameterResourceType (par);
  1296. CGenum var =cgGetParameterVariability (par);
  1297. Int bi =cgGetParameterBufferIndex (par);
  1298. Int bo =cgGetParameterBufferOffset (par);
  1299. Int pi =cgGetParameterIndex (par);
  1300. #endif
  1301. if(pclass==CG_PARAMETERCLASS_SCALAR || pclass==CG_PARAMETERCLASS_VECTOR)
  1302. {
  1303. pm.New().set(pname, sp, sp._gpu_data_size);
  1304. if(type==CG_FLOAT || type==CG_HALF || type==CG_FIXED ){sp._full_translation.New().set(sp._cpu_data_size, sp._gpu_data_size, SIZE(Flt )); sp._cpu_data_size+=SIZE(Flt ); sp._gpu_data_size+=SIZE(Flt );}else
  1305. if(type==CG_FLOAT2 || type==CG_HALF2 || type==CG_FIXED2){sp._full_translation.New().set(sp._cpu_data_size, sp._gpu_data_size, SIZE(Vec2)); sp._cpu_data_size+=SIZE(Vec2); sp._gpu_data_size+=SIZE(Vec2);}else
  1306. if(type==CG_FLOAT3 || type==CG_HALF3 || type==CG_FIXED3){sp._full_translation.New().set(sp._cpu_data_size, sp._gpu_data_size, SIZE(Vec )); sp._cpu_data_size+=SIZE(Vec ); sp._gpu_data_size+=SIZE(Vec );}else
  1307. if(type==CG_FLOAT4 || type==CG_HALF4 || type==CG_FIXED4){sp._full_translation.New().set(sp._cpu_data_size, sp._gpu_data_size, SIZE(Vec4)); sp._cpu_data_size+=SIZE(Vec4); sp._gpu_data_size+=SIZE(Vec4);}else
  1308. Exit(S+"Unhandled Shader Parameter Type for \""+pname+'"');
  1309. }else
  1310. if(pclass==CG_PARAMETERCLASS_MATRIX)
  1311. {
  1312. pm.New().set(pname, sp, sp._gpu_data_size);
  1313. Int rows =cgGetParameterRows (par),
  1314. columns=cgGetParameterColumns(par);
  1315. FREPD(y, columns)
  1316. FREPD(x, rows )sp._full_translation.New().set(sp._cpu_data_size+SIZE(Flt)*(y+x*columns), sp._gpu_data_size+SIZE(Flt)*(x+y*rows), SIZE(Flt));
  1317. sp._cpu_data_size+=SIZE(Flt)*rows*columns;
  1318. sp._gpu_data_size+=SIZE(Flt)*rows*columns;
  1319. }else
  1320. if(pclass==CG_PARAMETERCLASS_STRUCT)
  1321. {
  1322. for(CGparameter member=cgGetFirstStructParameter(par); member; member=cgGetNextParameter(member))AddTranslationGL(sp, member, pm);
  1323. }
  1324. }else
  1325. {
  1326. FREP(cgGetArraySize(par, 0))
  1327. {
  1328. CGparameter elm=cgGetArrayParameter(par, i);
  1329. AddTranslationGL(sp, elm, pm);
  1330. }
  1331. }
  1332. }
  1333. struct CGCONTEXT
  1334. {
  1335. CGcontext _;
  1336. operator CGcontext() {return _;}
  1337. ~CGCONTEXT() {cgDestroyContext(_);}
  1338. CGCONTEXT()
  1339. {
  1340. if(_=cgCreateContext())
  1341. {
  1342. #ifdef CG_BEHAVIOR_CURRENT
  1343. cgSetContextBehavior(_, CG_BEHAVIOR_CURRENT);
  1344. #endif
  1345. //cgSetAutoCompile(_, CG_COMPILE_IMMEDIATE);
  1346. cgGLRegisterStates(_);
  1347. }
  1348. }
  1349. Str error()
  1350. {
  1351. CGerror error;
  1352. CChar8 *string=cgGetLastErrorString(&error);
  1353. switch(error)
  1354. {
  1355. case CG_NO_ERROR: break;
  1356. //case CG_INVALID_PARAMETER_ERROR:
  1357. //case CG_NON_NUMERIC_PARAMETER_ERROR: break;
  1358. //case CG_COMPILER_ERROR: return S+string+'\n'+cgGetLastListing(T); break;
  1359. default:
  1360. {
  1361. Str s=string; s.line()+=cgGetLastListing(T);
  1362. if(string=(CChar8*)glGetString(GL_PROGRAM_ERROR_STRING_ARB))
  1363. {
  1364. int loc; glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &loc);
  1365. s.line()+=string;
  1366. }
  1367. return s;
  1368. }break;
  1369. }
  1370. return S;
  1371. }
  1372. };
  1373. struct CGEFFECT
  1374. {
  1375. CGeffect _;
  1376. operator CGeffect() {return _;}
  1377. ~CGEFFECT() {cgDestroyEffect(_);}
  1378. explicit CGEFFECT(CGeffect fx) {_=fx;}
  1379. };
  1380. #endif
  1381. static Bool ShaderCompileGL(Str name, C Str &dest, C MemPtr<ShaderMacro> &macros, Str *messages, C MemPtr<ShaderGLSL> &stg)
  1382. {
  1383. #if GL && !GL_ES && WINDOWS
  1384. Memc<Str8 > args_str; FREPA( macros)args_str.add(S+"-D"+macros[i].name+'='+macros[i].definition);
  1385. Memc<CChar8*> args ; FREPA(args_str)args .add(args_str[i]); args.add("-O3"); args.add((CChar8*)null);
  1386. name=NormalizePath(name); if(!FExistSystem(name))name=DataPath()+name;
  1387. Bool ok=false;
  1388. Map <Str8, ShaderParam> params(CompareCS);
  1389. Memc<ShaderImage*> images;
  1390. Memc<ShaderVSGL> vs;
  1391. Memc<ShaderPSGL> ps;
  1392. Memc<ShaderGL> techs;
  1393. CGCONTEXT context; if(context)
  1394. {
  1395. CGEFFECT effect(cgCreateEffectFromFile(context, UnixPathUTF8(name), args.data())); if(effect)
  1396. {
  1397. Memc<ParamMember> pm;
  1398. // add parameters
  1399. for(CGparameter par=cgGetFirstEffectParameter(effect); par; par=cgGetNextParameter(par))
  1400. {
  1401. CChar8 *pname =cgGetParameterName (par);
  1402. CGparameterclass pclass=cgGetParameterClass (par);
  1403. //Int rsize =cgGetParameterResourceSize(par);
  1404. if(pclass==CG_PARAMETERCLASS_SAMPLER)images.add(ShaderImages(Str8Temp(pname)));else
  1405. if(pclass!=CG_PARAMETERCLASS_OBJECT )
  1406. {
  1407. ShaderParam &sp=*params(Str8Temp(pname));
  1408. if(sp.is())Exit(S+"Shader parameter \""+pname+"\" listed more than once");else // if wasn't yet created
  1409. {
  1410. sp._owns_data=true;
  1411. sp._elements =cgGetArraySize(par, 0);
  1412. AddTranslationGL(sp, par, pm);
  1413. sp.optimize(); // required for setting default value
  1414. MAX(sp._gpu_data_size, SIZEI(Vec4)); // in OpenGL, parameters must be stored without padding
  1415. //if (sp._gpu_data_size!=rsize )Exit("Incorrect Shader Param Size.\nPlease contact Developer.");
  1416. if (sp._gpu_data_size<SIZE(Vec4))Exit("Shader Param Size < SIZE(Vec4)"); // some functions assume that '_gpu_data_size' is at least as big as 'Vec4' to set values without checking for size
  1417. // alloc data
  1418. AllocZero(sp._data, sp._gpu_data_size);
  1419. *Alloc (sp._changed)=true;
  1420. sp._constant_count=sp.fullConstantCount();
  1421. // set default value
  1422. Flt temp[4*1024]; if(Int elms=cgGetParameterDefaultValuefc(par, Elms(temp), temp))sp.set(Ptr(temp), elms*SIZE(Flt));
  1423. }
  1424. }
  1425. }
  1426. images.sort(Compare); // once we have all images for this file, sort them, so we can use binary search later while saving techniques when looking for image indexes
  1427. Str8 vs_code, ps_code, glsl_params;
  1428. File src, temp; src.writeMem(); temp.writeMem();
  1429. // techniques
  1430. Int tech_num=0; for(CGtechnique technique=cgGetFirstTechnique(effect); technique; technique=cgGetNextTechnique(technique), tech_num++); // get number of all techniques
  1431. Int t =1; for(CGtechnique technique=cgGetFirstTechnique(effect); technique; technique=cgGetNextTechnique(technique), t++ )
  1432. {
  1433. CChar8 *tech_name=cgGetTechniqueName(technique);
  1434. ShaderGL &tech=techs.New(); tech.name=tech_name;
  1435. #if DEBUG
  1436. LogN(S+"Processing tech \""+tech_name+"\" "+t+'/'+tech_num);
  1437. #endif
  1438. // try to find GLSL replacement
  1439. Bool cg=true;
  1440. REPA(stg)if(Equal(tech.name, stg[i].tech_name, true))
  1441. {
  1442. C ShaderGLSL &st=stg[i];
  1443. Str file; FileText f; if(f.read(name))for(; !f.end(); )file+=f.getLine()+'\n';
  1444. file =StrInside(file, S+"@GROUP \""+st.group_name+'"', "@GROUP_END" , true, true); if(!file .is())Exit(S+"@GROUP \""+st.group_name+"\" @GROUP_END not defined");
  1445. Str shared=StrInside(file, "@SHARED" , "@SHARED_END", true, true); if(!shared.is())Exit( "@SHARED @SHARED_END not defined" ); shared= StrInclude(shared, name);
  1446. Str vs =StrInside(file, "@VS" , "@VS_END" , true, true); if(!vs .is())Exit( "@VS @VS_END not defined" ); vs =shared+StrInclude(vs , name);
  1447. Str ps =StrInside(file, "@PS" , "@PS_END" , true, true); if(!ps .is())Exit( "@PS @PS_END not defined" ); ps =shared+StrInclude(ps , name);
  1448. vs=Clean(vs);
  1449. ps=Clean(ps);
  1450. REPA(ee_glsl)
  1451. {
  1452. vs=Replace(vs, ee_glsl[i].from, ee_glsl[i].to, true, true);
  1453. ps=Replace(ps, ee_glsl[i].from, ee_glsl[i].to, true, true);
  1454. }
  1455. glsl_params.clear(); FREPA(st.params)glsl_params+=S+"#define "+st.params[i].name+' '+st.params[i].definition+'\n';
  1456. cg=false;
  1457. vs_code=GLSLVSShader(glsl_params+vs);
  1458. ps_code=GLSLPSShader(glsl_params+ps, false); // default hand written GLSL shaders to low precision
  1459. break;
  1460. }
  1461. CChar8 *vs_cg_code=null, *ps_cg_code=null;
  1462. if(cg) // if haven't found GLSL replacement, then use CG version
  1463. {
  1464. CGpass pass =cgGetFirstPass (technique);
  1465. CGprogram cg_vs=cgGetPassProgram(pass, CG_VERTEX_DOMAIN );
  1466. CGprogram cg_ps=cgGetPassProgram(pass, CG_FRAGMENT_DOMAIN);
  1467. vs_cg_code=cgGetProgramString(cg_vs, CG_COMPILED_PROGRAM); if(!Is(vs_cg_code)){if(messages)messages->line()+=S+"Empty Vertex Shader Code in Technique \""+tech_name+"\""+context.error(); return false;}
  1468. ps_cg_code=cgGetProgramString(cg_ps, CG_COMPILED_PROGRAM); if(!Is(ps_cg_code)){if(messages)messages->line()+=S+"Empty Pixel Shader Code in Technique \"" +tech_name+"\""+context.error(); return false;}
  1469. Bool ps_hp=true; // default all CG shaders to high precision, alternatively use (cgGetNamedTechniqueAnnotation(technique, "ForceHP")!=null;
  1470. vs_code=GLSLVSShader(CleanCGShader(vs_cg_code));
  1471. ps_code=GLSLPSShader(CleanCGShader(ps_cg_code), ps_hp);
  1472. // specify precision modifiers
  1473. SpecifyCGPrecisionModifiers(vs_code, ps_code, true, ps_hp);
  1474. }
  1475. #if DEBUG
  1476. if(SHOW_GLSL_SRC)LogN(S+"// VERTEX SHADER\n\n"+vs_code+"\n\n// PIXEL SHADER\n\n"+ps_code);
  1477. #endif
  1478. // get shader data
  1479. tech.vs_index=StoreShader(vs_code, vs, src, temp);
  1480. tech.ps_index=StoreShader(ps_code, ps, src, temp);
  1481. // get GLSL->ShaderParam names
  1482. Str glsl_messages;
  1483. tech.compile(vs, ps, &glsl_messages); // compilation is required in order to get list of used parameters and their corresponding names and register address, don't clean the shader codes because they'll be needed for saving
  1484. if(!tech.prog)Exit(S+"Error compiling GLSL program:\n"+glsl_messages);
  1485. Int program_params=0; glGetProgramiv(tech.prog, GL_ACTIVE_UNIFORMS, &program_params);
  1486. FREP(program_params)
  1487. {
  1488. Char8 glsl_name[1024], temp_name[1024]; glsl_name[0]=0;
  1489. Int size=0;
  1490. GLenum type;
  1491. glGetActiveUniform(tech.prog, i, Elms(glsl_name), null, &size, &type, glsl_name);
  1492. Bool ok=false;
  1493. if(type==GL_SAMPLER_2D || type==GL_SAMPLER_3D || type==GL_SAMPLER_CUBE || type==GL_SAMPLER_2D_SHADOW) // Image
  1494. {
  1495. REPA(images)if(Equal(ShaderImages.dataInMapToKey(*images[i]), glsl_name, true))
  1496. {
  1497. //tech.glsl_images.add(images[i]);
  1498. ok=true;
  1499. break;
  1500. }
  1501. }else // ShaderParam
  1502. {
  1503. C ParamMember *p=Find(pm, glsl_name);
  1504. if(!p)
  1505. {
  1506. if(cg)
  1507. {
  1508. if(FindNameReplacement(temp_name, glsl_name, vs_cg_code)
  1509. || FindNameReplacement(temp_name, glsl_name, ps_cg_code))p=Find(pm, temp_name);
  1510. }else
  1511. if(Ends(glsl_name, "[0]"))
  1512. {
  1513. Set(temp_name, glsl_name, Length(glsl_name)-2);
  1514. p=Find(pm, temp_name);
  1515. }
  1516. }
  1517. if(p)
  1518. {
  1519. tech.glsl_params.New().set(p->gpu_offset, *p->sp, Equal(glsl_name, ShaderParams.dataInMapToKey(*p->sp), true) ? null : glsl_name); // if 'glsl_name' is exactly the same as ShaderParam name, then skip it so we don't have to save it. in other cases we need to store the 'glsl_name' because it can contain "obj.member" things, which we can't detect
  1520. ok=true;
  1521. }
  1522. }
  1523. if(!ok)
  1524. {
  1525. #if DEBUG
  1526. Log(vs_code);
  1527. Log(ps_code);
  1528. #endif
  1529. Exit(S+"GLSL Parameter \""+glsl_name+"\" not found");
  1530. }
  1531. }
  1532. // free
  1533. if(tech.prog){SyncLocker locker(D._lock); glDeleteProgram(tech.prog); tech.prog=0;} // clear while in lock
  1534. }
  1535. ok=true;
  1536. }else if(messages)messages->line()+=S+"Can't create CG effect: "+context.error();
  1537. }else if(messages)messages->line()+="Can't create CG context";
  1538. if(ok)
  1539. {
  1540. // sort any verify
  1541. techs.sort(Compare);
  1542. REPA(stg)if(!techs.binaryHas(stg[i].tech_name, Compare))Exit(S+"Shader doesn't have "+stg[i].tech_name);
  1543. // save
  1544. return ShaderSave(dest, params, images, vs, ps, techs);
  1545. }
  1546. #endif
  1547. return false;
  1548. }
  1549. /******************************************************************************/
  1550. Bool ShaderCompileTry(C Str &src, C Str &dest, SHADER_MODEL model, C MemPtr<ShaderMacro> &macros, C MemPtr<ShaderGLSL> &stg, Str *messages)
  1551. {
  1552. if(model==SM_UNKNOWN)return false;
  1553. Memc<ShaderMacro> temp; temp=macros;
  1554. switch(model)
  1555. {
  1556. case SM_UNKNOWN: return false;
  1557. case SM_GL_ES_2:
  1558. case SM_GL_ES_3:
  1559. case SM_GL : temp.New().set("MODEL", "SM_GL"); break;
  1560. case SM_3 : temp.New().set("MODEL", "SM_3" ); break;
  1561. default : temp.New().set("MODEL", "SM_4" ); break;
  1562. }
  1563. if(model>=SM_GL_ES_2 && model<=SM_GL)return ShaderCompileGL(src, dest, temp, messages, stg);
  1564. if( model==SM_3 )return ShaderCompile9 (src, dest, temp, messages);
  1565. if( model>=SM_4 )return ShaderCompile11(src, dest, temp, messages);
  1566. return false;
  1567. }
  1568. /******************************************************************************/
  1569. void ShaderCompile(C Str &src, C Str &dest, SHADER_MODEL model, C MemPtr<ShaderMacro> &macros, C MemPtr<ShaderGLSL> &stg)
  1570. {
  1571. Str messages;
  1572. if(!ShaderCompileTry(src, dest, model, macros, stg, &messages))
  1573. {
  1574. #if !WINDOWS
  1575. if(model==SM_3)Exit("Can't compile DX9 Shaders when not using Windows engine version");
  1576. #endif
  1577. #if !DX11
  1578. if(model>=SM_4)Exit("Can't compile DX10+ Shaders when not using DX10+ engine version");
  1579. #endif
  1580. #if DX9 || DX11
  1581. if(model>=SM_GL_ES_2 && model<=SM_GL)Exit("Can't compile OpenGL Shaders when not using OpenGL engine version");
  1582. #endif
  1583. Exit(S+"Error compiling shader\n\""+src+"\"\nto file\n\""+dest+"\"."+(messages.is() ? S+"\n\nCompilation Messages:\n"+messages : S));
  1584. }
  1585. }
  1586. Bool ShaderCompileTry(Str src, Str dest, SHADER_MODEL model, C MemPtr<ShaderMacro> &macros, Str *messages) {return ShaderCompileTry(src, dest, model, macros, null, messages);}
  1587. void ShaderCompile (Str src, Str dest, SHADER_MODEL model, C MemPtr<ShaderMacro> &macros ) { ShaderCompile (src, dest, model, macros, null );}
  1588. /******************************************************************************/
  1589. // IO
  1590. /******************************************************************************/
  1591. #if WINDOWS_OLD
  1592. Bool Shader9::save(File &f, C Map<Str8, ShaderParam> &params, C Memc<ShaderImage*> &images)C
  1593. {
  1594. // name
  1595. f.putStr(name).putMulti(vs_index, ps_index);
  1596. // textures
  1597. f.cmpUIntV(textures.elms()); FREPA(textures)f<<TextureIndex9(textures[i].index, GetIndex(images, textures[i].image));
  1598. // constants
  1599. f.cmpUIntV(vs_constants.elms());
  1600. FREPA( vs_constants)
  1601. {
  1602. C Constant &c=vs_constants[i]; f<<ConstantIndex9(c.start, c.count, UIntPtr(c.data)-UIntPtr(c.sp->_data), GetIndex(params, c.sp));
  1603. }
  1604. f.cmpUIntV(ps_constants.elms());
  1605. FREPA( ps_constants)
  1606. {
  1607. C Constant &c=ps_constants[i]; f<<ConstantIndex9(c.start, c.count, UIntPtr(c.data)-UIntPtr(c.sp->_data), GetIndex(params, c.sp));
  1608. }
  1609. return f.ok();
  1610. }
  1611. #if DX9
  1612. Bool Shader9::load(File &f, C MemtN<ShaderParam*, 256> &params, C MemtN<ShaderImage*, 256> &images)
  1613. {
  1614. // name
  1615. f.getStr(name).getMulti(vs_index, ps_index);
  1616. // textures
  1617. textures.setNum(f.decUIntV()); FREPA(textures)
  1618. {
  1619. Texture &t=textures[i]; TextureIndex9 ci; f>>ci; t.index=ci.bind_index; if(!InRange(t.index, MAX_DX9_TEXTURES))Exit(S+"Texture index: "+t.index+", is too big"); t.image=Get(ci.src_index, images);
  1620. }
  1621. // constants
  1622. vs_constants.setNum(f.decUIntV()); FREPA(vs_constants)
  1623. {
  1624. Constant &c=vs_constants[i]; ConstantIndex9 ci; f>>ci;
  1625. c.sp =Get(ci.src_index, params); c.changed=c.sp->_changed;
  1626. c.start=ci.start;
  1627. c.count=ci.count;
  1628. c.data =c.sp->_data+ci.offset;
  1629. c.final_count=((c.count<c.sp->fullConstantCount()) ? &c.count : &c.sp->_constant_count); // if this constant is not using full 'ShaderParam' size then keep its own count, otherwise point to the 'ShaderParam' count in case it can get decreased later (for example 'ViewMatrix' after 'SetMatrixCount'), use 'fullConstantCount' instead of '_constant_count' in case it already got modified
  1630. #if CACHE_DX9_CONSTANTS
  1631. DYNAMIC_ASSERT(c.start+c.count<=MAX_DX9_SHADER_CONSTANT/SIZE(Vec4), "Shader Constant out of range");
  1632. #endif
  1633. }
  1634. ps_constants.setNum(f.decUIntV()); FREPA(ps_constants)
  1635. {
  1636. Constant &c=ps_constants[i]; ConstantIndex9 ci; f>>ci;
  1637. c.sp =Get(ci.src_index, params); c.changed=c.sp->_changed;
  1638. c.start=ci.start;
  1639. c.count=ci.count;
  1640. c.data =c.sp->_data+ci.offset;
  1641. c.final_count=((c.count<c.sp->fullConstantCount()) ? &c.count : &c.sp->_constant_count); // if this constant is not using full 'ShaderParam' size then keep its own count, otherwise point to the 'ShaderParam' count in case it can get decreased later (for example 'ViewMatrix' after 'SetMatrixCount'), use 'fullConstantCount' instead of '_constant_count' in case it already got modified
  1642. #if CACHE_DX9_CONSTANTS
  1643. DYNAMIC_ASSERT(c.start+c.count<=MAX_DX9_SHADER_CONSTANT/SIZE(Vec4), "Shader Constant out of range");
  1644. #endif
  1645. }
  1646. if(f.ok())return true;
  1647. /*del();*/ return false;
  1648. }
  1649. #endif
  1650. #endif
  1651. /******************************************************************************/
  1652. #if DX11
  1653. static void SaveBuffers(File &f, C Mems<Shader11::Buffer> &constants, C Memc<ShaderBufferParams> &file_buffers, MemtN<UShort, 256> &all)
  1654. {
  1655. MemtN<ConstantIndex, 256> save;
  1656. FREPA(constants)
  1657. {
  1658. Int buffer_index=GetIndex(file_buffers, constants[i].buffer); // index of buffer in 'file_buffers' array
  1659. C ShaderBufferParams &buffer=file_buffers[buffer_index];
  1660. if(buffer.index<0) // here we have to save only buffers that don't have a constant bind point index
  1661. save.New().set(constants[i].index, buffer_index); // save to which index this buffer should be bound for this shader, and index of buffer in 'file_buffers' array
  1662. all.binaryInclude(AsUShort(buffer_index), Compare);
  1663. }
  1664. save.saveRaw(f);
  1665. }
  1666. Bool Shader11::save(File &f, C Memc<ShaderBufferParams> &buffers, C Memc<ShaderImage*> &images)C
  1667. {
  1668. // name
  1669. f.putStr(name).putMulti(vs_index, hs_index, ds_index, ps_index);
  1670. // images
  1671. f.cmpUIntV(vs_textures.elms()); FREPA(vs_textures)f<<ConstantIndex(vs_textures[i].index, GetIndex(images, vs_textures[i].image));
  1672. f.cmpUIntV(hs_textures.elms()); FREPA(hs_textures)f<<ConstantIndex(hs_textures[i].index, GetIndex(images, hs_textures[i].image));
  1673. f.cmpUIntV(ds_textures.elms()); FREPA(ds_textures)f<<ConstantIndex(ds_textures[i].index, GetIndex(images, ds_textures[i].image));
  1674. f.cmpUIntV(ps_textures.elms()); FREPA(ps_textures)f<<ConstantIndex(ps_textures[i].index, GetIndex(images, ps_textures[i].image));
  1675. // buffers
  1676. MemtN<UShort, 256> all;
  1677. SaveBuffers(f, vs_buffers, buffers, all);
  1678. SaveBuffers(f, hs_buffers, buffers, all);
  1679. SaveBuffers(f, ds_buffers, buffers, all);
  1680. SaveBuffers(f, ps_buffers, buffers, all);
  1681. all.saveRaw(f);
  1682. return f.ok();
  1683. }
  1684. #if DEBUG
  1685. static void Test(Shader11::Buffer &b)
  1686. {
  1687. switch(b.index)
  1688. {
  1689. case SBI_GLOBAL : if(Name(*b.buffer)!="Global" )error: Exit(S+"Invalid Shader Constant Index "+b.index+' '+Name(*b.buffer)); break;
  1690. case SBI_OBJ_MATRIX: if(Name(*b.buffer)!="ObjMatrix")goto error; break;
  1691. case SBI_OBJ_VEL : if(Name(*b.buffer)!="ObjVel" )goto error; break;
  1692. case SBI_MESH : if(Name(*b.buffer)!="Mesh" )goto error; break;
  1693. case SBI_MATERIAL : if(Name(*b.buffer)!="Material" )goto error; break;
  1694. case SBI_VIEWPORT : if(Name(*b.buffer)!="Viewport" )goto error; break;
  1695. case SBI_COLOR : if(Name(*b.buffer)!="Color" )goto error; break;
  1696. }ASSERT(SBI_NUM==7);
  1697. }
  1698. #endif
  1699. Bool Shader11::load(File &f, C MemtN<ShaderBuffer*, 256> &file_buffers, C MemtN<ShaderImage*, 256> &images)
  1700. {
  1701. // name
  1702. f.getStr(name).getMulti(vs_index, hs_index, ds_index, ps_index);
  1703. // textures
  1704. vs_textures.setNum(f.decUIntV()); FREPA(vs_textures){Texture &t=vs_textures[i]; ConstantIndex ci; f>>ci; t.index=ci.bind_index; if(!InRange(t.index, MAX_TEXTURES))Exit(S+"Texture index: "+t.index+", is too big"); t.image=Get(ci.src_index, images);}
  1705. hs_textures.setNum(f.decUIntV()); FREPA(hs_textures){Texture &t=hs_textures[i]; ConstantIndex ci; f>>ci; t.index=ci.bind_index; if(!InRange(t.index, MAX_TEXTURES))Exit(S+"Texture index: "+t.index+", is too big"); t.image=Get(ci.src_index, images);}
  1706. ds_textures.setNum(f.decUIntV()); FREPA(ds_textures){Texture &t=ds_textures[i]; ConstantIndex ci; f>>ci; t.index=ci.bind_index; if(!InRange(t.index, MAX_TEXTURES))Exit(S+"Texture index: "+t.index+", is too big"); t.image=Get(ci.src_index, images);}
  1707. ps_textures.setNum(f.decUIntV()); FREPA(ps_textures){Texture &t=ps_textures[i]; ConstantIndex ci; f>>ci; t.index=ci.bind_index; if(!InRange(t.index, MAX_TEXTURES))Exit(S+"Texture index: "+t.index+", is too big"); t.image=Get(ci.src_index, images);}
  1708. // buffers
  1709. vs_buffers.setNum(f.decUIntV()); FREPA(vs_buffers){Buffer &b=vs_buffers[i]; ConstantIndex ci; f>>ci; b.index=ci.bind_index; if(!InRange(b.index, MAX_SHADER_BUFFERS))Exit(S+"Buffer index: "+b.index+", is too big"); b.buffer=Get(ci.src_index, file_buffers);}
  1710. hs_buffers.setNum(f.decUIntV()); FREPA(hs_buffers){Buffer &b=hs_buffers[i]; ConstantIndex ci; f>>ci; b.index=ci.bind_index; if(!InRange(b.index, MAX_SHADER_BUFFERS))Exit(S+"Buffer index: "+b.index+", is too big"); b.buffer=Get(ci.src_index, file_buffers);}
  1711. ds_buffers.setNum(f.decUIntV()); FREPA(ds_buffers){Buffer &b=ds_buffers[i]; ConstantIndex ci; f>>ci; b.index=ci.bind_index; if(!InRange(b.index, MAX_SHADER_BUFFERS))Exit(S+"Buffer index: "+b.index+", is too big"); b.buffer=Get(ci.src_index, file_buffers);}
  1712. ps_buffers.setNum(f.decUIntV()); FREPA(ps_buffers){Buffer &b=ps_buffers[i]; ConstantIndex ci; f>>ci; b.index=ci.bind_index; if(!InRange(b.index, MAX_SHADER_BUFFERS))Exit(S+"Buffer index: "+b.index+", is too big"); b.buffer=Get(ci.src_index, file_buffers);}
  1713. buffers.setNum(f.decUIntV()); FREPA( buffers) buffers[i]=Get(f.getUShort(), file_buffers);
  1714. #if DEBUG && 1
  1715. //#pragma message("!! Warning: Use this only for debugging !!")
  1716. REPA(vs_buffers)Test(vs_buffers[i]);
  1717. REPA(hs_buffers)Test(hs_buffers[i]);
  1718. REPA(ds_buffers)Test(ds_buffers[i]);
  1719. REPA(ps_buffers)Test(ps_buffers[i]);
  1720. #endif
  1721. if(f.ok())return true;
  1722. /*del();*/ return false;
  1723. }
  1724. #endif
  1725. /******************************************************************************/
  1726. #if GL
  1727. void ShaderGL::GLSLParam::set(Int gpu_offset, ShaderParam &param, C Str8 &glsl_name) {T.gpu_offset=gpu_offset; T.param=&param; DYNAMIC_ASSERT(T.gpu_offset==gpu_offset, "gpu_offset out of range"); T.glsl_name=glsl_name;}
  1728. Bool ShaderGL::save(File &f, C Map<Str8, ShaderParam> &params, C Memc<ShaderImage*> &images)C
  1729. {
  1730. f.putStr(name);
  1731. f.putMulti(vs_index, ps_index);
  1732. f.cmpUIntV(glsl_params.elms()); FREPA(glsl_params)f<<glsl_params[i].gpu_offset<<AsUShort(GetIndex(params, glsl_params[i].param))<<glsl_params[i].glsl_name;
  1733. //f.cmpUIntV(glsl_images.elms()); FREPA(glsl_images)f<< AsUShort(GetIndex(images, glsl_images[i] ));
  1734. return f.ok();
  1735. }
  1736. Bool ShaderGL::load(File &f, C MemtN<ShaderParam*, 256> &params, C MemtN<ShaderImage*, 256> &images)
  1737. {
  1738. f.getStr(name);
  1739. f.getMulti(vs_index, ps_index);
  1740. glsl_params.setNum(f.decUIntV()); FREPA (glsl_params){GLSLParam &param=glsl_params[i]; f>>param.gpu_offset; param.param=Get(f.getUShort(), params); f>>param.glsl_name;}
  1741. //glsl_images.setNum(f.decUIntV()); FREPAO(glsl_images)= Get(f.getUShort(), images);
  1742. if(f.ok())return true;
  1743. /*del();*/ return false;
  1744. }
  1745. #endif
  1746. /******************************************************************************/
  1747. static Bool HasData(Byte *data, Int size)
  1748. {
  1749. FREP(size)if(data[i])return true;
  1750. return false;
  1751. }
  1752. static void SaveTranslation(C Mems<ShaderParam::Translation> &translation, File &f, Int elms)
  1753. {
  1754. if(elms<=1)translation.saveRaw(f);else
  1755. {
  1756. UShort single_translations=translation.elms()/elms,
  1757. gpu_offset=translation[single_translations].gpu_offset-translation[0].gpu_offset,
  1758. cpu_offset=translation[single_translations].cpu_offset-translation[0].cpu_offset;
  1759. f.putMulti(gpu_offset, cpu_offset, single_translations);
  1760. FREP(single_translations)f<<translation[i]; // save 1st element translation
  1761. }
  1762. }
  1763. static void LoadTranslation(MemPtr<ShaderParam::Translation> translation, File &f, Int elms)
  1764. {
  1765. if(elms<=1)translation.loadRaw(f);else
  1766. {
  1767. translation.clear();
  1768. UShort single_translations, gpu_offset, cpu_offset; f.getMulti(gpu_offset, cpu_offset, single_translations);
  1769. FREP( single_translations)f>>translation.New(); // load 1st element translation
  1770. for(Int e=1, co=0, go=0; e<elms; e++) // add rest of the elements
  1771. {
  1772. co+=cpu_offset; // element offset
  1773. go+=gpu_offset; // element offset
  1774. FREP(single_translations)
  1775. {
  1776. ShaderParam::Translation &t=translation.New(); // create and store reference !! memory address changes, do not perform adding new element and referencing previous element in one line of code !!
  1777. t=translation[i];
  1778. t.cpu_offset+=co;
  1779. t.gpu_offset+=go;
  1780. }
  1781. }
  1782. }
  1783. }
  1784. static void LimitTranslation(ShaderParam &sp)
  1785. {
  1786. Memt<ShaderParam::Translation> translation;
  1787. FREPA(sp._full_translation) // go from the start
  1788. {
  1789. ShaderParam::Translation &t=sp._full_translation[i];
  1790. Int size=t.elm_size; // copy to temp var in case original is unsigned
  1791. Int end=Min(t.cpu_offset+size, sp._cpu_data_size); MIN(size, end-t.cpu_offset);
  1792. end=Min(t.gpu_offset+size, sp._gpu_data_size); MIN(size, end-t.gpu_offset);
  1793. if(size>0){t.elm_size=size; translation.add(t);}
  1794. }
  1795. sp._full_translation=translation;
  1796. }
  1797. Bool ShaderParam::save(File &f, C Str8 &name)C
  1798. {
  1799. Byte *param_data=_data+_full_translation[0].gpu_offset; // in DX10+, '_data' when saving, points to Shader Constant Buffer data, that's why we need to use offset
  1800. f.putStr(name).putMulti(_cpu_data_size, _gpu_data_size, _elements); // name+info
  1801. SaveTranslation(_full_translation, f, _elements); // translation
  1802. if(HasData(param_data, _gpu_data_size)) // data
  1803. {
  1804. f.putBool(true);
  1805. f.put(param_data, _gpu_data_size);
  1806. }else
  1807. {
  1808. f.putBool(false);
  1809. }
  1810. return f.ok();
  1811. }
  1812. /******************************************************************************/
  1813. static void ExitParam(C Str &param_name, C Str &shader_name)
  1814. {
  1815. #if GL && VARIABLE_MAX_MATRIX
  1816. if(D.meshBoneSplit())if(param_name=="ViewMatrix" || param_name=="ObjVel" || param_name=="FurVel")return; // allow ViewMatrix and ObjVel to differ, because they're dynamically resized depending on GPU capabilities
  1817. #endif
  1818. Exit(S+"Shader Param \""+param_name+"\"\nfrom Shader File \""+shader_name+"\"\nAlready exists in Shader Constants Map but with different parameters.\nThis means that some of your shaders were compiled with different headers.\nPlease recompile your shaders.");
  1819. }
  1820. Bool ShaderFile::load(C Str &name)
  1821. {
  1822. del();
  1823. Str8 temp_str;
  1824. File f; if(f.readTry(Sh.path+name))
  1825. {
  1826. if(f.getUInt()==CC4_SHDR) // cc4
  1827. {
  1828. switch(f.getByte()) // type
  1829. {
  1830. #if DX9
  1831. case SHADER_DX9:
  1832. {
  1833. switch(f.decUIntV()) // version
  1834. {
  1835. case 0:
  1836. {
  1837. // params
  1838. MemtN<ShaderParam*, 256> params; params.setNum(f.decUIntV());
  1839. ShaderParams.lock();
  1840. FREPA(params)
  1841. {
  1842. f.getStr(temp_str); ShaderParam &sp=*ShaderParams(temp_str); params[i]=&sp;
  1843. if(!sp.is()) // wasn't yet created
  1844. {
  1845. sp._owns_data=true;
  1846. f.getMulti(sp._cpu_data_size, sp._gpu_data_size, sp._elements); // info
  1847. LoadTranslation(sp._full_translation, f, sp._elements); // translation
  1848. Alloc(sp._data, sp._gpu_data_size); // data
  1849. Alloc(sp._changed );
  1850. sp._constant_count=sp.fullConstantCount();
  1851. if(f.getBool())f.get(sp._data, sp._gpu_data_size); // load default value
  1852. else Zero (sp._data, sp._gpu_data_size); // zero default value
  1853. sp.optimize();
  1854. }else // verify if it's identical to previously created
  1855. {
  1856. Memt<ShaderParam::Translation> translation;
  1857. Int cpu_data_size, gpu_data_size, elements; f.getMulti(cpu_data_size, gpu_data_size, elements);
  1858. if(sp._cpu_data_size!=cpu_data_size // check cpu size
  1859. || sp._gpu_data_size!=gpu_data_size // check gpu size
  1860. || sp._elements !=elements )ExitParam(temp_str, name); // check number of elements
  1861. LoadTranslation(translation, f, sp._elements); // translation
  1862. if(f.getBool())f.skip(sp._gpu_data_size); // ignore default value
  1863. // check translation
  1864. if( translation.elms()!=sp._full_translation.elms())ExitParam(temp_str, name);
  1865. FREPA(translation)if(translation[i] !=sp._full_translation[i] )ExitParam(temp_str, name);
  1866. }
  1867. }
  1868. ShaderParams.unlock();
  1869. // images
  1870. MemtN<ShaderImage*, 256> images; images.setNum(f.decUIntV());
  1871. FREPA(images){f.getStr(temp_str); images[i]=ShaderImages(temp_str);}
  1872. // shaders
  1873. if(_vs .load(f))
  1874. if(_ps .load(f))
  1875. if(_shaders.load(f, params, images))
  1876. if(f.ok())return true;
  1877. }break;
  1878. }
  1879. }break;
  1880. #elif DX11
  1881. case SHADER_DX11:
  1882. {
  1883. switch(f.decUIntV()) // version
  1884. {
  1885. case 0:
  1886. {
  1887. // buffers
  1888. MemtN<ShaderBuffer*, 256> buffers; buffers.setNum(f.decUIntV());
  1889. ShaderBuffers.lock();
  1890. ShaderParams .lock();
  1891. FREPA(buffers)
  1892. {
  1893. // buffer
  1894. f.getStr(temp_str); ShaderBuffer &sb=*ShaderBuffers(temp_str); buffers[i]=&sb;
  1895. if(!sb.is()) // wasn't yet created
  1896. {
  1897. sb.create(f.decUIntV());
  1898. Int index=f.getSByte(); if(index>=0){SyncLocker lock(D._lock); sb.bind(index);}
  1899. }else // verify if it's identical to previously created
  1900. {
  1901. if(sb.size()!=f.decUIntV())ExitParam(temp_str, name);
  1902. sb.bindCheck(f.getSByte());
  1903. }
  1904. // params
  1905. REP(f.decUIntV())
  1906. {
  1907. f.getStr(temp_str); ShaderParam &sp=*ShaderParams(temp_str);
  1908. if(!sp.is()) // wasn't yet created
  1909. {
  1910. sp._owns_data= false;
  1911. sp._data = sb.data;
  1912. sp._changed =&sb.changed;
  1913. f.getMulti(sp._cpu_data_size, sp._gpu_data_size, sp._elements); // info
  1914. //sp._constant_count= // unused on DX10+
  1915. LoadTranslation(sp._full_translation, f, sp._elements); // translation
  1916. Int offset=sp._full_translation[0].gpu_offset; sp._data+=offset; REPAO(sp._full_translation).gpu_offset-=offset; // apply offset
  1917. if(f.getBool())f.get(sp._data, sp._gpu_data_size); // load default value, no need to zero in other case, because data is stored in ShaderBuffer's, and they're always zeroed at start
  1918. sp.optimize(); // optimize
  1919. }else // verify if it's identical to previously created
  1920. {
  1921. Int cpu_data_size, gpu_data_size, elements; f.getMulti(cpu_data_size, gpu_data_size, elements);
  1922. Memt<ShaderParam::Translation> translation;
  1923. if(sp._changed !=&sb.changed // check matching Constant Buffer
  1924. || sp._cpu_data_size!= cpu_data_size // check cpu size
  1925. || sp._gpu_data_size!= gpu_data_size // check gpu size
  1926. || sp._elements != elements )ExitParam(temp_str, name); // check number of elements
  1927. LoadTranslation(translation, f, sp._elements); // translation
  1928. Int offset=translation[0].gpu_offset; REPAO(translation).gpu_offset-=offset; // apply offset
  1929. if(f.getBool())f.skip(sp._gpu_data_size); // ignore default value
  1930. // check translation
  1931. if( translation.elms()!=sp._full_translation.elms())ExitParam(temp_str, name);
  1932. FREPA(translation)if(translation[i] !=sp._full_translation[i] )ExitParam(temp_str, name);
  1933. }
  1934. }
  1935. }
  1936. ShaderParams .unlock();
  1937. ShaderBuffers.unlock();
  1938. // images
  1939. MemtN<ShaderImage*, 256> images; images.setNum(f.decUIntV());
  1940. FREPA(images){f.getStr(temp_str); images[i]=ShaderImages(temp_str);}
  1941. // shaders
  1942. if(_vs .load(f))
  1943. if(_hs .load(f))
  1944. if(_ds .load(f))
  1945. if(_ps .load(f))
  1946. if(_shaders.load(f, buffers, images))
  1947. if(f.ok())return true;
  1948. }break;
  1949. }
  1950. }break;
  1951. #elif GL
  1952. case SHADER_GL:
  1953. {
  1954. switch(f.decUIntV()) // version
  1955. {
  1956. case 0:
  1957. {
  1958. // params
  1959. MemtN<ShaderParam*, 256> params; params.setNum(f.decUIntV());
  1960. ShaderParams.lock();
  1961. FREPA(params)
  1962. {
  1963. f.getStr(temp_str); ShaderParam &sp=*ShaderParams(temp_str); params[i]=&sp;
  1964. if(!sp.is()) // wasn't yet created
  1965. {
  1966. sp._owns_data=true;
  1967. f.getMulti(sp._cpu_data_size, sp._gpu_data_size, sp._elements); // info
  1968. LoadTranslation(sp._full_translation, f, sp._elements); // translation
  1969. Alloc(sp._data, sp._gpu_data_size); // data
  1970. Alloc(sp._changed );
  1971. if(f.getBool())f.get(sp._data, sp._gpu_data_size); // load default value
  1972. else Zero (sp._data, sp._gpu_data_size); // zero default value
  1973. #if VARIABLE_MAX_MATRIX
  1974. when enabling VARIABLE_MAX_MATRIX then shaders need to be recompiled with "MAX_MATRIX 256" (for CG and GLSL) because we're only reducing in 'LimitTranslation' and when replacing shader codes
  1975. if(D.meshBoneSplit())
  1976. {
  1977. if(temp_str=="ViewMatrix")
  1978. {
  1979. sp._cpu_data_size=
  1980. sp._gpu_data_size=SIZE(GpuMatrix)*D.maxShaderMatrixes();
  1981. LimitTranslation(sp);
  1982. }else
  1983. if(temp_str=="ObjVel")
  1984. {
  1985. sp._cpu_data_size=
  1986. sp._gpu_data_size=SIZE(Vec)*D.maxShaderMatrixes();
  1987. LimitTranslation(sp);
  1988. }else
  1989. if(temp_str=="FurVel")
  1990. {
  1991. sp._cpu_data_size=
  1992. sp._gpu_data_size=SIZE(Vec)*D.maxShaderMatrixes();
  1993. LimitTranslation(sp);
  1994. }
  1995. }
  1996. #endif
  1997. sp._constant_count=sp.fullConstantCount();
  1998. sp.optimize();
  1999. }else // verify if it's identical to previously created
  2000. {
  2001. Int cpu_data_size, gpu_data_size, elements; f.getMulti(cpu_data_size, gpu_data_size, elements);
  2002. Memt<ShaderParam::Translation> translation;
  2003. if(sp._cpu_data_size!=cpu_data_size // check cpu size
  2004. || sp._gpu_data_size!=gpu_data_size // check gpu size
  2005. || sp._elements !=elements )ExitParam(temp_str, name); // check number of elements
  2006. LoadTranslation(translation, f, elements); // translation
  2007. if(f.getBool())f.skip(gpu_data_size); // ignore default value
  2008. // check translation
  2009. if( translation.elms()!=sp._full_translation.elms()) ExitParam(temp_str, name);else
  2010. FREPA(translation)if(translation[i] !=sp._full_translation[i] ){ExitParam(temp_str, name); break;}
  2011. }
  2012. }
  2013. ShaderParams.unlock();
  2014. // images
  2015. MemtN<ShaderImage*, 256> images; images.setNum(f.decUIntV());
  2016. FREPA(images){f.getStr(temp_str); images[i]=ShaderImages(temp_str);}
  2017. // shaders
  2018. if(_vs .load(f))
  2019. if(_ps .load(f))
  2020. if(_shaders.load(f, params, images))
  2021. if(f.ok())return true;
  2022. }break;
  2023. }
  2024. }break;
  2025. #endif
  2026. }
  2027. }
  2028. }
  2029. //error:
  2030. del(); return false;
  2031. }
  2032. /******************************************************************************/
  2033. }
  2034. /******************************************************************************/