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#include "ShaderStage.h"
22#include "common/Exception.h"
23#include "Graphics.h"
24
25#include "libraries/glslang/glslang/Public/ShaderLang.h"
26
27// TODO: Use love.graphics to determine actual limits?
28static const TBuiltInResource defaultTBuiltInResource = {
29 /* .MaxLights = */ 32,
30 /* .MaxClipPlanes = */ 6,
31 /* .MaxTextureUnits = */ 32,
32 /* .MaxTextureCoords = */ 32,
33 /* .MaxVertexAttribs = */ 64,
34 /* .MaxVertexUniformComponents = */ 16384,
35 /* .MaxVaryingFloats = */ 128,
36 /* .MaxVertexTextureImageUnits = */ 32,
37 /* .MaxCombinedTextureImageUnits = */ 80,
38 /* .MaxTextureImageUnits = */ 32,
39 /* .MaxFragmentUniformComponents = */ 16384,
40 /* .MaxDrawBuffers = */ 8,
41 /* .MaxVertexUniformVectors = */ 4096,
42 /* .MaxVaryingVectors = */ 32,
43 /* .MaxFragmentUniformVectors = */ 4096,
44 /* .MaxVertexOutputVectors = */ 32,
45 /* .MaxFragmentInputVectors = */ 31,
46 /* .MinProgramTexelOffset = */ -8,
47 /* .MaxProgramTexelOffset = */ 7,
48 /* .MaxClipDistances = */ 8,
49 /* .MaxComputeWorkGroupCountX = */ 65535,
50 /* .MaxComputeWorkGroupCountY = */ 65535,
51 /* .MaxComputeWorkGroupCountZ = */ 65535,
52 /* .MaxComputeWorkGroupSizeX = */ 1024,
53 /* .MaxComputeWorkGroupSizeY = */ 1024,
54 /* .MaxComputeWorkGroupSizeZ = */ 64,
55 /* .MaxComputeUniformComponents = */ 1024,
56 /* .MaxComputeTextureImageUnits = */ 32,
57 /* .MaxComputeImageUniforms = */ 16,
58 /* .MaxComputeAtomicCounters = */ 4096,
59 /* .MaxComputeAtomicCounterBuffers = */ 8,
60 /* .MaxVaryingComponents = */ 128,
61 /* .MaxVertexOutputComponents = */ 128,
62 /* .MaxGeometryInputComponents = */ 128,
63 /* .MaxGeometryOutputComponents = */ 128,
64 /* .MaxFragmentInputComponents = */ 128,
65 /* .MaxImageUnits = */ 192,
66 /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144,
67 /* .MaxCombinedShaderOutputResources = */ 144,
68 /* .MaxImageSamples = */ 32,
69 /* .MaxVertexImageUniforms = */ 16,
70 /* .MaxTessControlImageUniforms = */ 16,
71 /* .MaxTessEvaluationImageUniforms = */ 16,
72 /* .MaxGeometryImageUniforms = */ 16,
73 /* .MaxFragmentImageUniforms = */ 16,
74 /* .MaxCombinedImageUniforms = */ 80,
75 /* .MaxGeometryTextureImageUnits = */ 16,
76 /* .MaxGeometryOutputVertices = */ 256,
77 /* .MaxGeometryTotalOutputComponents = */ 1024,
78 /* .MaxGeometryUniformComponents = */ 1024,
79 /* .MaxGeometryVaryingComponents = */ 64,
80 /* .MaxTessControlInputComponents = */ 128,
81 /* .MaxTessControlOutputComponents = */ 128,
82 /* .MaxTessControlTextureImageUnits = */ 16,
83 /* .MaxTessControlUniformComponents = */ 1024,
84 /* .MaxTessControlTotalOutputComponents = */ 4096,
85 /* .MaxTessEvaluationInputComponents = */ 128,
86 /* .MaxTessEvaluationOutputComponents = */ 128,
87 /* .MaxTessEvaluationTextureImageUnits = */ 16,
88 /* .MaxTessEvaluationUniformComponents = */ 1024,
89 /* .MaxTessPatchComponents = */ 120,
90 /* .MaxPatchVertices = */ 32,
91 /* .MaxTessGenLevel = */ 64,
92 /* .MaxViewports = */ 16,
93 /* .MaxVertexAtomicCounters = */ 4096,
94 /* .MaxTessControlAtomicCounters = */ 4096,
95 /* .MaxTessEvaluationAtomicCounters = */ 4096,
96 /* .MaxGeometryAtomicCounters = */ 4096,
97 /* .MaxFragmentAtomicCounters = */ 4096,
98 /* .MaxCombinedAtomicCounters = */ 4096,
99 /* .MaxAtomicCounterBindings = */ 8,
100 /* .MaxVertexAtomicCounterBuffers = */ 8,
101 /* .MaxTessControlAtomicCounterBuffers = */ 8,
102 /* .MaxTessEvaluationAtomicCounterBuffers = */ 8,
103 /* .MaxGeometryAtomicCounterBuffers = */ 8,
104 /* .MaxFragmentAtomicCounterBuffers = */ 8,
105 /* .MaxCombinedAtomicCounterBuffers = */ 8,
106 /* .MaxAtomicCounterBufferSize = */ 16384,
107 /* .MaxTransformFeedbackBuffers = */ 4,
108 /* .MaxTransformFeedbackInterleavedComponents = */ 64,
109 /* .MaxCullDistances = */ 8,
110 /* .MaxCombinedClipAndCullDistances = */ 8,
111 /* .MaxSamples = */ 32,
112 /* .maxMeshOutputVerticesNV = */ 256,
113 /* .maxMeshOutputPrimitivesNV = */ 512,
114 /* .maxMeshWorkGroupSizeX_NV = */ 32,
115 /* .maxMeshWorkGroupSizeY_NV = */ 1,
116 /* .maxMeshWorkGroupSizeZ_NV = */ 1,
117 /* .maxTaskWorkGroupSizeX_NV = */ 32,
118 /* .maxTaskWorkGroupSizeY_NV = */ 1,
119 /* .maxTaskWorkGroupSizeZ_NV = */ 1,
120 /* .maxMeshViewCountNV = */ 4,
121 /* .limits = */ {
122 /* .nonInductiveForLoops = */ 1,
123 /* .whileLoops = */ 1,
124 /* .doWhileLoops = */ 1,
125 /* .generalUniformIndexing = */ 1,
126 /* .generalAttributeMatrixVectorIndexing = */ 1,
127 /* .generalVaryingIndexing = */ 1,
128 /* .generalSamplerIndexing = */ 1,
129 /* .generalVariableIndexing = */ 1,
130 /* .generalConstantMatrixVectorIndexing = */ 1,
131 }
132};
133
134namespace love
135{
136namespace graphics
137{
138
139ShaderStage::ShaderStage(Graphics *gfx, StageType stage, const std::string &glsl, bool gles, const std::string &cachekey)
140 : stageType(stage)
141 , source(glsl)
142 , cacheKey(cachekey)
143 , glslangShader(nullptr)
144{
145 EShLanguage glslangStage = EShLangCount;
146 if (stage == STAGE_VERTEX)
147 glslangStage = EShLangVertex;
148 else if (stage == STAGE_PIXEL)
149 glslangStage = EShLangFragment;
150 else
151 throw love::Exception("Cannot compile shader stage: unknown stage type.");
152
153 glslangShader = new glslang::TShader(glslangStage);
154
155 bool supportsGLSL3 = gfx->getCapabilities().features[Graphics::FEATURE_GLSL3];
156 int defaultversion = gles ? 100 : 120;
157 EProfile defaultprofile = ENoProfile;
158
159 const char *csrc = glsl.c_str();
160 int srclen = (int) glsl.length();
161 glslangShader->setStringsWithLengths(&csrc, &srclen, 1);
162
163 bool forcedefault = false;
164 if (source.find("#define LOVE_GLSL1_ON_GLSL3") != std::string::npos)
165 forcedefault = true;
166
167 bool forwardcompat = supportsGLSL3 && !forcedefault;
168
169 if (!glslangShader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings))
170 {
171 const char *stagename = "unknown";
172 getConstant(stage, stagename);
173
174 std::string err = "Error validating " + std::string(stagename) + " shader:\n\n"
175 + std::string(glslangShader->getInfoLog()) + "\n"
176 + std::string(glslangShader->getInfoDebugLog());
177
178 delete glslangShader;
179 throw love::Exception("%s", err.c_str());
180 }
181}
182
183ShaderStage::~ShaderStage()
184{
185 if (!cacheKey.empty())
186 {
187 auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
188 if (gfx != nullptr)
189 gfx->cleanupCachedShaderStage(stageType, cacheKey);
190 }
191
192 delete glslangShader;
193}
194
195bool ShaderStage::getConstant(const char *in, StageType &out)
196{
197 return stageNames.find(in, out);
198}
199
200bool ShaderStage::getConstant(StageType in, const char *&out)
201{
202 return stageNames.find(in, out);
203}
204
205StringMap<ShaderStage::StageType, ShaderStage::STAGE_MAX_ENUM>::Entry ShaderStage::stageNameEntries[] =
206{
207 { "vertex", STAGE_VERTEX },
208 { "pixel", STAGE_PIXEL },
209};
210
211StringMap<ShaderStage::StageType, ShaderStage::STAGE_MAX_ENUM> ShaderStage::stageNames(ShaderStage::stageNameEntries, sizeof(ShaderStage::stageNameEntries));
212
213} // graphics
214} // love
215