]> git.lizzy.rs Git - minetest.git/blob - src/shader.cpp
Make MutexQueue use jsemaphore for signaling
[minetest.git] / src / shader.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013 Kahrl <kahrl@gmx.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "shader.h"
22 #include "irrlichttypes_extrabloated.h"
23 #include "debug.h"
24 #include "main.h" // for g_settings
25 #include "filesys.h"
26 #include "util/container.h"
27 #include "util/thread.h"
28 #include "settings.h"
29 #include <iterator>
30 #include <ICameraSceneNode.h>
31 #include <IGPUProgrammingServices.h>
32 #include <IMaterialRenderer.h>
33 #include <IMaterialRendererServices.h>
34 #include <IShaderConstantSetCallBack.h>
35 #include "EShaderTypes.h"
36 #include "log.h"
37 #include "gamedef.h"
38 #include "strfnd.h" // trim()
39
40 /*
41         A cache from shader name to shader path
42 */
43 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
44
45 /*
46         Gets the path to a shader by first checking if the file
47           name_of_shader/filename
48         exists in shader_path and if not, using the data path.
49
50         If not found, returns "".
51
52         Utilizes a thread-safe cache.
53 */
54 std::string getShaderPath(const std::string &name_of_shader,
55                 const std::string &filename)
56 {
57         std::string combined = name_of_shader + DIR_DELIM + filename;
58         std::string fullpath = "";
59         /*
60                 Check from cache
61         */
62         bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
63         if(incache)
64                 return fullpath;
65
66         /*
67                 Check from shader_path
68         */
69         std::string shader_path = g_settings->get("shader_path");
70         if(shader_path != "")
71         {
72                 std::string testpath = shader_path + DIR_DELIM + combined;
73                 if(fs::PathExists(testpath))
74                         fullpath = testpath;
75         }
76
77         /*
78                 Check from default data directory
79         */
80         if(fullpath == "")
81         {
82                 std::string rel_path = std::string("client") + DIR_DELIM
83                                 + "shaders" + DIR_DELIM
84                                 + name_of_shader + DIR_DELIM
85                                 + filename;
86                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
87                 if(fs::PathExists(testpath))
88                         fullpath = testpath;
89         }
90
91         // Add to cache (also an empty result is cached)
92         g_shadername_to_path_cache.set(combined, fullpath);
93
94         // Finally return it
95         return fullpath;
96 }
97
98 /*
99         SourceShaderCache: A cache used for storing source shaders.
100 */
101
102 class SourceShaderCache
103 {
104 public:
105         void insert(const std::string &name_of_shader,
106                         const std::string &filename,
107                         const std::string &program,
108                         bool prefer_local)
109         {
110                 std::string combined = name_of_shader + DIR_DELIM + filename;
111                 // Try to use local shader instead if asked to
112                 if(prefer_local){
113                         std::string path = getShaderPath(name_of_shader, filename);
114                         if(path != ""){
115                                 std::string p = readFile(path);
116                                 if(p != ""){
117                                         m_programs[combined] = p;
118                                         return;
119                                 }
120                         }
121                 }
122                 m_programs[combined] = program;
123         }
124         std::string get(const std::string &name_of_shader,
125                         const std::string &filename)
126         {
127                 std::string combined = name_of_shader + DIR_DELIM + filename;
128                 std::map<std::string, std::string>::iterator n;
129                 n = m_programs.find(combined);
130                 if(n != m_programs.end())
131                         return n->second;
132                 return "";
133         }
134         // Primarily fetches from cache, secondarily tries to read from filesystem
135         std::string getOrLoad(const std::string &name_of_shader,
136                         const std::string &filename)
137         {
138                 std::string combined = name_of_shader + DIR_DELIM + filename;
139                 std::map<std::string, std::string>::iterator n;
140                 n = m_programs.find(combined);
141                 if(n != m_programs.end())
142                         return n->second;
143                 std::string path = getShaderPath(name_of_shader, filename);
144                 if(path == ""){
145                         infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
146                                         <<combined<<"\""<<std::endl;
147                         return "";
148                 }
149                 infostream<<"SourceShaderCache::getOrLoad(): Loading path \""<<path
150                                 <<"\""<<std::endl;
151                 std::string p = readFile(path);
152                 if(p != ""){
153                         m_programs[combined] = p;
154                         return p;
155                 }
156                 return "";
157         }
158 private:
159         std::map<std::string, std::string> m_programs;
160         std::string readFile(const std::string &path)
161         {
162                 std::ifstream is(path.c_str(), std::ios::binary);
163                 if(!is.is_open())
164                         return "";
165                 std::ostringstream tmp_os;
166                 tmp_os << is.rdbuf();
167                 return tmp_os.str();
168         }
169 };
170
171 /*
172         ShaderCallback: Sets constants that can be used in shaders
173 */
174
175 class IShaderConstantSetterRegistry
176 {
177 public:
178         virtual ~IShaderConstantSetterRegistry(){};
179         virtual void onSetConstants(video::IMaterialRendererServices *services,
180                         bool is_highlevel, const std::string &name) = 0;
181 };
182
183 class ShaderCallback : public video::IShaderConstantSetCallBack
184 {
185         IShaderConstantSetterRegistry *m_scsr;
186         std::string m_name;
187
188 public:
189         ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
190                 m_scsr(scsr),
191                 m_name(name)
192         {}
193         ~ShaderCallback() {}
194
195         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
196         {
197                 video::IVideoDriver *driver = services->getVideoDriver();
198                 assert(driver);
199
200                 bool is_highlevel = userData;
201
202                 m_scsr->onSetConstants(services, is_highlevel, m_name);
203         }
204 };
205
206 /*
207         MainShaderConstantSetter: Set basic constants required for almost everything
208 */
209
210 class MainShaderConstantSetter : public IShaderConstantSetter
211 {
212 public:
213         MainShaderConstantSetter(IrrlichtDevice *device):
214                 m_device(device)
215         {}
216         ~MainShaderConstantSetter() {}
217
218         virtual void onSetConstants(video::IMaterialRendererServices *services,
219                         bool is_highlevel)
220         {
221                 video::IVideoDriver *driver = services->getVideoDriver();
222                 assert(driver);
223
224                 // set inverted world matrix
225                 core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
226                 invWorld.makeInverse();
227                 if(is_highlevel)
228                         services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
229                 else
230                         services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
231
232                 // set clip matrix
233                 core::matrix4 worldViewProj;
234                 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
235                 worldViewProj *= driver->getTransform(video::ETS_VIEW);
236                 worldViewProj *= driver->getTransform(video::ETS_WORLD);
237                 if(is_highlevel)
238                         services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
239                 else
240                         services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
241
242                 // set transposed world matrix
243                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
244                 world = world.getTransposed();
245                 if(is_highlevel)
246                         services->setVertexShaderConstant("mTransWorld", world.pointer(), 16);
247                 else
248                         services->setVertexShaderConstant(world.pointer(), 8, 4);
249         }
250
251 private:
252         IrrlichtDevice *m_device;
253 };
254
255 /*
256         ShaderSource
257 */
258
259 class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
260 {
261 public:
262         ShaderSource(IrrlichtDevice *device);
263         ~ShaderSource();
264
265         /*
266                 Gets a shader material id from cache or
267                 - if main thread, from getShaderIdDirect
268                 - if other thread, adds to request queue and waits for main thread
269         */
270         u32 getShaderId(const std::string &name);
271
272         /*
273                 - If shader material specified by name is found from cache,
274                   return the cached id.
275                 - Otherwise generate the shader material, add to cache and return id.
276
277                 The id 0 points to a null shader. Its material is EMT_SOLID.
278         */
279         u32 getShaderIdDirect(const std::string &name);
280
281         // Finds out the name of a cached shader.
282         std::string getShaderName(u32 id);
283
284         /*
285                 If shader specified by the name pointed by the id doesn't
286                 exist, create it, then return the cached shader.
287
288                 Can be called from any thread. If called from some other thread
289                 and not found in cache, the call is queued to the main thread
290                 for processing.
291         */
292         ShaderInfo getShader(u32 id);
293
294         ShaderInfo getShader(const std::string &name)
295         {
296                 return getShader(getShaderId(name));
297         }
298
299         // Processes queued shader requests from other threads.
300         // Shall be called from the main thread.
301         void processQueue();
302
303         // Insert a shader program into the cache without touching the
304         // filesystem. Shall be called from the main thread.
305         void insertSourceShader(const std::string &name_of_shader,
306                 const std::string &filename, const std::string &program);
307
308         // Rebuild shaders from the current set of source shaders
309         // Shall be called from the main thread.
310         void rebuildShaders();
311
312         void addGlobalConstantSetter(IShaderConstantSetter *setter)
313         {
314                 m_global_setters.push_back(setter);
315         }
316
317         void onSetConstants(video::IMaterialRendererServices *services,
318                         bool is_highlevel, const std::string &name);
319
320 private:
321
322         // The id of the thread that is allowed to use irrlicht directly
323         threadid_t m_main_thread;
324         // The irrlicht device
325         IrrlichtDevice *m_device;
326         // The set-constants callback
327         ShaderCallback *m_shader_callback;
328
329         // Cache of source shaders
330         // This should be only accessed from the main thread
331         SourceShaderCache m_sourcecache;
332
333         // A shader id is index in this array.
334         // The first position contains a dummy shader.
335         std::vector<ShaderInfo> m_shaderinfo_cache;
336         // Maps a shader name to an index in the former.
337         std::map<std::string, u32> m_name_to_id;
338         // The two former containers are behind this mutex
339         JMutex m_shaderinfo_cache_mutex;
340
341         // Queued shader fetches (to be processed by the main thread)
342         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
343
344         // Global constant setters
345         // TODO: Delete these in the destructor
346         std::vector<IShaderConstantSetter*> m_global_setters;
347 };
348
349 IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
350 {
351         return new ShaderSource(device);
352 }
353
354 /*
355         Generate shader given the shader name.
356 */
357 ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
358                 video::IShaderConstantSetCallBack *callback,
359                 SourceShaderCache *sourcecache);
360
361 /*
362         Load shader programs
363 */
364 void load_shaders(std::string name, SourceShaderCache *sourcecache,
365                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
366                 std::string &vertex_program, std::string &pixel_program,
367                 std::string &geometry_program, bool &is_highlevel);
368
369 ShaderSource::ShaderSource(IrrlichtDevice *device):
370                 m_device(device)
371 {
372         assert(m_device);
373
374         m_shader_callback = new ShaderCallback(this, "default");
375
376         m_main_thread = get_current_thread_id();
377
378         // Add a dummy ShaderInfo as the first index, named ""
379         m_shaderinfo_cache.push_back(ShaderInfo());
380         m_name_to_id[""] = 0;
381
382         // Add main global constant setter
383         addGlobalConstantSetter(new MainShaderConstantSetter(device));
384 }
385
386 ShaderSource::~ShaderSource()
387 {
388         //m_shader_callback->drop();
389
390         for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
391                         iter != m_global_setters.end(); iter++) {
392                 delete *iter;
393         }
394         m_global_setters.clear();
395 }
396
397 u32 ShaderSource::getShaderId(const std::string &name)
398 {
399         //infostream<<"getShaderId(): \""<<name<<"\""<<std::endl;
400
401         {
402                 /*
403                         See if shader already exists
404                 */
405                 JMutexAutoLock lock(m_shaderinfo_cache_mutex);
406                 std::map<std::string, u32>::iterator n;
407                 n = m_name_to_id.find(name);
408                 if(n != m_name_to_id.end())
409                         return n->second;
410         }
411
412         /*
413                 Get shader
414         */
415         if(get_current_thread_id() == m_main_thread){
416                 return getShaderIdDirect(name);
417         } else {
418                 /*errorstream<<"getShaderId(): Queued: name=\""<<name<<"\""<<std::endl;*/
419
420                 // We're gonna ask the result to be put into here
421
422                 static ResultQueue<std::string, u32, u8, u8> result_queue;
423
424                 // Throw a request in
425                 m_get_shader_queue.add(name, 0, 0, &result_queue);
426
427                 /* infostream<<"Waiting for shader from main thread, name=\""
428                                 <<name<<"\""<<std::endl;*/
429
430                 while(true) {
431                         GetResult<std::string, u32, u8, u8>
432                                 result = result_queue.pop_frontNoEx();
433
434                         if (result.key == name) {
435                                 return result.item;
436                         }
437                         else {
438                                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
439                         }
440                 }
441
442         }
443
444         infostream<<"getShaderId(): Failed"<<std::endl;
445
446         return 0;
447 }
448
449 /*
450         This method generates all the shaders
451 */
452 u32 ShaderSource::getShaderIdDirect(const std::string &name)
453 {
454         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
455
456         // Empty name means shader 0
457         if(name == ""){
458                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
459                 return 0;
460         }
461
462         /*
463                 Calling only allowed from main thread
464         */
465         if(get_current_thread_id() != m_main_thread){
466                 errorstream<<"ShaderSource::getShaderIdDirect() "
467                                 "called not from main thread"<<std::endl;
468                 return 0;
469         }
470
471         /*
472                 See if shader already exists
473         */
474         {
475                 JMutexAutoLock lock(m_shaderinfo_cache_mutex);
476
477                 std::map<std::string, u32>::iterator n;
478                 n = m_name_to_id.find(name);
479                 if(n != m_name_to_id.end()){
480                         /*infostream<<"getShaderIdDirect(): \""<<name
481                                         <<"\" found in cache"<<std::endl;*/
482                         return n->second;
483                 }
484         }
485
486         /*infostream<<"getShaderIdDirect(): \""<<name
487                         <<"\" NOT found in cache. Creating it."<<std::endl;*/
488
489         ShaderInfo info = generate_shader(name, m_device,
490                         m_shader_callback, &m_sourcecache);
491
492         /*
493                 Add shader to caches (add dummy shaders too)
494         */
495
496         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
497
498         u32 id = m_shaderinfo_cache.size();
499         m_shaderinfo_cache.push_back(info);
500         m_name_to_id[name] = id;
501
502         /*infostream<<"getShaderIdDirect(): "
503                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
504
505         return id;
506 }
507
508 std::string ShaderSource::getShaderName(u32 id)
509 {
510         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
511
512         if(id >= m_shaderinfo_cache.size()){
513                 errorstream<<"ShaderSource::getShaderName(): id="<<id
514                                 <<" >= m_shaderinfo_cache.size()="
515                                 <<m_shaderinfo_cache.size()<<std::endl;
516                 return "";
517         }
518
519         return m_shaderinfo_cache[id].name;
520 }
521
522 ShaderInfo ShaderSource::getShader(u32 id)
523 {
524         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
525
526         if(id >= m_shaderinfo_cache.size())
527                 return ShaderInfo();
528
529         return m_shaderinfo_cache[id];
530 }
531
532 void ShaderSource::processQueue()
533 {
534         /*
535                 Fetch shaders
536         */
537         //NOTE this is only thread safe for ONE consumer thread!
538         if(!m_get_shader_queue.empty()){
539                 GetRequest<std::string, u32, u8, u8>
540                                 request = m_get_shader_queue.pop();
541
542                 /**errorstream<<"ShaderSource::processQueue(): "
543                                 <<"got shader request with "
544                                 <<"name=\""<<request.key<<"\""
545                                 <<std::endl;**/
546
547                 m_get_shader_queue.pushResult(request,getShaderIdDirect(request.key));
548         }
549 }
550
551 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
552                 const std::string &filename, const std::string &program)
553 {
554         /*infostream<<"ShaderSource::insertSourceShader(): "
555                         "name_of_shader=\""<<name_of_shader<<"\", "
556                         "filename=\""<<filename<<"\""<<std::endl;*/
557
558         assert(get_current_thread_id() == m_main_thread);
559
560         m_sourcecache.insert(name_of_shader, filename, program, true);
561 }
562
563 void ShaderSource::rebuildShaders()
564 {
565         JMutexAutoLock lock(m_shaderinfo_cache_mutex);
566
567         /*// Oh well... just clear everything, they'll load sometime.
568         m_shaderinfo_cache.clear();
569         m_name_to_id.clear();*/
570
571         /*
572                 FIXME: Old shader materials can't be deleted in Irrlicht,
573                 or can they?
574                 (This would be nice to do in the destructor too)
575         */
576
577         // Recreate shaders
578         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
579                 ShaderInfo *info = &m_shaderinfo_cache[i];
580                 if(info->name != ""){
581                         *info = generate_shader(info->name, m_device,
582                                         m_shader_callback, &m_sourcecache);
583                 }
584         }
585 }
586
587 void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
588                 bool is_highlevel, const std::string &name)
589 {
590         for(u32 i=0; i<m_global_setters.size(); i++){
591                 IShaderConstantSetter *setter = m_global_setters[i];
592                 setter->onSetConstants(services, is_highlevel);
593         }
594 }
595
596 ShaderInfo generate_shader(std::string name, IrrlichtDevice *device,
597                 video::IShaderConstantSetCallBack *callback,
598                 SourceShaderCache *sourcecache)
599 {
600         /*infostream<<"generate_shader(): "
601                         "\""<<name<<"\""<<std::endl;*/
602
603         ShaderInfo shaderinfo;
604         shaderinfo.name = name;
605         shaderinfo.material = video::EMT_SOLID;
606
607         /*
608                 Get the base material
609         */
610         std::string base_material_name =
611                 trim(sourcecache->getOrLoad(name, "base.txt"));
612         for(s32 i = 0; video::sBuiltInMaterialTypeNames[i] != 0; i++){
613                 if(video::sBuiltInMaterialTypeNames[i] == base_material_name){
614                         shaderinfo.material = (video::E_MATERIAL_TYPE) i;
615                         break;
616                 }
617         }
618
619         bool enable_shaders = g_settings->getBool("enable_shaders");
620         if(!enable_shaders)
621                 return shaderinfo;
622
623         video::IVideoDriver* driver = device->getVideoDriver();
624         assert(driver);
625
626         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
627         if(!gpu){
628                 errorstream<<"generate_shader(): "
629                                 "failed to generate \""<<name<<"\", "
630                                 "GPU programming not supported."
631                                 <<std::endl;
632                 return shaderinfo;
633         }
634
635         // Choose shader language depending on driver type and settings
636         // Then load shaders
637         std::string vertex_program;
638         std::string pixel_program;
639         std::string geometry_program;
640         bool is_highlevel;
641         load_shaders(name, sourcecache, driver->getDriverType(),
642                         enable_shaders, vertex_program, pixel_program,
643                         geometry_program, is_highlevel);
644
645         // Check hardware/driver support
646         if(vertex_program != "" &&
647                         !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
648                         !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
649                 infostream<<"generate_shader(): vertex shaders disabled "
650                                 "because of missing driver/hardware support."
651                                 <<std::endl;
652                 vertex_program = "";
653         }
654         if(pixel_program != "" &&
655                         !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
656                         !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
657                 infostream<<"generate_shader(): pixel shaders disabled "
658                                 "because of missing driver/hardware support."
659                                 <<std::endl;
660                 pixel_program = "";
661         }
662         if(geometry_program != "" &&
663                         !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
664                 infostream<<"generate_shader(): geometry shaders disabled "
665                                 "because of missing driver/hardware support."
666                                 <<std::endl;
667                 geometry_program = "";
668         }
669
670         // If no shaders are used, don't make a separate material type
671         if(vertex_program == "" && pixel_program == "" && geometry_program == "")
672                 return shaderinfo;
673
674         // Create shaders header
675         std::string shaders_header = "#version 120\n";
676         
677         if (g_settings->getBool("enable_bumpmapping"))
678                 shaders_header += "#define ENABLE_BUMPMAPPING\n";
679
680         if (g_settings->getBool("enable_parallax_occlusion")){
681                 shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
682                 shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
683                 shaders_header += ftos(g_settings->getFloat("parallax_occlusion_scale"));
684                 shaders_header += "\n";
685                 shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
686                 shaders_header += ftos(g_settings->getFloat("parallax_occlusion_bias"));
687                 shaders_header += "\n";
688                 }
689
690         if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
691                 shaders_header += "#define USE_NORMALMAPS\n";
692
693         if (g_settings->getBool("enable_waving_water")){
694                 shaders_header += "#define ENABLE_WAVING_WATER\n";
695                 shaders_header += "#define WATER_WAVE_HEIGHT ";
696                 shaders_header += ftos(g_settings->getFloat("water_wave_height"));
697                 shaders_header += "\n";
698                 shaders_header += "#define WATER_WAVE_LENGTH ";
699                 shaders_header += ftos(g_settings->getFloat("water_wave_length"));
700                 shaders_header += "\n";
701                 shaders_header += "#define WATER_WAVE_SPEED ";
702                 shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
703                 shaders_header += "\n";
704         }
705
706         if (g_settings->getBool("enable_waving_leaves"))
707                 shaders_header += "#define ENABLE_WAVING_LEAVES\n";
708
709         if (g_settings->getBool("enable_waving_plants"))
710                 shaders_header += "#define ENABLE_WAVING_PLANTS\n";
711
712         if(pixel_program != "")
713                 pixel_program = shaders_header + pixel_program;
714         if(vertex_program != "")
715                 vertex_program = shaders_header + vertex_program;
716         if(geometry_program != "")
717                 geometry_program = shaders_header + geometry_program;
718
719         // Call addHighLevelShaderMaterial() or addShaderMaterial()
720         const c8* vertex_program_ptr = 0;
721         const c8* pixel_program_ptr = 0;
722         const c8* geometry_program_ptr = 0;
723         if(vertex_program != "")
724                 vertex_program_ptr = vertex_program.c_str();
725         if(pixel_program != "")
726                 pixel_program_ptr = pixel_program.c_str();
727         if(geometry_program != "")
728                 geometry_program_ptr = geometry_program.c_str();
729         s32 shadermat = -1;
730         if(is_highlevel){
731                 infostream<<"Compiling high level shaders for "<<name<<std::endl;
732                 shadermat = gpu->addHighLevelShaderMaterial(
733                         vertex_program_ptr,   // Vertex shader program
734                         "vertexMain",         // Vertex shader entry point
735                         video::EVST_VS_1_1,   // Vertex shader version
736                         pixel_program_ptr,    // Pixel shader program
737                         "pixelMain",          // Pixel shader entry point
738                         video::EPST_PS_1_1,   // Pixel shader version
739                         geometry_program_ptr, // Geometry shader program
740                         "geometryMain",       // Geometry shader entry point
741                         video::EGST_GS_4_0,   // Geometry shader version
742                         scene::EPT_TRIANGLES,      // Geometry shader input
743                         scene::EPT_TRIANGLE_STRIP, // Geometry shader output
744                         0,                         // Support maximum number of vertices
745                         callback,             // Set-constant callback
746                         shaderinfo.material,  // Base material
747                         1                     // Userdata passed to callback
748                         );
749
750                 if(shadermat == -1){
751                         errorstream<<"generate_shader(): "
752                                         "failed to generate \""<<name<<"\", "
753                                         "addHighLevelShaderMaterial failed."
754                                         <<std::endl;
755                         return shaderinfo;
756                 }
757         }
758         else{
759                 infostream<<"Compiling assembly shaders for "<<name<<std::endl;
760                 shadermat = gpu->addShaderMaterial(
761                         vertex_program_ptr,   // Vertex shader program
762                         pixel_program_ptr,    // Pixel shader program
763                         callback,             // Set-constant callback
764                         shaderinfo.material,  // Base material
765                         0                     // Userdata passed to callback
766                         );
767
768                 if(shadermat == -1){
769                         errorstream<<"generate_shader(): "
770                                         "failed to generate \""<<name<<"\", "
771                                         "addShaderMaterial failed."
772                                         <<std::endl;
773                         return shaderinfo;
774                 }
775         }
776
777         // HACK, TODO: investigate this better
778         // Grab the material renderer once more so minetest doesn't crash on exit
779         driver->getMaterialRenderer(shadermat)->grab();
780
781         // Apply the newly created material type
782         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
783         return shaderinfo;
784 }
785
786 void load_shaders(std::string name, SourceShaderCache *sourcecache,
787                 video::E_DRIVER_TYPE drivertype, bool enable_shaders,
788                 std::string &vertex_program, std::string &pixel_program,
789                 std::string &geometry_program, bool &is_highlevel)
790 {
791         vertex_program = "";
792         pixel_program = "";
793         geometry_program = "";
794         is_highlevel = false;
795
796         if(enable_shaders){
797                 // Look for high level shaders
798                 if(drivertype == video::EDT_DIRECT3D9){
799                         // Direct3D 9: HLSL
800                         // (All shaders in one file)
801                         vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
802                         pixel_program = vertex_program;
803                         geometry_program = vertex_program;
804                 }
805                 else if(drivertype == video::EDT_OPENGL){
806                         // OpenGL: GLSL
807                         vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
808                         pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
809                         geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
810                 }
811                 if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
812                         is_highlevel = true;
813                         return;
814                 }
815         }
816
817 }