blob: 6cfa4b9f1bdb1e50f5c9d0cb0f99f05905f16e5c [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
Geoff Langcec35902014-04-16 10:52:36 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Shader.cpp: Implements the gl::Shader class and its derived classes
8// VertexShader and FragmentShader. Implements GL shader objects and related
9// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
10
Geoff Lang2b5420c2014-11-19 14:20:15 -050011#include "libANGLE/Shader.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040012
13#include <sstream>
14
Jamie Madill91445bc2015-09-23 16:47:53 -040015#include "common/utilities.h"
16#include "GLSLANG/ShaderLang.h"
Jamie Madill006cbc52015-09-23 16:47:54 -040017#include "libANGLE/Compiler.h"
Jamie Madill91445bc2015-09-23 16:47:53 -040018#include "libANGLE/Constants.h"
19#include "libANGLE/renderer/Renderer.h"
20#include "libANGLE/renderer/ShaderImpl.h"
21#include "libANGLE/ResourceManager.h"
22
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000023namespace gl
24{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000025
Jamie Madill006cbc52015-09-23 16:47:54 -040026namespace
27{
28template <typename VarT>
29std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList)
30{
31 ASSERT(variableList);
32 std::vector<VarT> result;
33 for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++)
34 {
35 const VarT &var = variableList->at(varIndex);
36 if (var.staticUse)
37 {
38 result.push_back(var);
39 }
40 }
41 return result;
42}
43
44template <typename VarT>
45const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList)
46{
47 ASSERT(variableList);
48 return *variableList;
49}
50
Jamie Madill9fc36822015-11-18 13:08:07 -050051} // anonymous namespace
52
Jamie Madill006cbc52015-09-23 16:47:54 -040053// true if varying x has a higher priority in packing than y
Jamie Madill55c25d02015-11-18 13:08:08 -050054bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
Jamie Madill006cbc52015-09-23 16:47:54 -040055{
56 if (x.type == y.type)
57 {
58 return x.arraySize > y.arraySize;
59 }
60
61 // Special case for handling structs: we sort these to the end of the list
62 if (x.type == GL_STRUCT_ANGLEX)
63 {
64 return false;
65 }
66
67 if (y.type == GL_STRUCT_ANGLEX)
68 {
69 return true;
70 }
71
72 return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
73}
74
Geoff Lang66988742015-12-22 19:39:19 +000075Shader::Data::Data(GLenum shaderType) : mShaderType(shaderType), mShaderVersion(100)
Jamie Madill91445bc2015-09-23 16:47:53 -040076{
77}
78
79Shader::Data::~Data()
80{
81}
82
Jamie Madill006cbc52015-09-23 16:47:54 -040083Shader::Shader(ResourceManager *manager,
84 rx::ImplFactory *implFactory,
85 const gl::Limitations &rendererLimitations,
86 GLenum type,
87 GLuint handle)
Jamie Madill91445bc2015-09-23 16:47:53 -040088 : mData(type),
Jamie Madill006cbc52015-09-23 16:47:54 -040089 mImplementation(implFactory->createShader(mData)),
90 mRendererLimitations(rendererLimitations),
Brandon Jonesf05cdee2014-08-27 15:24:07 -070091 mHandle(handle),
Corentin Wallezbc99bb62015-05-14 17:42:20 -040092 mType(type),
Brandon Jonesf05cdee2014-08-27 15:24:07 -070093 mRefCount(0),
94 mDeleteStatus(false),
Corentin Wallezbc99bb62015-05-14 17:42:20 -040095 mCompiled(false),
96 mResourceManager(manager)
Jamie Madille294bb82014-07-17 14:16:26 -040097{
Jamie Madill91445bc2015-09-23 16:47:53 -040098 ASSERT(mImplementation);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000099}
100
101Shader::~Shader()
102{
Jamie Madill91445bc2015-09-23 16:47:53 -0400103 SafeDelete(mImplementation);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000104}
105
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000106GLuint Shader::getHandle() const
107{
108 return mHandle;
109}
110
shannon.woods%transgaming.com@gtempaccount.com5f339332013-04-13 03:29:02 +0000111void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000112{
Geoff Lang536d7262013-08-26 17:04:20 -0400113 std::ostringstream stream;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000114
115 for (int i = 0; i < count; i++)
116 {
Geoff Langf60fab62014-11-24 11:21:20 -0500117 if (length == nullptr || length[i] < 0)
118 {
Jamie Madille7cfb3d2014-12-03 10:58:56 -0500119 stream.write(string[i], strlen(string[i]));
Geoff Langf60fab62014-11-24 11:21:20 -0500120 }
121 else
122 {
123 stream.write(string[i], length[i]);
124 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125 }
126
Jamie Madill006cbc52015-09-23 16:47:54 -0400127 mData.mSource = stream.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000128}
129
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000130int Shader::getInfoLogLength() const
131{
Jamie Madill006cbc52015-09-23 16:47:54 -0400132 if (mInfoLog.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400133 {
134 return 0;
135 }
136
Jamie Madill006cbc52015-09-23 16:47:54 -0400137 return (static_cast<int>(mInfoLog.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000138}
139
Geoff Lang536d7262013-08-26 17:04:20 -0400140void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000141{
142 int index = 0;
143
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000144 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000145 {
Jamie Madill006cbc52015-09-23 16:47:54 -0400146 index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
147 memcpy(infoLog, mInfoLog.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000148
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000149 infoLog[index] = '\0';
150 }
151
152 if (length)
153 {
154 *length = index;
155 }
156}
157
158int Shader::getSourceLength() const
159{
Jamie Madill006cbc52015-09-23 16:47:54 -0400160 return mData.mSource.empty() ? 0 : (static_cast<int>(mData.mSource.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000161}
162
zmo@google.coma574f782011-10-03 21:45:23 +0000163int Shader::getTranslatedSourceLength() const
164{
Jamie Madill91445bc2015-09-23 16:47:53 -0400165 if (mData.mTranslatedSource.empty())
166 {
167 return 0;
168 }
169
170 return (static_cast<int>(mData.mTranslatedSource.length()) + 1);
zmo@google.coma574f782011-10-03 21:45:23 +0000171}
172
Jamie Madill847638a2015-11-20 13:01:41 -0500173int Shader::getTranslatedSourceWithDebugInfoLength() const
174{
175 const std::string &debugInfo = mImplementation->getDebugInfo();
176 if (debugInfo.empty())
177 {
178 return 0;
179 }
180
181 return (static_cast<int>(debugInfo.length()) + 1);
182}
183
Brandon Jonesf05cdee2014-08-27 15:24:07 -0700184void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000185{
186 int index = 0;
187
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000188 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000189 {
Geoff Lang536d7262013-08-26 17:04:20 -0400190 index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
191 memcpy(buffer, source.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000192
zmo@google.coma574f782011-10-03 21:45:23 +0000193 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000194 }
195
196 if (length)
197 {
198 *length = index;
199 }
200}
201
Geoff Lang536d7262013-08-26 17:04:20 -0400202void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000203{
Jamie Madill006cbc52015-09-23 16:47:54 -0400204 getSourceImpl(mData.mSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000205}
206
Geoff Lang536d7262013-08-26 17:04:20 -0400207void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000208{
Jamie Madill91445bc2015-09-23 16:47:53 -0400209 getSourceImpl(mData.mTranslatedSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000210}
211
Tibor den Ouden97049c62014-10-06 21:39:16 +0200212void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
213{
Jamie Madill847638a2015-11-20 13:01:41 -0500214 const std::string &debugInfo = mImplementation->getDebugInfo();
Tibor den Ouden97049c62014-10-06 21:39:16 +0200215 getSourceImpl(debugInfo, bufSize, length, buffer);
216}
217
Geoff Lang492a7e42014-11-05 13:27:06 -0500218void Shader::compile(Compiler *compiler)
Jamie Madillbf9cce22014-07-18 10:33:09 -0400219{
Jamie Madill91445bc2015-09-23 16:47:53 -0400220 mData.mTranslatedSource.clear();
Jamie Madill006cbc52015-09-23 16:47:54 -0400221 mInfoLog.clear();
Jamie Madill91445bc2015-09-23 16:47:53 -0400222 mData.mShaderVersion = 100;
223 mData.mVaryings.clear();
224 mData.mUniforms.clear();
225 mData.mInterfaceBlocks.clear();
226 mData.mActiveAttributes.clear();
227 mData.mActiveOutputVariables.clear();
228
Jamie Madill006cbc52015-09-23 16:47:54 -0400229 ShHandle compilerHandle = compiler->getCompilerHandle(mData.mShaderType);
230
231 std::stringstream sourceStream;
232
Jamie Madilld2c52e32015-10-14 17:07:05 -0400233 std::string sourcePath;
234 int additionalOptions =
235 mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
Jamie Madill006cbc52015-09-23 16:47:54 -0400236 int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
237
238 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
239 // in fragment shaders. Shader compilation will fail. To provide a better error message we can
240 // instruct the compiler to pre-validate.
241 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
242 {
243 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
244 }
245
246 std::string sourceString = sourceStream.str();
Jamie Madilld2c52e32015-10-14 17:07:05 -0400247 std::vector<const char *> sourceCStrings;
248
249 if (!sourcePath.empty())
250 {
251 sourceCStrings.push_back(sourcePath.c_str());
252 }
253
254 sourceCStrings.push_back(sourceString.c_str());
255
256 bool result =
257 ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
Jamie Madill006cbc52015-09-23 16:47:54 -0400258
259 if (!result)
260 {
261 mInfoLog = ShGetInfoLog(compilerHandle);
262 TRACE("\n%s", mInfoLog.c_str());
263 mCompiled = false;
264 return;
265 }
266
267 mData.mTranslatedSource = ShGetObjectCode(compilerHandle);
268
269#ifndef NDEBUG
270 // Prefix translated shader with commented out un-translated shader.
271 // Useful in diagnostics tools which capture the shader source.
272 std::ostringstream shaderStream;
273 shaderStream << "// GLSL\n";
274 shaderStream << "//\n";
275
276 size_t curPos = 0;
277 while (curPos != std::string::npos)
278 {
279 size_t nextLine = mData.mSource.find("\n", curPos);
280 size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
281
282 shaderStream << "// " << mData.mSource.substr(curPos, len);
283
284 curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
285 }
286 shaderStream << "\n\n";
287 shaderStream << mData.mTranslatedSource;
288 mData.mTranslatedSource = shaderStream.str();
289#endif
290
291 // Gather the shader information
292 mData.mShaderVersion = ShGetShaderVersion(compilerHandle);
293
294 mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
295 mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
296 mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
297
298 if (mData.mShaderType == GL_VERTEX_SHADER)
299 {
300 mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
301 }
302 else
303 {
304 ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER);
305
306 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
Jamie Madill55c25d02015-11-18 13:08:08 -0500307 std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareShaderVar);
Jamie Madill006cbc52015-09-23 16:47:54 -0400308 mData.mActiveOutputVariables =
309 GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
310 }
311
312 ASSERT(!mData.mTranslatedSource.empty());
313
314 mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000315}
316
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000317void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000318{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000319 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000320}
321
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000322void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000323{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000324 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000325
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000326 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000327 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000328 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000329 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330}
331
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000332unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000334 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000335}
336
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000337bool Shader::isFlaggedForDeletion() const
338{
339 return mDeleteStatus;
340}
341
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342void Shader::flagForDeletion()
343{
344 mDeleteStatus = true;
345}
346
Jamie Madill80a6fc02015-08-21 16:53:16 -0400347int Shader::getShaderVersion() const
348{
Jamie Madill91445bc2015-09-23 16:47:53 -0400349 return mData.mShaderVersion;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400350}
351
Jamie Madill4cff2472015-08-21 16:53:18 -0400352const std::vector<sh::Varying> &Shader::getVaryings() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400353{
Jamie Madill91445bc2015-09-23 16:47:53 -0400354 return mData.getVaryings();
Jamie Madilld15250e2014-09-03 09:40:44 -0400355}
356
357const std::vector<sh::Uniform> &Shader::getUniforms() const
358{
Jamie Madill91445bc2015-09-23 16:47:53 -0400359 return mData.getUniforms();
Jamie Madilld15250e2014-09-03 09:40:44 -0400360}
361
362const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
363{
Jamie Madill91445bc2015-09-23 16:47:53 -0400364 return mData.getInterfaceBlocks();
Jamie Madilld15250e2014-09-03 09:40:44 -0400365}
366
367const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
368{
Jamie Madill91445bc2015-09-23 16:47:53 -0400369 return mData.getActiveAttributes();
Jamie Madilld15250e2014-09-03 09:40:44 -0400370}
371
Jamie Madilla0a9e122015-09-02 15:54:30 -0400372const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400373{
Jamie Madill91445bc2015-09-23 16:47:53 -0400374 return mData.getActiveOutputVariables();
Jamie Madilld15250e2014-09-03 09:40:44 -0400375}
376
Jamie Madill437d2662014-12-05 14:23:35 -0500377int Shader::getSemanticIndex(const std::string &attributeName) const
378{
379 if (!attributeName.empty())
380 {
Jamie Madill91445bc2015-09-23 16:47:53 -0400381 const auto &activeAttributes = mData.getActiveAttributes();
Jamie Madill437d2662014-12-05 14:23:35 -0500382
383 int semanticIndex = 0;
384 for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
385 {
386 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
387
388 if (attribute.name == attributeName)
389 {
390 return semanticIndex;
391 }
392
393 semanticIndex += gl::VariableRegisterCount(attribute.type);
394 }
395 }
396
397 return -1;
398}
399
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000400}