X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fshader.cpp;h=3b49a36bad48c25f6753e1f0bb61a9314c6dd010;hb=c6975febbab02db306329a93d4ccc3249df209e3;hp=917d878bb213b510f7564ab9de68092857f97ee8;hpb=6be74d17df75714066b36cfa6ae40081526ef477;p=minetest.git diff --git a/src/shader.cpp b/src/shader.cpp index 917d878bb..3b49a36ba 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -32,10 +32,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "client/renderingengine.h" #include "EShaderTypes.h" #include "log.h" #include "gamedef.h" -#include "strfnd.h" // trim() #include "client/tile.h" /* @@ -56,7 +56,7 @@ std::string getShaderPath(const std::string &name_of_shader, const std::string &filename) { std::string combined = name_of_shader + DIR_DELIM + filename; - std::string fullpath = ""; + std::string fullpath; /* Check from cache */ @@ -68,8 +68,7 @@ std::string getShaderPath(const std::string &name_of_shader, Check from shader_path */ std::string shader_path = g_settings->get("shader_path"); - if(shader_path != "") - { + if (!shader_path.empty()) { std::string testpath = shader_path + DIR_DELIM + combined; if(fs::PathExists(testpath)) fullpath = testpath; @@ -78,8 +77,7 @@ std::string getShaderPath(const std::string &name_of_shader, /* Check from default data directory */ - if(fullpath == "") - { + if (fullpath.empty()) { std::string rel_path = std::string("client") + DIR_DELIM + "shaders" + DIR_DELIM + name_of_shader + DIR_DELIM @@ -110,9 +108,9 @@ class SourceShaderCache // Try to use local shader instead if asked to if(prefer_local){ std::string path = getShaderPath(name_of_shader, filename); - if(path != ""){ + if(!path.empty()){ std::string p = readFile(path); - if(p != ""){ + if (!p.empty()) { m_programs[combined] = p; return; } @@ -140,7 +138,7 @@ class SourceShaderCache if (n != m_programs.end()) return n->second; std::string path = getShaderPath(name_of_shader, filename); - if (path == "") { + if (path.empty()) { infostream << "SourceShaderCache::getOrLoad(): No path found for \"" << combined << "\"" << std::endl; return ""; @@ -148,7 +146,7 @@ class SourceShaderCache infostream << "SourceShaderCache::getOrLoad(): Loading path \"" << path << "\"" << std::endl; std::string p = readFile(path); - if (p != "") { + if (!p.empty()) { m_programs[combined] = p; return p; } @@ -168,29 +166,27 @@ class SourceShaderCache } }; + /* ShaderCallback: Sets constants that can be used in shaders */ -class IShaderConstantSetterRegistry -{ -public: - virtual ~IShaderConstantSetterRegistry(){}; - virtual void onSetConstants(video::IMaterialRendererServices *services, - bool is_highlevel, const std::string &name) = 0; -}; - class ShaderCallback : public video::IShaderConstantSetCallBack { - IShaderConstantSetterRegistry *m_scsr; - std::string m_name; + std::vector m_setters; public: - ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name): - m_scsr(scsr), - m_name(name) - {} - ~ShaderCallback() {} + ShaderCallback(const std::vector &factories) + { + for (IShaderConstantSetterFactory *factory : factories) + m_setters.push_back(factory->create()); + } + + ~ShaderCallback() + { + for (IShaderConstantSetter *setter : m_setters) + delete setter; + } virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) { @@ -199,20 +195,27 @@ class ShaderCallback : public video::IShaderConstantSetCallBack bool is_highlevel = userData; - m_scsr->onSetConstants(services, is_highlevel, m_name); + for (IShaderConstantSetter *setter : m_setters) + setter->onSetConstants(services, is_highlevel); } }; + /* MainShaderConstantSetter: Set basic constants required for almost everything */ class MainShaderConstantSetter : public IShaderConstantSetter { + CachedVertexShaderSetting m_world_view_proj; + CachedVertexShaderSetting m_world; + public: - MainShaderConstantSetter(IrrlichtDevice *device) + MainShaderConstantSetter() : + m_world_view_proj("mWorldViewProj"), + m_world("mWorld") {} - ~MainShaderConstantSetter() {} + ~MainShaderConstantSetter() = default; virtual void onSetConstants(video::IMaterialRendererServices *services, bool is_highlevel) @@ -220,50 +223,43 @@ class MainShaderConstantSetter : public IShaderConstantSetter video::IVideoDriver *driver = services->getVideoDriver(); sanity_check(driver); - // set inverted world matrix - core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD); - invWorld.makeInverse(); - if(is_highlevel) - services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16); - else - services->setVertexShaderConstant(invWorld.pointer(), 0, 4); - - // set clip matrix + // Set clip matrix core::matrix4 worldViewProj; worldViewProj = driver->getTransform(video::ETS_PROJECTION); worldViewProj *= driver->getTransform(video::ETS_VIEW); worldViewProj *= driver->getTransform(video::ETS_WORLD); - if(is_highlevel) - services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16); - else - services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4); - - // set transposed world matrix - core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD); - transWorld = transWorld.getTransposed(); - if(is_highlevel) - services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16); + if (is_highlevel) + m_world_view_proj.set(*reinterpret_cast(worldViewProj.pointer()), services); else - services->setVertexShaderConstant(transWorld.pointer(), 8, 4); + services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4); - // set world matrix + // Set world matrix core::matrix4 world = driver->getTransform(video::ETS_WORLD); - if(is_highlevel) - services->setVertexShaderConstant("mWorld", world.pointer(), 16); + if (is_highlevel) + m_world.set(*reinterpret_cast(world.pointer()), services); else - services->setVertexShaderConstant(world.pointer(), 8, 4); + services->setVertexShaderConstant(world.pointer(), 4, 4); } }; + +class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory +{ +public: + virtual IShaderConstantSetter* create() + { return new MainShaderConstantSetter(); } +}; + + /* ShaderSource */ -class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry +class ShaderSource : public IWritableShaderSource { public: - ShaderSource(IrrlichtDevice *device); + ShaderSource(); ~ShaderSource(); /* @@ -303,22 +299,15 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR // Shall be called from the main thread. void rebuildShaders(); - void addGlobalConstantSetter(IShaderConstantSetter *setter) + void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) { - m_global_setters.push_back(setter); + m_setter_factories.push_back(setter); } - void onSetConstants(video::IMaterialRendererServices *services, - bool is_highlevel, const std::string &name); - private: // The id of the thread that is allowed to use irrlicht directly - threadid_t m_main_thread; - // The irrlicht device - IrrlichtDevice *m_device; - // The set-constants callback - ShaderCallback *m_shader_callback; + std::thread::id m_main_thread; // Cache of source shaders // This should be only accessed from the main thread @@ -328,65 +317,57 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR // The first position contains a dummy shader. std::vector m_shaderinfo_cache; // The former container is behind this mutex - Mutex m_shaderinfo_cache_mutex; + std::mutex m_shaderinfo_cache_mutex; // Queued shader fetches (to be processed by the main thread) RequestQueue m_get_shader_queue; - // Global constant setters - // TODO: Delete these in the destructor - std::vector m_global_setters; + // Global constant setter factories + std::vector m_setter_factories; + + // Shader callbacks + std::vector m_callbacks; }; -IWritableShaderSource* createShaderSource(IrrlichtDevice *device) +IWritableShaderSource *createShaderSource() { - return new ShaderSource(device); + return new ShaderSource(); } /* Generate shader given the shader name. */ -ShaderInfo generate_shader(std::string name, - u8 material_type, u8 drawtype, - IrrlichtDevice *device, - video::IShaderConstantSetCallBack *callback, +ShaderInfo generate_shader(const std::string &name, + u8 material_type, u8 drawtype, std::vector &callbacks, + const std::vector &setter_factories, SourceShaderCache *sourcecache); /* Load shader programs */ -void load_shaders(std::string name, SourceShaderCache *sourcecache, +void load_shaders(const std::string &name, SourceShaderCache *sourcecache, video::E_DRIVER_TYPE drivertype, bool enable_shaders, std::string &vertex_program, std::string &pixel_program, std::string &geometry_program, bool &is_highlevel); -ShaderSource::ShaderSource(IrrlichtDevice *device): - m_device(device) +ShaderSource::ShaderSource() { - assert(m_device); // Pre-condition - - m_shader_callback = new ShaderCallback(this, "default"); - - m_main_thread = thr_get_current_thread_id(); + m_main_thread = std::this_thread::get_id(); // Add a dummy ShaderInfo as the first index, named "" - m_shaderinfo_cache.push_back(ShaderInfo()); + m_shaderinfo_cache.emplace_back(); // Add main global constant setter - addGlobalConstantSetter(new MainShaderConstantSetter(device)); + addShaderConstantSetterFactory(new MainShaderConstantSetterFactory()); } ShaderSource::~ShaderSource() { - for (std::vector::iterator iter = m_global_setters.begin(); - iter != m_global_setters.end(); ++iter) { - delete *iter; + for (ShaderCallback *callback : m_callbacks) { + delete callback; } - m_global_setters.clear(); - - if (m_shader_callback) { - m_shader_callback->drop(); - m_shader_callback = NULL; + for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) { + delete setter_factorie; } } @@ -397,36 +378,34 @@ u32 ShaderSource::getShader(const std::string &name, Get shader */ - if (thr_is_current_thread(m_main_thread)) { + if (std::this_thread::get_id() == m_main_thread) { return getShaderIdDirect(name, material_type, drawtype); - } else { - /*errorstream<<"getShader(): Queued: name=\""< result_queue; + // We're gonna ask the result to be put into here - // Throw a request in - m_get_shader_queue.add(name, 0, 0, &result_queue); + static ResultQueue result_queue; - /* infostream<<"Waiting for shader from main thread, name=\"" - < - result = result_queue.pop_frontNoEx(); + /* infostream<<"Waiting for shader from main thread, name=\"" + < + result = result_queue.pop_frontNoEx(); + + if (result.key == name) { + return result.item; } + errorstream << "Got shader with invalid name: " << result.key << std::endl; } - infostream<<"getShader(): Failed"<name != ""){ + for (ShaderInfo &i : m_shaderinfo_cache) { + ShaderInfo *info = &i; + if (!info->name.empty()) { *info = generate_shader(info->name, info->material_type, - info->drawtype, m_device, m_shader_callback, &m_sourcecache); + info->drawtype, m_callbacks, + m_setter_factories, &m_sourcecache); } } } -void ShaderSource::onSetConstants(video::IMaterialRendererServices *services, - bool is_highlevel, const std::string &name) -{ - for(u32 i=0; ionSetConstants(services, is_highlevel); - } -} -ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, - IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback, +ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype, + std::vector &callbacks, + const std::vector &setter_factories, SourceShaderCache *sourcecache) { ShaderInfo shaderinfo; @@ -551,33 +524,27 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, shaderinfo.material_type = material_type; shaderinfo.drawtype = drawtype; shaderinfo.material = video::EMT_SOLID; - switch(material_type){ - case TILE_MATERIAL_BASIC: - shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - break; - case TILE_MATERIAL_ALPHA: - shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - break; - case TILE_MATERIAL_LIQUID_TRANSPARENT: - shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA; - break; - case TILE_MATERIAL_LIQUID_OPAQUE: - shaderinfo.base_material = video::EMT_SOLID; - break; - case TILE_MATERIAL_WAVING_LEAVES: - shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - break; - case TILE_MATERIAL_WAVING_PLANTS: - shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + switch (material_type) { + case TILE_MATERIAL_OPAQUE: + case TILE_MATERIAL_LIQUID_OPAQUE: + shaderinfo.base_material = video::EMT_SOLID; + break; + case TILE_MATERIAL_ALPHA: + case TILE_MATERIAL_LIQUID_TRANSPARENT: + shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + break; + case TILE_MATERIAL_BASIC: + case TILE_MATERIAL_WAVING_LEAVES: + case TILE_MATERIAL_WAVING_PLANTS: + shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; break; } bool enable_shaders = g_settings->getBool("enable_shaders"); - if(!enable_shaders) + if (!enable_shaders) return shaderinfo; - video::IVideoDriver* driver = device->getVideoDriver(); - sanity_check(driver); + video::IVideoDriver *driver = RenderingEngine::get_video_driver(); video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices(); if(!gpu){ @@ -598,7 +565,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, enable_shaders, vertex_program, pixel_program, geometry_program, is_highlevel); // Check hardware/driver support - if(vertex_program != "" && + if (!vertex_program.empty() && !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) && !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){ infostream<<"generate_shader(): vertex shaders disabled " @@ -606,7 +573,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, <queryFeature(video::EVDF_PIXEL_SHADER_1_1) && !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){ infostream<<"generate_shader(): pixel shaders disabled " @@ -614,7 +581,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, <queryFeature(video::EVDF_GEOMETRY_SHADER)){ infostream<<"generate_shader(): geometry shaders disabled " "because of missing driver/hardware support." @@ -623,7 +590,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, } // If no shaders are used, don't make a separate material type - if(vertex_program == "" && pixel_program == "" && geometry_program == "") + if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty()) return shaderinfo; // Create shaders header @@ -645,7 +612,8 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, "NDT_NODEBOX", "NDT_GLASSLIKE_FRAMED", "NDT_FIRELIKE", - "NDT_GLASSLIKE_FRAMED_OPTIONAL" + "NDT_GLASSLIKE_FRAMED_OPTIONAL", + "NDT_PLANTLIKE_ROOTED", }; for (int i = 0; i < 14; i++){ @@ -662,10 +630,11 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, "TILE_MATERIAL_LIQUID_TRANSPARENT", "TILE_MATERIAL_LIQUID_OPAQUE", "TILE_MATERIAL_WAVING_LEAVES", - "TILE_MATERIAL_WAVING_PLANTS" + "TILE_MATERIAL_WAVING_PLANTS", + "TILE_MATERIAL_OPAQUE" }; - for (int i = 0; i < 6; i++){ + for (int i = 0; i < 7; i++){ shaders_header += "#define "; shaders_header += materialTypes[i]; shaders_header += " "; @@ -764,22 +733,30 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, else shaders_header += "0\n"; - if(pixel_program != "") - pixel_program = shaders_header + pixel_program; - if(vertex_program != "") - vertex_program = shaders_header + vertex_program; - if(geometry_program != "") - geometry_program = shaders_header + geometry_program; + if (g_settings->getBool("tone_mapping")) + shaders_header += "#define ENABLE_TONE_MAPPING\n"; + + shaders_header += "#define FOG_START "; + shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f)); + shaders_header += "\n"; + // Call addHighLevelShaderMaterial() or addShaderMaterial() const c8* vertex_program_ptr = 0; const c8* pixel_program_ptr = 0; const c8* geometry_program_ptr = 0; - if(vertex_program != "") + if (!vertex_program.empty()) { + vertex_program = shaders_header + vertex_program; vertex_program_ptr = vertex_program.c_str(); - if(pixel_program != "") + } + if (!pixel_program.empty()) { + pixel_program = shaders_header + pixel_program; pixel_program_ptr = pixel_program.c_str(); - if(geometry_program != "") + } + if (!geometry_program.empty()) { + geometry_program = shaders_header + geometry_program; geometry_program_ptr = geometry_program.c_str(); + } + ShaderCallback *cb = new ShaderCallback(setter_factories); s32 shadermat = -1; if(is_highlevel){ infostream<<"Compiling high level shaders for "<addShaderMaterial( vertex_program_ptr, // Vertex shader program pixel_program_ptr, // Pixel shader program - callback, // Set-constant callback + cb, // Set-constant callback shaderinfo.base_material, // Base material 0 // Userdata passed to callback ); @@ -823,9 +804,13 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype, "failed to generate \""<getOrLoad(name, "opengl_fragment.glsl"); geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl"); } - if(vertex_program != "" || pixel_program != "" || geometry_program != ""){ + if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){ is_highlevel = true; return; } } } + +void dumpShaderProgram(std::ostream &output_stream, + const std::string &program_type, const std::string &program) +{ + output_stream << program_type << " shader program:" << std::endl << + "----------------------------------" << std::endl; + size_t pos = 0; + size_t prev = 0; + s16 line = 1; + while ((pos = program.find('\n', prev)) != std::string::npos) { + output_stream << line++ << ": "<< program.substr(prev, pos - prev) << + std::endl; + prev = pos + 1; + } + output_stream << line << ": " << program.substr(prev) << std::endl << + "End of " << program_type << " shader program." << std::endl << + " " << std::endl; +}