]> git.lizzy.rs Git - minetest.git/blob - src/client/shader.cpp
da3da8ab1d17a65969129be68c8ad7ec5b6d2a80
[minetest.git] / src / client / 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 <fstream>
22 #include <iterator>
23 #include "shader.h"
24 #include "irrlichttypes_extrabloated.h"
25 #include "irr_ptr.h"
26 #include "debug.h"
27 #include "filesys.h"
28 #include "util/container.h"
29 #include "util/thread.h"
30 #include "settings.h"
31 #include <ICameraSceneNode.h>
32 #include <IGPUProgrammingServices.h>
33 #include <IMaterialRenderer.h>
34 #include <IMaterialRendererServices.h>
35 #include <IShaderConstantSetCallBack.h>
36 #include "client/renderingengine.h"
37 #include "EShaderTypes.h"
38 #include "log.h"
39 #include "gamedef.h"
40 #include "client/tile.h"
41 #include "config.h"
42
43 #include <mt_opengl.h>
44
45 /*
46         A cache from shader name to shader path
47 */
48 MutexedMap<std::string, std::string> g_shadername_to_path_cache;
49
50 /*
51         Gets the path to a shader by first checking if the file
52           name_of_shader/filename
53         exists in shader_path and if not, using the data path.
54
55         If not found, returns "".
56
57         Utilizes a thread-safe cache.
58 */
59 std::string getShaderPath(const std::string &name_of_shader,
60                 const std::string &filename)
61 {
62         std::string combined = name_of_shader + DIR_DELIM + filename;
63         std::string fullpath;
64         /*
65                 Check from cache
66         */
67         bool incache = g_shadername_to_path_cache.get(combined, &fullpath);
68         if(incache)
69                 return fullpath;
70
71         /*
72                 Check from shader_path
73         */
74         std::string shader_path = g_settings->get("shader_path");
75         if (!shader_path.empty()) {
76                 std::string testpath = shader_path + DIR_DELIM + combined;
77                 if(fs::PathExists(testpath))
78                         fullpath = testpath;
79         }
80
81         /*
82                 Check from default data directory
83         */
84         if (fullpath.empty()) {
85                 std::string rel_path = std::string("client") + DIR_DELIM
86                                 + "shaders" + DIR_DELIM
87                                 + name_of_shader + DIR_DELIM
88                                 + filename;
89                 std::string testpath = porting::path_share + DIR_DELIM + rel_path;
90                 if(fs::PathExists(testpath))
91                         fullpath = testpath;
92         }
93
94         // Add to cache (also an empty result is cached)
95         g_shadername_to_path_cache.set(combined, fullpath);
96
97         // Finally return it
98         return fullpath;
99 }
100
101 /*
102         SourceShaderCache: A cache used for storing source shaders.
103 */
104
105 class SourceShaderCache
106 {
107 public:
108         void insert(const std::string &name_of_shader, const std::string &filename,
109                 const std::string &program, bool prefer_local)
110         {
111                 std::string combined = name_of_shader + DIR_DELIM + filename;
112                 // Try to use local shader instead if asked to
113                 if(prefer_local){
114                         std::string path = getShaderPath(name_of_shader, filename);
115                         if(!path.empty()){
116                                 std::string p = readFile(path);
117                                 if (!p.empty()) {
118                                         m_programs[combined] = p;
119                                         return;
120                                 }
121                         }
122                 }
123                 m_programs[combined] = program;
124         }
125
126         std::string get(const std::string &name_of_shader,
127                 const std::string &filename)
128         {
129                 std::string combined = name_of_shader + DIR_DELIM + filename;
130                 StringMap::iterator n = m_programs.find(combined);
131                 if (n != m_programs.end())
132                         return n->second;
133                 return "";
134         }
135
136         // Primarily fetches from cache, secondarily tries to read from filesystem
137         std::string getOrLoad(const std::string &name_of_shader,
138                 const std::string &filename)
139         {
140                 std::string combined = name_of_shader + DIR_DELIM + filename;
141                 StringMap::iterator n = m_programs.find(combined);
142                 if (n != m_programs.end())
143                         return n->second;
144                 std::string path = getShaderPath(name_of_shader, filename);
145                 if (path.empty()) {
146                         infostream << "SourceShaderCache::getOrLoad(): No path found for \""
147                                 << combined << "\"" << std::endl;
148                         return "";
149                 }
150                 infostream << "SourceShaderCache::getOrLoad(): Loading path \""
151                         << path << "\"" << std::endl;
152                 std::string p = readFile(path);
153                 if (!p.empty()) {
154                         m_programs[combined] = p;
155                         return p;
156                 }
157                 return "";
158         }
159 private:
160         StringMap m_programs;
161
162         std::string readFile(const std::string &path)
163         {
164                 std::ifstream is(path.c_str(), std::ios::binary);
165                 if(!is.is_open())
166                         return "";
167                 std::ostringstream tmp_os;
168                 tmp_os << is.rdbuf();
169                 return tmp_os.str();
170         }
171 };
172
173
174 /*
175         ShaderCallback: Sets constants that can be used in shaders
176 */
177
178 class ShaderCallback : public video::IShaderConstantSetCallBack
179 {
180         std::vector<std::unique_ptr<IShaderConstantSetter>> m_setters;
181
182 public:
183         template <typename Factories>
184         ShaderCallback(const Factories &factories)
185         {
186                 for (auto &&factory : factories)
187                         m_setters.emplace_back(factory->create());
188         }
189
190         virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
191         {
192                 video::IVideoDriver *driver = services->getVideoDriver();
193                 sanity_check(driver != NULL);
194
195                 for (auto &&setter : m_setters)
196                         setter->onSetConstants(services);
197         }
198
199         virtual void OnSetMaterial(const video::SMaterial& material) override
200         {
201                 for (auto &&setter : m_setters)
202                         setter->onSetMaterial(material);
203         }
204 };
205
206
207 /*
208         MainShaderConstantSetter: Set basic constants required for almost everything
209 */
210
211 class MainShaderConstantSetter : public IShaderConstantSetter
212 {
213         CachedVertexShaderSetting<f32, 16> m_world_view_proj;
214         CachedVertexShaderSetting<f32, 16> m_world;
215
216         // Shadow-related
217         CachedPixelShaderSetting<f32, 16> m_shadow_view_proj;
218         CachedPixelShaderSetting<f32, 3> m_light_direction;
219         CachedPixelShaderSetting<f32> m_texture_res;
220         CachedPixelShaderSetting<f32> m_shadow_strength;
221         CachedPixelShaderSetting<f32> m_time_of_day;
222         CachedPixelShaderSetting<f32> m_shadowfar;
223         CachedPixelShaderSetting<f32, 4> m_camera_pos;
224         CachedPixelShaderSetting<s32> m_shadow_texture;
225         CachedVertexShaderSetting<f32> m_perspective_bias0_vertex;
226         CachedPixelShaderSetting<f32> m_perspective_bias0_pixel;
227         CachedVertexShaderSetting<f32> m_perspective_bias1_vertex;
228         CachedPixelShaderSetting<f32> m_perspective_bias1_pixel;
229         CachedVertexShaderSetting<f32> m_perspective_zbias_vertex;
230         CachedPixelShaderSetting<f32> m_perspective_zbias_pixel;
231
232 #if ENABLE_GLES
233         // Modelview matrix
234         CachedVertexShaderSetting<float, 16> m_world_view;
235         // Texture matrix
236         CachedVertexShaderSetting<float, 16> m_texture;
237         // Normal matrix
238         CachedVertexShaderSetting<float, 9> m_normal;
239 #endif
240
241 public:
242         MainShaderConstantSetter() :
243                   m_world_view_proj("mWorldViewProj")
244                 , m_world("mWorld")
245                 , m_shadow_view_proj("m_ShadowViewProj")
246                 , m_light_direction("v_LightDirection")
247                 , m_texture_res("f_textureresolution")
248                 , m_shadow_strength("f_shadow_strength")
249                 , m_time_of_day("f_timeofday")
250                 , m_shadowfar("f_shadowfar")
251                 , m_camera_pos("CameraPos")
252                 , m_shadow_texture("ShadowMapSampler")
253                 , m_perspective_bias0_vertex("xyPerspectiveBias0")
254                 , m_perspective_bias0_pixel("xyPerspectiveBias0")
255                 , m_perspective_bias1_vertex("xyPerspectiveBias1")
256                 , m_perspective_bias1_pixel("xyPerspectiveBias1")
257                 , m_perspective_zbias_vertex("zPerspectiveBias")
258                 , m_perspective_zbias_pixel("zPerspectiveBias")
259 #if ENABLE_GLES
260                 , m_world_view("mWorldView")
261                 , m_texture("mTexture")
262                 , m_normal("mNormal")
263 #endif
264         {}
265         ~MainShaderConstantSetter() = default;
266
267         virtual void onSetConstants(video::IMaterialRendererServices *services) override
268         {
269                 video::IVideoDriver *driver = services->getVideoDriver();
270                 sanity_check(driver);
271
272                 // Set world matrix
273                 core::matrix4 world = driver->getTransform(video::ETS_WORLD);
274                 m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
275
276                 // Set clip matrix
277                 core::matrix4 worldView;
278                 worldView = driver->getTransform(video::ETS_VIEW);
279                 worldView *= world;
280
281                 core::matrix4 worldViewProj;
282                 worldViewProj = driver->getTransform(video::ETS_PROJECTION);
283                 worldViewProj *= worldView;
284                 m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
285
286 #if ENABLE_GLES
287                 core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
288                 m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
289                 m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
290
291                 core::matrix4 normal;
292                 worldView.getTransposed(normal);
293                 sanity_check(normal.makeInverse());
294                 float m[9] = {
295                         normal[0], normal[1], normal[2],
296                         normal[4], normal[5], normal[6],
297                         normal[8], normal[9], normal[10],
298                 };
299                 m_normal.set(m, services);
300 #endif
301
302                 // Set uniforms for Shadow shader
303                 if (ShadowRenderer *shadow = RenderingEngine::get_shadow_renderer()) {
304                         const auto &light = shadow->getDirectionalLight();
305
306                         core::matrix4 shadowViewProj = light.getProjectionMatrix();
307                         shadowViewProj *= light.getViewMatrix();
308                         m_shadow_view_proj.set(shadowViewProj.pointer(), services);
309
310                         f32 v_LightDirection[3];
311                         light.getDirection().getAs3Values(v_LightDirection);
312                         m_light_direction.set(v_LightDirection, services);
313
314                         f32 TextureResolution = light.getMapResolution();
315                         m_texture_res.set(&TextureResolution, services);
316
317                         f32 ShadowStrength = shadow->getShadowStrength();
318                         m_shadow_strength.set(&ShadowStrength, services);
319
320                         f32 timeOfDay = shadow->getTimeOfDay();
321                         m_time_of_day.set(&timeOfDay, services);
322
323                         f32 shadowFar = shadow->getMaxShadowFar();
324                         m_shadowfar.set(&shadowFar, services);
325
326                         f32 cam_pos[4];
327                         shadowViewProj.transformVect(cam_pos, light.getPlayerPos());
328                         m_camera_pos.set(cam_pos, services);
329
330                         // I don't like using this hardcoded value. maybe something like
331                         // MAX_TEXTURE - 1 or somthing like that??
332                         s32 TextureLayerID = 3;
333                         m_shadow_texture.set(&TextureLayerID, services);
334
335                         f32 bias0 = shadow->getPerspectiveBiasXY();
336                         m_perspective_bias0_vertex.set(&bias0, services);
337                         m_perspective_bias0_pixel.set(&bias0, services);
338                         f32 bias1 = 1.0f - bias0 + 1e-5f;
339                         m_perspective_bias1_vertex.set(&bias1, services);
340                         m_perspective_bias1_pixel.set(&bias1, services);
341                         f32 zbias = shadow->getPerspectiveBiasZ();
342                         m_perspective_zbias_vertex.set(&zbias, services);
343                         m_perspective_zbias_pixel.set(&zbias, services);
344                 }
345         }
346 };
347
348
349 class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
350 {
351 public:
352         virtual IShaderConstantSetter* create()
353                 { return new MainShaderConstantSetter(); }
354 };
355
356
357 /*
358         ShaderSource
359 */
360
361 class ShaderSource : public IWritableShaderSource
362 {
363 public:
364         ShaderSource();
365
366         /*
367                 - If shader material specified by name is found from cache,
368                   return the cached id.
369                 - Otherwise generate the shader material, add to cache and return id.
370
371                 The id 0 points to a null shader. Its material is EMT_SOLID.
372         */
373         u32 getShaderIdDirect(const std::string &name,
374                 MaterialType material_type, NodeDrawType drawtype) override;
375
376         /*
377                 If shader specified by the name pointed by the id doesn't
378                 exist, create it, then return id.
379
380                 Can be called from any thread. If called from some other thread
381                 and not found in cache, the call is queued to the main thread
382                 for processing.
383         */
384
385         u32 getShader(const std::string &name,
386                 MaterialType material_type, NodeDrawType drawtype) override;
387
388         ShaderInfo getShaderInfo(u32 id) override;
389
390         // Processes queued shader requests from other threads.
391         // Shall be called from the main thread.
392         void processQueue() override;
393
394         // Insert a shader program into the cache without touching the
395         // filesystem. Shall be called from the main thread.
396         void insertSourceShader(const std::string &name_of_shader,
397                 const std::string &filename, const std::string &program) override;
398
399         // Rebuild shaders from the current set of source shaders
400         // Shall be called from the main thread.
401         void rebuildShaders() override;
402
403         void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) override
404         {
405                 m_setter_factories.emplace_back(setter);
406         }
407
408 private:
409
410         // The id of the thread that is allowed to use irrlicht directly
411         std::thread::id m_main_thread;
412
413         // Cache of source shaders
414         // This should be only accessed from the main thread
415         SourceShaderCache m_sourcecache;
416
417         // A shader id is index in this array.
418         // The first position contains a dummy shader.
419         std::vector<ShaderInfo> m_shaderinfo_cache;
420         // The former container is behind this mutex
421         std::mutex m_shaderinfo_cache_mutex;
422
423         // Queued shader fetches (to be processed by the main thread)
424         RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
425
426         // Global constant setter factories
427         std::vector<std::unique_ptr<IShaderConstantSetterFactory>> m_setter_factories;
428
429         // Generate shader given the shader name.
430         ShaderInfo generateShader(const std::string &name,
431                         MaterialType material_type, NodeDrawType drawtype);
432 };
433
434 IWritableShaderSource *createShaderSource()
435 {
436         return new ShaderSource();
437 }
438
439 ShaderSource::ShaderSource()
440 {
441         m_main_thread = std::this_thread::get_id();
442
443         // Add a dummy ShaderInfo as the first index, named ""
444         m_shaderinfo_cache.emplace_back();
445
446         // Add main global constant setter
447         addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
448 }
449
450 u32 ShaderSource::getShader(const std::string &name,
451                 MaterialType material_type, NodeDrawType drawtype)
452 {
453         /*
454                 Get shader
455         */
456
457         if (std::this_thread::get_id() == m_main_thread) {
458                 return getShaderIdDirect(name, material_type, drawtype);
459         }
460
461         /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
462
463         // We're gonna ask the result to be put into here
464
465         static ResultQueue<std::string, u32, u8, u8> result_queue;
466
467         // Throw a request in
468         m_get_shader_queue.add(name, 0, 0, &result_queue);
469
470         /* infostream<<"Waiting for shader from main thread, name=\""
471                         <<name<<"\""<<std::endl;*/
472
473         while(true) {
474                 GetResult<std::string, u32, u8, u8>
475                         result = result_queue.pop_frontNoEx();
476
477                 if (result.key == name) {
478                         return result.item;
479                 }
480
481                 errorstream << "Got shader with invalid name: " << result.key << std::endl;
482         }
483
484         infostream << "getShader(): Failed" << std::endl;
485
486         return 0;
487 }
488
489 /*
490         This method generates all the shaders
491 */
492 u32 ShaderSource::getShaderIdDirect(const std::string &name,
493                 MaterialType material_type, NodeDrawType drawtype)
494 {
495         //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
496
497         // Empty name means shader 0
498         if (name.empty()) {
499                 infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
500                 return 0;
501         }
502
503         // Check if already have such instance
504         for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
505                 ShaderInfo *info = &m_shaderinfo_cache[i];
506                 if(info->name == name && info->material_type == material_type &&
507                         info->drawtype == drawtype)
508                         return i;
509         }
510
511         /*
512                 Calling only allowed from main thread
513         */
514         if (std::this_thread::get_id() != m_main_thread) {
515                 errorstream<<"ShaderSource::getShaderIdDirect() "
516                                 "called not from main thread"<<std::endl;
517                 return 0;
518         }
519
520         ShaderInfo info = generateShader(name, material_type, drawtype);
521
522         /*
523                 Add shader to caches (add dummy shaders too)
524         */
525
526         MutexAutoLock lock(m_shaderinfo_cache_mutex);
527
528         u32 id = m_shaderinfo_cache.size();
529         m_shaderinfo_cache.push_back(info);
530
531         infostream<<"getShaderIdDirect(): "
532                         <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;
533
534         return id;
535 }
536
537
538 ShaderInfo ShaderSource::getShaderInfo(u32 id)
539 {
540         MutexAutoLock lock(m_shaderinfo_cache_mutex);
541
542         if(id >= m_shaderinfo_cache.size())
543                 return ShaderInfo();
544
545         return m_shaderinfo_cache[id];
546 }
547
548 void ShaderSource::processQueue()
549 {
550
551
552 }
553
554 void ShaderSource::insertSourceShader(const std::string &name_of_shader,
555                 const std::string &filename, const std::string &program)
556 {
557         /*infostream<<"ShaderSource::insertSourceShader(): "
558                         "name_of_shader=\""<<name_of_shader<<"\", "
559                         "filename=\""<<filename<<"\""<<std::endl;*/
560
561         sanity_check(std::this_thread::get_id() == m_main_thread);
562
563         m_sourcecache.insert(name_of_shader, filename, program, true);
564 }
565
566 void ShaderSource::rebuildShaders()
567 {
568         MutexAutoLock lock(m_shaderinfo_cache_mutex);
569
570         /*// Oh well... just clear everything, they'll load sometime.
571         m_shaderinfo_cache.clear();
572         m_name_to_id.clear();*/
573
574         /*
575                 FIXME: Old shader materials can't be deleted in Irrlicht,
576                 or can they?
577                 (This would be nice to do in the destructor too)
578         */
579
580         // Recreate shaders
581         for (ShaderInfo &i : m_shaderinfo_cache) {
582                 ShaderInfo *info = &i;
583                 if (!info->name.empty()) {
584                         *info = generateShader(info->name, info->material_type, info->drawtype);
585                 }
586         }
587 }
588
589
590 ShaderInfo ShaderSource::generateShader(const std::string &name,
591                 MaterialType material_type, NodeDrawType drawtype)
592 {
593         ShaderInfo shaderinfo;
594         shaderinfo.name = name;
595         shaderinfo.material_type = material_type;
596         shaderinfo.drawtype = drawtype;
597         switch (material_type) {
598         case TILE_MATERIAL_OPAQUE:
599         case TILE_MATERIAL_LIQUID_OPAQUE:
600         case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
601                 shaderinfo.base_material = video::EMT_SOLID;
602                 break;
603         case TILE_MATERIAL_ALPHA:
604         case TILE_MATERIAL_PLAIN_ALPHA:
605         case TILE_MATERIAL_LIQUID_TRANSPARENT:
606         case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
607                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
608                 break;
609         case TILE_MATERIAL_BASIC:
610         case TILE_MATERIAL_PLAIN:
611         case TILE_MATERIAL_WAVING_LEAVES:
612         case TILE_MATERIAL_WAVING_PLANTS:
613         case TILE_MATERIAL_WAVING_LIQUID_BASIC:
614                 shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
615                 break;
616         }
617         shaderinfo.material = shaderinfo.base_material;
618
619         bool enable_shaders = g_settings->getBool("enable_shaders");
620         if (!enable_shaders)
621                 return shaderinfo;
622
623         video::IVideoDriver *driver = RenderingEngine::get_video_driver();
624         if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
625                 errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
626                 return shaderinfo;
627         }
628         video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
629
630         // Create shaders header
631         bool use_gles = false;
632 #if ENABLE_GLES
633         use_gles = driver->getDriverType() == video::EDT_OGLES2;
634 #endif
635         std::stringstream shaders_header;
636         shaders_header
637                 << std::noboolalpha
638                 << std::showpoint // for GLSL ES
639                 ;
640         std::string vertex_header, fragment_header, geometry_header;
641         if (use_gles) {
642                 shaders_header << R"(
643                         #version 100
644                 )";
645                 vertex_header = R"(
646                         precision mediump float;
647
648                         uniform highp mat4 mWorldView;
649                         uniform highp mat4 mWorldViewProj;
650                         uniform mediump mat4 mTexture;
651                         uniform mediump mat3 mNormal;
652
653                         attribute highp vec4 inVertexPosition;
654                         attribute lowp vec4 inVertexColor;
655                         attribute mediump vec4 inTexCoord0;
656                         attribute mediump vec3 inVertexNormal;
657                         attribute mediump vec4 inVertexTangent;
658                         attribute mediump vec4 inVertexBinormal;
659                 )";
660                 fragment_header = R"(
661                         precision mediump float;
662                 )";
663         } else {
664                 shaders_header << R"(
665                         #version 120
666                         #define lowp
667                         #define mediump
668                         #define highp
669                 )";
670                 vertex_header = R"(
671                         #define mWorldView gl_ModelViewMatrix
672                         #define mWorldViewProj gl_ModelViewProjectionMatrix
673                         #define mTexture (gl_TextureMatrix[0])
674                         #define mNormal gl_NormalMatrix
675
676                         #define inVertexPosition gl_Vertex
677                         #define inVertexColor gl_Color
678                         #define inTexCoord0 gl_MultiTexCoord0
679                         #define inVertexNormal gl_Normal
680                         #define inVertexTangent gl_MultiTexCoord1
681                         #define inVertexBinormal gl_MultiTexCoord2
682                 )";
683         }
684
685         // map legacy semantic texture names to texture identifiers
686         fragment_header += R"(
687                 #define baseTexture texture0
688                 #define normalTexture texture1
689                 #define textureFlags texture2
690         )";
691
692         // Since this is the first time we're using the GL bindings be extra careful.
693         // This should be removed before 5.6.0 or similar.
694         if (!GL.GetString) {
695                 errorstream << "OpenGL procedures were not loaded correctly, "
696                         "please open a bug report with details about your platform/OS." << std::endl;
697                 abort();
698         }
699
700         bool use_discard = use_gles;
701         // For renderers that should use discard instead of GL_ALPHA_TEST
702         const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));
703         if (strstr(renderer, "GC7000"))
704                 use_discard = true;
705         if (use_discard) {
706                 if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL)
707                         shaders_header << "#define USE_DISCARD 1\n";
708                 else if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF)
709                         shaders_header << "#define USE_DISCARD_REF 1\n";
710         }
711
712 #define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n"
713
714         PROVIDE(NDT_NORMAL);
715         PROVIDE(NDT_AIRLIKE);
716         PROVIDE(NDT_LIQUID);
717         PROVIDE(NDT_FLOWINGLIQUID);
718         PROVIDE(NDT_GLASSLIKE);
719         PROVIDE(NDT_ALLFACES);
720         PROVIDE(NDT_ALLFACES_OPTIONAL);
721         PROVIDE(NDT_TORCHLIKE);
722         PROVIDE(NDT_SIGNLIKE);
723         PROVIDE(NDT_PLANTLIKE);
724         PROVIDE(NDT_FENCELIKE);
725         PROVIDE(NDT_RAILLIKE);
726         PROVIDE(NDT_NODEBOX);
727         PROVIDE(NDT_GLASSLIKE_FRAMED);
728         PROVIDE(NDT_FIRELIKE);
729         PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL);
730         PROVIDE(NDT_PLANTLIKE_ROOTED);
731
732         PROVIDE(TILE_MATERIAL_BASIC);
733         PROVIDE(TILE_MATERIAL_ALPHA);
734         PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT);
735         PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE);
736         PROVIDE(TILE_MATERIAL_WAVING_LEAVES);
737         PROVIDE(TILE_MATERIAL_WAVING_PLANTS);
738         PROVIDE(TILE_MATERIAL_OPAQUE);
739         PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC);
740         PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
741         PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE);
742         PROVIDE(TILE_MATERIAL_PLAIN);
743         PROVIDE(TILE_MATERIAL_PLAIN_ALPHA);
744
745 #undef PROVIDE
746
747         shaders_header << "#define MATERIAL_TYPE " << (int)material_type << "\n";
748         shaders_header << "#define DRAW_TYPE " << (int)drawtype << "\n";
749
750         bool enable_waving_water = g_settings->getBool("enable_waving_water");
751         shaders_header << "#define ENABLE_WAVING_WATER " << enable_waving_water << "\n";
752         if (enable_waving_water) {
753                 shaders_header << "#define WATER_WAVE_HEIGHT " << g_settings->getFloat("water_wave_height") << "\n";
754                 shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n";
755                 shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n";
756         }
757
758         shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
759         shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
760         shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n";
761
762         shaders_header << "#define FOG_START " << core::clamp(g_settings->getFloat("fog_start"), 0.0f, 0.99f) << "\n";
763
764         if (g_settings->getBool("enable_dynamic_shadows")) {
765                 shaders_header << "#define ENABLE_DYNAMIC_SHADOWS 1\n";
766                 if (g_settings->getBool("shadow_map_color"))
767                         shaders_header << "#define COLORED_SHADOWS 1\n";
768
769                 if (g_settings->getBool("shadow_poisson_filter"))
770                         shaders_header << "#define POISSON_FILTER 1\n";
771
772                 s32 shadow_filter = g_settings->getS32("shadow_filters");
773                 shaders_header << "#define SHADOW_FILTER " << shadow_filter << "\n";
774
775                 float shadow_soft_radius = g_settings->getFloat("shadow_soft_radius");
776                 if (shadow_soft_radius < 1.0f)
777                         shadow_soft_radius = 1.0f;
778                 shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
779         }
780
781         if (g_settings->getBool("enable_bloom")) {
782                 shaders_header << "#define ENABLE_BLOOM 1\n";
783                 if (g_settings->getBool("enable_bloom_debug"))
784                         shaders_header << "#define ENABLE_BLOOM_DEBUG 1\n";
785         }
786
787         shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics
788
789         std::string common_header = shaders_header.str();
790
791         std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
792         std::string fragment_shader = m_sourcecache.getOrLoad(name, "opengl_fragment.glsl");
793         std::string geometry_shader = m_sourcecache.getOrLoad(name, "opengl_geometry.glsl");
794
795         vertex_shader = common_header + vertex_header + vertex_shader;
796         fragment_shader = common_header + fragment_header + fragment_shader;
797         const char *geometry_shader_ptr = nullptr; // optional
798         if (!geometry_shader.empty()) {
799                 geometry_shader = common_header + geometry_header + geometry_shader;
800                 geometry_shader_ptr = geometry_shader.c_str();
801         }
802
803         irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
804         infostream<<"Compiling high level shaders for "<<name<<std::endl;
805         s32 shadermat = gpu->addHighLevelShaderMaterial(
806                 vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
807                 fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
808                 geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
809                 cb.get(), shaderinfo.base_material,  1);
810         if (shadermat == -1) {
811                 errorstream<<"generate_shader(): "
812                                 "failed to generate \""<<name<<"\", "
813                                 "addHighLevelShaderMaterial failed."
814                                 <<std::endl;
815                 dumpShaderProgram(warningstream, "Vertex", vertex_shader);
816                 dumpShaderProgram(warningstream, "Fragment", fragment_shader);
817                 dumpShaderProgram(warningstream, "Geometry", geometry_shader);
818                 return shaderinfo;
819         }
820
821         // Apply the newly created material type
822         shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
823         return shaderinfo;
824 }
825
826 void dumpShaderProgram(std::ostream &output_stream,
827                 const std::string &program_type, const std::string &program)
828 {
829         output_stream << program_type << " shader program:" << std::endl <<
830                 "----------------------------------" << std::endl;
831         size_t pos = 0;
832         size_t prev = 0;
833         s16 line = 1;
834         while ((pos = program.find('\n', prev)) != std::string::npos) {
835                 output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
836                         std::endl;
837                 prev = pos + 1;
838         }
839         output_stream << line << ": " << program.substr(prev) << std::endl <<
840                 "End of " << program_type << " shader program." << std::endl <<
841                 " " << std::endl;
842 }