mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
204 lines
5.5 KiB
C++
204 lines
5.5 KiB
C++
/**
|
|
* Copyright (c) 2006-2020 LOVE Development Team
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
**/
|
|
|
|
// LOVE
|
|
#include "Shader.h"
|
|
#include "Graphics.h"
|
|
#include "math/MathModule.h"
|
|
|
|
// glslang
|
|
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
|
|
|
// C++
|
|
#include <string>
|
|
|
|
namespace love
|
|
{
|
|
namespace graphics
|
|
{
|
|
|
|
static_assert(sizeof(Shader::BuiltinUniformData) == sizeof(float) * 4 * 13, "Update the array in wrap_GraphicsShader.lua if this changes.");
|
|
|
|
love::Type Shader::type("Shader", &Object::type);
|
|
|
|
Shader *Shader::current = nullptr;
|
|
Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr};
|
|
|
|
Shader::Shader(ShaderStage *vertex, ShaderStage *pixel)
|
|
: stages()
|
|
{
|
|
std::string err;
|
|
if (!validate(vertex, pixel, err))
|
|
throw love::Exception("%s", err.c_str());
|
|
|
|
stages[ShaderStage::STAGE_VERTEX] = vertex;
|
|
stages[ShaderStage::STAGE_PIXEL] = pixel;
|
|
}
|
|
|
|
Shader::~Shader()
|
|
{
|
|
for (int i = 0; i < STANDARD_MAX_ENUM; i++)
|
|
{
|
|
if (this == standardShaders[i])
|
|
standardShaders[i] = nullptr;
|
|
}
|
|
|
|
if (current == this)
|
|
attachDefault(STANDARD_DEFAULT);
|
|
}
|
|
|
|
void Shader::attachDefault(StandardShader defaultType)
|
|
{
|
|
Shader *defaultshader = standardShaders[defaultType];
|
|
|
|
if (defaultshader == nullptr)
|
|
{
|
|
current = nullptr;
|
|
return;
|
|
}
|
|
|
|
if (current != defaultshader)
|
|
defaultshader->attach();
|
|
}
|
|
|
|
bool Shader::isDefaultActive()
|
|
{
|
|
for (int i = 0; i < STANDARD_MAX_ENUM; i++)
|
|
{
|
|
if (current == standardShaders[i])
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
TextureType Shader::getMainTextureType() const
|
|
{
|
|
const UniformInfo *info = getUniformInfo(BUILTIN_TEXTURE_MAIN);
|
|
return info != nullptr ? info->textureType : TEXTURE_MAX_ENUM;
|
|
}
|
|
|
|
void Shader::checkMainTextureType(TextureType textype, bool isDepthSampler) const
|
|
{
|
|
const UniformInfo *info = getUniformInfo(BUILTIN_TEXTURE_MAIN);
|
|
|
|
if (info == nullptr)
|
|
return;
|
|
|
|
if (info->textureType != TEXTURE_MAX_ENUM && info->textureType != textype)
|
|
{
|
|
const char *textypestr = "unknown";
|
|
const char *shadertextypestr = "unknown";
|
|
Texture::getConstant(textype, textypestr);
|
|
Texture::getConstant(info->textureType, shadertextypestr);
|
|
throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
|
|
}
|
|
|
|
if (info->isDepthSampler != isDepthSampler)
|
|
{
|
|
if (info->isDepthSampler)
|
|
throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
|
|
else
|
|
throw love::Exception("Depth textures which have depth comparison set can only be used with depth/shadow samplers in shaders.");
|
|
}
|
|
}
|
|
|
|
void Shader::checkMainTexture(Texture *tex) const
|
|
{
|
|
if (!tex->isReadable())
|
|
throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
|
|
|
|
checkMainTextureType(tex->getTextureType(), tex->getSamplerState().depthSampleMode.hasValue);
|
|
}
|
|
|
|
bool Shader::validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err)
|
|
{
|
|
glslang::TProgram program;
|
|
|
|
if (vertex != nullptr)
|
|
program.addShader(vertex->getGLSLangShader());
|
|
|
|
if (pixel != nullptr)
|
|
program.addShader(pixel->getGLSLangShader());
|
|
|
|
if (!program.link(EShMsgDefault))
|
|
{
|
|
err = "Cannot compile shader:\n\n" + std::string(program.getInfoLog()) + "\n" + std::string(program.getInfoDebugLog());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Shader::initialize()
|
|
{
|
|
return glslang::InitializeProcess();
|
|
}
|
|
|
|
void Shader::deinitialize()
|
|
{
|
|
glslang::FinalizeProcess();
|
|
}
|
|
|
|
bool Shader::getConstant(const char *in, Language &out)
|
|
{
|
|
return languages.find(in, out);
|
|
}
|
|
|
|
bool Shader::getConstant(Language in, const char *&out)
|
|
{
|
|
return languages.find(in, out);
|
|
}
|
|
|
|
bool Shader::getConstant(const char *in, BuiltinUniform &out)
|
|
{
|
|
return builtinNames.find(in, out);
|
|
}
|
|
|
|
bool Shader::getConstant(BuiltinUniform in, const char *&out)
|
|
{
|
|
return builtinNames.find(in, out);
|
|
}
|
|
|
|
StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM>::Entry Shader::languageEntries[] =
|
|
{
|
|
{ "glsl1", LANGUAGE_GLSL1 },
|
|
{ "essl1", LANGUAGE_ESSL1 },
|
|
{ "glsl3", LANGUAGE_GLSL3 },
|
|
{ "essl3", LANGUAGE_ESSL3 },
|
|
};
|
|
|
|
StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM> Shader::languages(Shader::languageEntries, sizeof(Shader::languageEntries));
|
|
|
|
StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
|
|
{
|
|
{ "MainTex", BUILTIN_TEXTURE_MAIN },
|
|
{ "love_VideoYChannel", BUILTIN_TEXTURE_VIDEO_Y },
|
|
{ "love_VideoCbChannel", BUILTIN_TEXTURE_VIDEO_CB },
|
|
{ "love_VideoCrChannel", BUILTIN_TEXTURE_VIDEO_CR },
|
|
{ "love_UniformsPerDraw", BUILTIN_UNIFORMS_PER_DRAW },
|
|
{ "love_PointSize", BUILTIN_POINT_SIZE },
|
|
};
|
|
|
|
StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
|
|
|
|
} // graphics
|
|
} // love
|