1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13* claim that you wrote the original software. If you use this software
14* in a product, an acknowledgment in the product documentation would be
15* appreciated but is not required.
16* 2. Altered source versions must be plainly marked as such, and must not be
17* misrepresented as being the original software.
18* 3. This notice may not be removed or altered from any source distribution.
19**/
20
21// LOVE
22#include "Shader.h"
23#include "Graphics.h"
24#include "math/MathModule.h"
25
26// glslang
27#include "libraries/glslang/glslang/Public/ShaderLang.h"
28
29// C++
30#include <string>
31
32namespace love
33{
34namespace graphics
35{
36
37love::Type Shader::type("Shader", &Object::type);
38
39Shader *Shader::current = nullptr;
40Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr};
41
42Shader::Shader(ShaderStage *vertex, ShaderStage *pixel)
43 : stages()
44{
45 std::string err;
46 if (!validate(vertex, pixel, err))
47 throw love::Exception("%s", err.c_str());
48
49 stages[ShaderStage::STAGE_VERTEX] = vertex;
50 stages[ShaderStage::STAGE_PIXEL] = pixel;
51}
52
53Shader::~Shader()
54{
55 for (int i = 0; i < STANDARD_MAX_ENUM; i++)
56 {
57 if (this == standardShaders[i])
58 standardShaders[i] = nullptr;
59 }
60
61 if (current == this)
62 attachDefault(STANDARD_DEFAULT);
63}
64
65void Shader::attachDefault(StandardShader defaultType)
66{
67 Shader *defaultshader = standardShaders[defaultType];
68
69 if (defaultshader == nullptr)
70 {
71 current = nullptr;
72 return;
73 }
74
75 if (current != defaultshader)
76 defaultshader->attach();
77}
78
79bool Shader::isDefaultActive()
80{
81 for (int i = 0; i < STANDARD_MAX_ENUM; i++)
82 {
83 if (current == standardShaders[i])
84 return true;
85 }
86
87 return false;
88}
89
90TextureType Shader::getMainTextureType() const
91{
92 const UniformInfo *info = getUniformInfo(BUILTIN_TEXTURE_MAIN);
93 return info != nullptr ? info->textureType : TEXTURE_MAX_ENUM;
94}
95
96void Shader::checkMainTextureType(TextureType textype, bool isDepthSampler) const
97{
98 const UniformInfo *info = getUniformInfo(BUILTIN_TEXTURE_MAIN);
99
100 if (info == nullptr)
101 return;
102
103 if (info->textureType != TEXTURE_MAX_ENUM && info->textureType != textype)
104 {
105 const char *textypestr = "unknown";
106 const char *shadertextypestr = "unknown";
107 Texture::getConstant(textype, textypestr);
108 Texture::getConstant(info->textureType, shadertextypestr);
109 throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
110 }
111
112 if (info->isDepthSampler != isDepthSampler)
113 {
114 if (info->isDepthSampler)
115 throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
116 else
117 throw love::Exception("Depth textures which have depth comparison set can only be used with depth/shadow samplers in shaders.");
118 }
119}
120
121void Shader::checkMainTexture(Texture *tex) const
122{
123 if (!tex->isReadable())
124 throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
125
126 checkMainTextureType(tex->getTextureType(), tex->getDepthSampleMode().hasValue);
127}
128
129bool Shader::validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err)
130{
131 glslang::TProgram program;
132
133 if (vertex != nullptr)
134 program.addShader(vertex->getGLSLangShader());
135
136 if (pixel != nullptr)
137 program.addShader(pixel->getGLSLangShader());
138
139 if (!program.link(EShMsgDefault))
140 {
141 err = "Cannot compile shader:\n\n" + std::string(program.getInfoLog()) + "\n" + std::string(program.getInfoDebugLog());
142 return false;
143 }
144
145 return true;
146}
147
148bool Shader::initialize()
149{
150 return glslang::InitializeProcess();
151}
152
153void Shader::deinitialize()
154{
155 glslang::FinalizeProcess();
156}
157
158bool Shader::getConstant(const char *in, Language &out)
159{
160 return languages.find(in, out);
161}
162
163bool Shader::getConstant(Language in, const char *&out)
164{
165 return languages.find(in, out);
166}
167
168bool Shader::getConstant(const char *in, BuiltinUniform &out)
169{
170 return builtinNames.find(in, out);
171}
172
173bool Shader::getConstant(BuiltinUniform in, const char *&out)
174{
175 return builtinNames.find(in, out);
176}
177
178StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM>::Entry Shader::languageEntries[] =
179{
180 { "glsl1", LANGUAGE_GLSL1 },
181 { "essl1", LANGUAGE_ESSL1 },
182 { "glsl3", LANGUAGE_GLSL3 },
183 { "essl3", LANGUAGE_ESSL3 },
184};
185
186StringMap<Shader::Language, Shader::LANGUAGE_MAX_ENUM> Shader::languages(Shader::languageEntries, sizeof(Shader::languageEntries));
187
188StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
189{
190 { "MainTex", BUILTIN_TEXTURE_MAIN },
191 { "love_VideoYChannel", BUILTIN_TEXTURE_VIDEO_Y },
192 { "love_VideoCbChannel", BUILTIN_TEXTURE_VIDEO_CB },
193 { "love_VideoCrChannel", BUILTIN_TEXTURE_VIDEO_CR },
194 { "ViewSpaceFromLocal", BUILTIN_MATRIX_VIEW_FROM_LOCAL },
195 { "ClipSpaceFromView", BUILTIN_MATRIX_CLIP_FROM_VIEW },
196 { "ClipSpaceFromLocal", BUILTIN_MATRIX_CLIP_FROM_LOCAL },
197 { "ViewNormalFromLocal", BUILTIN_MATRIX_VIEW_NORMAL_FROM_LOCAL },
198 { "love_PointSize", BUILTIN_POINT_SIZE },
199 { "love_ScreenSize", BUILTIN_SCREEN_SIZE },
200};
201
202StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
203
204} // graphics
205} // love
206