mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Change shaders to be defined by input constants rather than drawtype/material type
This commit is contained in:
parent
baa4c7cd21
commit
f3c2bbfb48
2 changed files with 127 additions and 89 deletions
|
@ -410,14 +410,13 @@ public:
|
||||||
~ShaderSource() override;
|
~ShaderSource() override;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- If shader material specified by name is found from cache,
|
- If shader material is found from cache, return the cached id.
|
||||||
return the cached id.
|
|
||||||
- Otherwise generate the shader material, add to cache and return id.
|
- Otherwise generate the shader material, add to cache and return id.
|
||||||
|
|
||||||
The id 0 points to a null shader. Its material is EMT_SOLID.
|
The id 0 points to a null shader. Its material is EMT_SOLID.
|
||||||
*/
|
*/
|
||||||
u32 getShaderIdDirect(const std::string &name,
|
u32 getShaderIdDirect(const std::string &name, const ShaderConstants &input_const,
|
||||||
MaterialType material_type, NodeDrawType drawtype);
|
video::E_MATERIAL_TYPE base_mat);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If shader specified by the name pointed by the id doesn't
|
If shader specified by the name pointed by the id doesn't
|
||||||
|
@ -427,19 +426,10 @@ public:
|
||||||
and not found in cache, the call is queued to the main thread
|
and not found in cache, the call is queued to the main thread
|
||||||
for processing.
|
for processing.
|
||||||
*/
|
*/
|
||||||
u32 getShader(const std::string &name,
|
u32 getShader(const std::string &name, const ShaderConstants &input_const,
|
||||||
MaterialType material_type, NodeDrawType drawtype) override;
|
video::E_MATERIAL_TYPE base_mat) override;
|
||||||
|
|
||||||
u32 getShaderRaw(const std::string &name, bool blendAlpha) override
|
const ShaderInfo &getShaderInfo(u32 id) override;
|
||||||
{
|
|
||||||
// TODO: the shader system should be refactored to be much more generic.
|
|
||||||
// Just let callers pass arbitrary constants, this would also deal with
|
|
||||||
// runtime changes cleanly.
|
|
||||||
return getShader(name, blendAlpha ? TILE_MATERIAL_ALPHA : TILE_MATERIAL_BASIC,
|
|
||||||
NodeDrawType_END);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderInfo getShaderInfo(u32 id) override;
|
|
||||||
|
|
||||||
// Processes queued shader requests from other threads.
|
// Processes queued shader requests from other threads.
|
||||||
// Shall be called from the main thread.
|
// Shall be called from the main thread.
|
||||||
|
@ -492,7 +482,16 @@ private:
|
||||||
|
|
||||||
// Generate shader given the shader name.
|
// Generate shader given the shader name.
|
||||||
ShaderInfo generateShader(const std::string &name,
|
ShaderInfo generateShader(const std::string &name,
|
||||||
MaterialType material_type, NodeDrawType drawtype);
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat);
|
||||||
|
|
||||||
|
/// @brief outputs a constant to an ostream
|
||||||
|
inline void putConstant(std::ostream &os, const ShaderConstants::mapped_type &it)
|
||||||
|
{
|
||||||
|
if (auto *ival = std::get_if<int>(&it); ival)
|
||||||
|
os << *ival;
|
||||||
|
else
|
||||||
|
os << std::get<float>(it);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IWritableShaderSource *createShaderSource()
|
IWritableShaderSource *createShaderSource()
|
||||||
|
@ -520,22 +519,27 @@ ShaderSource::~ShaderSource()
|
||||||
// Delete materials
|
// Delete materials
|
||||||
auto *gpu = RenderingEngine::get_video_driver()->getGPUProgrammingServices();
|
auto *gpu = RenderingEngine::get_video_driver()->getGPUProgrammingServices();
|
||||||
assert(gpu);
|
assert(gpu);
|
||||||
|
u32 n = 0;
|
||||||
for (ShaderInfo &i : m_shaderinfo_cache) {
|
for (ShaderInfo &i : m_shaderinfo_cache) {
|
||||||
if (!i.name.empty())
|
if (!i.name.empty()) {
|
||||||
gpu->deleteShaderMaterial(i.material);
|
gpu->deleteShaderMaterial(i.material);
|
||||||
|
n++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_shaderinfo_cache.clear();
|
m_shaderinfo_cache.clear();
|
||||||
|
|
||||||
|
infostream << "~ShaderSource() cleaned up " << n << " materials" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ShaderSource::getShader(const std::string &name,
|
u32 ShaderSource::getShader(const std::string &name,
|
||||||
MaterialType material_type, NodeDrawType drawtype)
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Get shader
|
Get shader
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (std::this_thread::get_id() == m_main_thread) {
|
if (std::this_thread::get_id() == m_main_thread) {
|
||||||
return getShaderIdDirect(name, material_type, drawtype);
|
return getShaderIdDirect(name, input_const, base_mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
errorstream << "ShaderSource::getShader(): getting from "
|
errorstream << "ShaderSource::getShader(): getting from "
|
||||||
|
@ -573,7 +577,7 @@ u32 ShaderSource::getShader(const std::string &name,
|
||||||
This method generates all the shaders
|
This method generates all the shaders
|
||||||
*/
|
*/
|
||||||
u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
||||||
MaterialType material_type, NodeDrawType drawtype)
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat)
|
||||||
{
|
{
|
||||||
// Empty name means shader 0
|
// Empty name means shader 0
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
|
@ -582,10 +586,10 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if already have such instance
|
// Check if already have such instance
|
||||||
for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
|
for (u32 i = 0; i < m_shaderinfo_cache.size(); i++) {
|
||||||
ShaderInfo *info = &m_shaderinfo_cache[i];
|
auto &info = m_shaderinfo_cache[i];
|
||||||
if(info->name == name && info->material_type == material_type &&
|
if (info.name == name && info.base_material == base_mat &&
|
||||||
info->drawtype == drawtype)
|
info.input_constants == input_const)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +602,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderInfo info = generateShader(name, material_type, drawtype);
|
ShaderInfo info = generateShader(name, input_const, base_mat);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Add shader to caches (add dummy shaders too)
|
Add shader to caches (add dummy shaders too)
|
||||||
|
@ -607,19 +611,19 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
|
||||||
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||||
|
|
||||||
u32 id = m_shaderinfo_cache.size();
|
u32 id = m_shaderinfo_cache.size();
|
||||||
m_shaderinfo_cache.push_back(info);
|
m_shaderinfo_cache.push_back(std::move(info));
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ShaderInfo ShaderSource::getShaderInfo(u32 id)
|
const ShaderInfo &ShaderSource::getShaderInfo(u32 id)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
MutexAutoLock lock(m_shaderinfo_cache_mutex);
|
||||||
|
|
||||||
if(id >= m_shaderinfo_cache.size())
|
if (id >= m_shaderinfo_cache.size()) {
|
||||||
return ShaderInfo();
|
static ShaderInfo empty;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
return m_shaderinfo_cache[id];
|
return m_shaderinfo_cache[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,46 +659,31 @@ void ShaderSource::rebuildShaders()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infostream << "ShaderSource: recreating " << m_shaderinfo_cache.size()
|
||||||
|
<< " shaders" << std::endl;
|
||||||
|
|
||||||
// Recreate shaders
|
// Recreate shaders
|
||||||
for (ShaderInfo &i : m_shaderinfo_cache) {
|
for (ShaderInfo &i : m_shaderinfo_cache) {
|
||||||
ShaderInfo *info = &i;
|
ShaderInfo *info = &i;
|
||||||
if (!info->name.empty()) {
|
if (!info->name.empty()) {
|
||||||
*info = generateShader(info->name, info->material_type, info->drawtype);
|
*info = generateShader(info->name, info->input_constants, info->base_material);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ShaderInfo ShaderSource::generateShader(const std::string &name,
|
ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||||
MaterialType material_type, NodeDrawType drawtype)
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat)
|
||||||
{
|
{
|
||||||
ShaderInfo shaderinfo;
|
ShaderInfo shaderinfo;
|
||||||
shaderinfo.name = name;
|
shaderinfo.name = name;
|
||||||
shaderinfo.material_type = material_type;
|
shaderinfo.input_constants = input_const;
|
||||||
shaderinfo.drawtype = drawtype;
|
// fixed pipeline materials don't make sense here
|
||||||
switch (material_type) {
|
assert(base_mat != video::EMT_TRANSPARENT_VERTEX_ALPHA && base_mat != video::EMT_ONETEXTURE_BLEND);
|
||||||
case TILE_MATERIAL_OPAQUE:
|
shaderinfo.base_material = base_mat;
|
||||||
case TILE_MATERIAL_LIQUID_OPAQUE:
|
|
||||||
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
|
|
||||||
shaderinfo.base_material = video::EMT_SOLID;
|
|
||||||
break;
|
|
||||||
case TILE_MATERIAL_ALPHA:
|
|
||||||
case TILE_MATERIAL_PLAIN_ALPHA:
|
|
||||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
|
||||||
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
|
||||||
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
|
||||||
break;
|
|
||||||
case TILE_MATERIAL_BASIC:
|
|
||||||
case TILE_MATERIAL_PLAIN:
|
|
||||||
case TILE_MATERIAL_WAVING_LEAVES:
|
|
||||||
case TILE_MATERIAL_WAVING_PLANTS:
|
|
||||||
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
|
|
||||||
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shaderinfo.material = shaderinfo.base_material;
|
shaderinfo.material = shaderinfo.base_material;
|
||||||
|
|
||||||
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
|
auto *driver = RenderingEngine::get_video_driver();
|
||||||
// The null driver doesn't support shaders (duh), but we can pretend it does.
|
// The null driver doesn't support shaders (duh), but we can pretend it does.
|
||||||
if (driver->getDriverType() == video::EDT_NULL)
|
if (driver->getDriverType() == video::EDT_NULL)
|
||||||
return shaderinfo;
|
return shaderinfo;
|
||||||
|
@ -770,18 +759,18 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||||
|
|
||||||
/// Unique name of this shader, for debug/logging
|
/// Unique name of this shader, for debug/logging
|
||||||
std::string log_name = name;
|
std::string log_name = name;
|
||||||
|
for (auto &it : input_const) {
|
||||||
ShaderConstants constants;
|
if (log_name.size() > 60) { // it shouldn't be too long
|
||||||
|
log_name.append("...");
|
||||||
// Temporary plumbing <-> NodeShaderConstantSetter
|
break;
|
||||||
if (drawtype != NodeDrawType_END) {
|
}
|
||||||
constants["DRAWTYPE"] = (int)drawtype;
|
std::ostringstream oss;
|
||||||
constants["MATERIAL_TYPE"] = (int)material_type;
|
putConstant(oss, it.second);
|
||||||
|
log_name.append(" ").append(it.first).append("=").append(oss.str());
|
||||||
log_name.append(" mat=").append(itos(material_type))
|
|
||||||
.append(" draw=").append(itos(drawtype));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderConstants constants = input_const;
|
||||||
|
|
||||||
bool use_discard = fully_programmable;
|
bool use_discard = fully_programmable;
|
||||||
if (!use_discard) {
|
if (!use_discard) {
|
||||||
// workaround for a certain OpenGL implementation lacking GL_ALPHA_TEST
|
// workaround for a certain OpenGL implementation lacking GL_ALPHA_TEST
|
||||||
|
@ -805,10 +794,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||||
// spaces could cause duplicates
|
// spaces could cause duplicates
|
||||||
assert(trim(it.first) == it.first);
|
assert(trim(it.first) == it.first);
|
||||||
shaders_header << "#define " << it.first << ' ';
|
shaders_header << "#define " << it.first << ' ';
|
||||||
if (auto *ival = std::get_if<int>(&it.second); ival)
|
putConstant(shaders_header, it.second);
|
||||||
shaders_header << *ival;
|
|
||||||
else
|
|
||||||
shaders_header << std::get<float>(it.second);
|
|
||||||
shaders_header << '\n';
|
shaders_header << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,6 +835,39 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||||
return shaderinfo;
|
return shaderinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Other functions and helpers
|
||||||
|
*/
|
||||||
|
|
||||||
|
u32 IShaderSource::getShader(const std::string &name,
|
||||||
|
MaterialType material_type, NodeDrawType drawtype)
|
||||||
|
{
|
||||||
|
ShaderConstants input_const;
|
||||||
|
input_const["MATERIAL_TYPE"] = (int)material_type;
|
||||||
|
input_const["DRAWTYPE"] = (int)drawtype;
|
||||||
|
|
||||||
|
video::E_MATERIAL_TYPE base_mat = video::EMT_SOLID;
|
||||||
|
switch (material_type) {
|
||||||
|
case TILE_MATERIAL_ALPHA:
|
||||||
|
case TILE_MATERIAL_PLAIN_ALPHA:
|
||||||
|
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||||
|
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
||||||
|
base_mat = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||||
|
break;
|
||||||
|
case TILE_MATERIAL_BASIC:
|
||||||
|
case TILE_MATERIAL_PLAIN:
|
||||||
|
case TILE_MATERIAL_WAVING_LEAVES:
|
||||||
|
case TILE_MATERIAL_WAVING_PLANTS:
|
||||||
|
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
|
||||||
|
base_mat = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getShader(name, input_const, base_mat);
|
||||||
|
}
|
||||||
|
|
||||||
void dumpShaderProgram(std::ostream &output_stream,
|
void dumpShaderProgram(std::ostream &output_stream,
|
||||||
const std::string &program_type, std::string_view program)
|
const std::string &program_type, std::string_view program)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,17 +28,6 @@
|
||||||
std::string getShaderPath(const std::string &name_of_shader,
|
std::string getShaderPath(const std::string &name_of_shader,
|
||||||
const std::string &filename);
|
const std::string &filename);
|
||||||
|
|
||||||
struct ShaderInfo {
|
|
||||||
std::string name = "";
|
|
||||||
video::E_MATERIAL_TYPE base_material = video::EMT_SOLID;
|
|
||||||
video::E_MATERIAL_TYPE material = video::EMT_SOLID;
|
|
||||||
NodeDrawType drawtype = NDT_NORMAL;
|
|
||||||
MaterialType material_type = TILE_MATERIAL_BASIC;
|
|
||||||
|
|
||||||
ShaderInfo() = default;
|
|
||||||
virtual ~ShaderInfo() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Abstraction for pushing constants (or what we pretend is) into
|
Abstraction for pushing constants (or what we pretend is) into
|
||||||
shaders. These end up as `#define` prepended to the shader source.
|
shaders. These end up as `#define` prepended to the shader source.
|
||||||
|
@ -218,7 +207,18 @@ using CachedStructPixelShaderSetting = CachedStructShaderSetting<T, count, cache
|
||||||
|
|
||||||
A "shader" could more precisely be called a "shader material" and comprises
|
A "shader" could more precisely be called a "shader material" and comprises
|
||||||
a vertex, fragment and optional geometry shader.
|
a vertex, fragment and optional geometry shader.
|
||||||
|
It is uniquely identified by a name, base material and the input constants.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct ShaderInfo {
|
||||||
|
std::string name;
|
||||||
|
video::E_MATERIAL_TYPE base_material = video::EMT_SOLID;
|
||||||
|
// Material ID the shader has received from Irrlicht
|
||||||
|
video::E_MATERIAL_TYPE material = video::EMT_SOLID;
|
||||||
|
// Input constants
|
||||||
|
ShaderConstants input_constants;
|
||||||
|
};
|
||||||
|
|
||||||
class IShaderSource {
|
class IShaderSource {
|
||||||
public:
|
public:
|
||||||
IShaderSource() = default;
|
IShaderSource() = default;
|
||||||
|
@ -229,19 +229,38 @@ public:
|
||||||
*
|
*
|
||||||
* Use this to get the material ID to plug into `video::SMaterial`.
|
* Use this to get the material ID to plug into `video::SMaterial`.
|
||||||
*/
|
*/
|
||||||
virtual ShaderInfo getShaderInfo(u32 id) = 0;
|
virtual const ShaderInfo &getShaderInfo(u32 id) = 0;
|
||||||
|
|
||||||
/// @brief Generates or gets a shader suitable for nodes and entities
|
|
||||||
virtual u32 getShader(const std::string &name,
|
|
||||||
MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates or gets a shader for general use.
|
* Generates or gets a shader.
|
||||||
|
*
|
||||||
|
* Note that the input constants are not for passing the entire world into
|
||||||
|
* the shader. Use `IShaderConstantSetter` to handle user settings.
|
||||||
* @param name name of the shader (directory on disk)
|
* @param name name of the shader (directory on disk)
|
||||||
|
* @param input_const primary key constants for this shader
|
||||||
|
* @param base_mat base material to use
|
||||||
|
* @return shader ID
|
||||||
|
* @note `base_material` only controls alpha behavior
|
||||||
|
*/
|
||||||
|
virtual u32 getShader(const std::string &name,
|
||||||
|
const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat) = 0;
|
||||||
|
|
||||||
|
/// @brief Helper: Generates or gets a shader suitable for nodes and entities
|
||||||
|
u32 getShader(const std::string &name,
|
||||||
|
MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper: Generates or gets a shader for common, general use.
|
||||||
|
* @param name name of the shader
|
||||||
* @param blendAlpha enable alpha blending for this material?
|
* @param blendAlpha enable alpha blending for this material?
|
||||||
* @return shader ID
|
* @return shader ID
|
||||||
*/
|
*/
|
||||||
virtual u32 getShaderRaw(const std::string &name, bool blendAlpha = false) = 0;
|
inline u32 getShaderRaw(const std::string &name, bool blendAlpha = false)
|
||||||
|
{
|
||||||
|
auto base_mat = blendAlpha ? video::EMT_TRANSPARENT_ALPHA_CHANNEL :
|
||||||
|
video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||||
|
return getShader(name, ShaderConstants(), base_mat);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class IWritableShaderSource : public IShaderSource {
|
class IWritableShaderSource : public IShaderSource {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue