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