LCOV - code coverage report
Current view: top level - src - shader.cpp (source / functions) Hit Total Coverage
Test: report Lines: 275 359 76.6 %
Date: 2015-07-11 18:23:49 Functions: 28 33 84.8 %

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

Generated by: LCOV version 1.11