blob: bf0f742cb18b486cd42811ff749932b22c3e8526 [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 Madill53ea9cc2016-05-17 10:12:52 -040017#include "libANGLE/Caps.h"
Jamie Madill006cbc52015-09-23 16:47:54 -040018#include "libANGLE/Compiler.h"
Jamie Madill91445bc2015-09-23 16:47:53 -040019#include "libANGLE/Constants.h"
Jamie Madill53ea9cc2016-05-17 10:12:52 -040020#include "libANGLE/renderer/GLImplFactory.h"
Jamie Madill91445bc2015-09-23 16:47:53 -040021#include "libANGLE/renderer/ShaderImpl.h"
22#include "libANGLE/ResourceManager.h"
23
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000024namespace gl
25{
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000026
Jamie Madill006cbc52015-09-23 16:47:54 -040027namespace
28{
29template <typename VarT>
30std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList)
31{
32 ASSERT(variableList);
33 std::vector<VarT> result;
34 for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++)
35 {
36 const VarT &var = variableList->at(varIndex);
37 if (var.staticUse)
38 {
39 result.push_back(var);
40 }
41 }
42 return result;
43}
44
45template <typename VarT>
46const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList)
47{
48 ASSERT(variableList);
49 return *variableList;
50}
51
Jamie Madill9fc36822015-11-18 13:08:07 -050052} // anonymous namespace
53
Jamie Madill006cbc52015-09-23 16:47:54 -040054// true if varying x has a higher priority in packing than y
Jamie Madill55c25d02015-11-18 13:08:08 -050055bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
Jamie Madill006cbc52015-09-23 16:47:54 -040056{
57 if (x.type == y.type)
58 {
59 return x.arraySize > y.arraySize;
60 }
61
62 // Special case for handling structs: we sort these to the end of the list
63 if (x.type == GL_STRUCT_ANGLEX)
64 {
65 return false;
66 }
67
68 if (y.type == GL_STRUCT_ANGLEX)
69 {
70 return true;
71 }
72
73 return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
74}
75
Jamie Madill15243d92016-04-26 13:41:35 -040076ShaderState::ShaderState(GLenum shaderType) : mLabel(), mShaderType(shaderType), mShaderVersion(100)
Jamie Madill91445bc2015-09-23 16:47:53 -040077{
78}
79
Jamie Madill15243d92016-04-26 13:41:35 -040080ShaderState::~ShaderState()
Jamie Madill91445bc2015-09-23 16:47:53 -040081{
82}
83
Jamie Madill006cbc52015-09-23 16:47:54 -040084Shader::Shader(ResourceManager *manager,
Jamie Madill7aea7e02016-05-10 10:39:45 -040085 rx::GLImplFactory *implFactory,
Jamie Madill006cbc52015-09-23 16:47:54 -040086 const gl::Limitations &rendererLimitations,
87 GLenum type,
88 GLuint handle)
Jamie Madill15243d92016-04-26 13:41:35 -040089 : mState(type),
90 mImplementation(implFactory->createShader(mState)),
Jamie Madill006cbc52015-09-23 16:47:54 -040091 mRendererLimitations(rendererLimitations),
Brandon Jonesf05cdee2014-08-27 15:24:07 -070092 mHandle(handle),
Corentin Wallezbc99bb62015-05-14 17:42:20 -040093 mType(type),
Brandon Jonesf05cdee2014-08-27 15:24:07 -070094 mRefCount(0),
95 mDeleteStatus(false),
Corentin Wallezbc99bb62015-05-14 17:42:20 -040096 mCompiled(false),
97 mResourceManager(manager)
Jamie Madille294bb82014-07-17 14:16:26 -040098{
Jamie Madill91445bc2015-09-23 16:47:53 -040099 ASSERT(mImplementation);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000100}
101
102Shader::~Shader()
103{
Jamie Madill91445bc2015-09-23 16:47:53 -0400104 SafeDelete(mImplementation);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000105}
106
Geoff Lang70d0f492015-12-10 17:45:46 -0500107void Shader::setLabel(const std::string &label)
108{
Jamie Madill15243d92016-04-26 13:41:35 -0400109 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500110}
111
112const std::string &Shader::getLabel() const
113{
Jamie Madill15243d92016-04-26 13:41:35 -0400114 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500115}
116
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000117GLuint Shader::getHandle() const
118{
119 return mHandle;
120}
121
shannon.woods%transgaming.com@gtempaccount.com5f339332013-04-13 03:29:02 +0000122void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000123{
Geoff Lang536d7262013-08-26 17:04:20 -0400124 std::ostringstream stream;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000125
126 for (int i = 0; i < count; i++)
127 {
Geoff Langf60fab62014-11-24 11:21:20 -0500128 if (length == nullptr || length[i] < 0)
129 {
Jamie Madille7cfb3d2014-12-03 10:58:56 -0500130 stream.write(string[i], strlen(string[i]));
Geoff Langf60fab62014-11-24 11:21:20 -0500131 }
132 else
133 {
134 stream.write(string[i], length[i]);
135 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136 }
137
Jamie Madill15243d92016-04-26 13:41:35 -0400138 mState.mSource = stream.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000139}
140
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000141int Shader::getInfoLogLength() const
142{
Jamie Madill006cbc52015-09-23 16:47:54 -0400143 if (mInfoLog.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400144 {
145 return 0;
146 }
147
Jamie Madill006cbc52015-09-23 16:47:54 -0400148 return (static_cast<int>(mInfoLog.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000149}
150
Geoff Lang536d7262013-08-26 17:04:20 -0400151void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000152{
153 int index = 0;
154
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000155 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000156 {
Jamie Madill006cbc52015-09-23 16:47:54 -0400157 index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
158 memcpy(infoLog, mInfoLog.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000159
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000160 infoLog[index] = '\0';
161 }
162
163 if (length)
164 {
165 *length = index;
166 }
167}
168
169int Shader::getSourceLength() const
170{
Jamie Madill15243d92016-04-26 13:41:35 -0400171 return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000172}
173
zmo@google.coma574f782011-10-03 21:45:23 +0000174int Shader::getTranslatedSourceLength() const
175{
Jamie Madill15243d92016-04-26 13:41:35 -0400176 if (mState.mTranslatedSource.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400177 {
178 return 0;
179 }
180
Jamie Madill15243d92016-04-26 13:41:35 -0400181 return (static_cast<int>(mState.mTranslatedSource.length()) + 1);
zmo@google.coma574f782011-10-03 21:45:23 +0000182}
183
Jamie Madill847638a2015-11-20 13:01:41 -0500184int Shader::getTranslatedSourceWithDebugInfoLength() const
185{
186 const std::string &debugInfo = mImplementation->getDebugInfo();
187 if (debugInfo.empty())
188 {
189 return 0;
190 }
191
192 return (static_cast<int>(debugInfo.length()) + 1);
193}
194
Brandon Jonesf05cdee2014-08-27 15:24:07 -0700195void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000196{
197 int index = 0;
198
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000199 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000200 {
Geoff Lang536d7262013-08-26 17:04:20 -0400201 index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
202 memcpy(buffer, source.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000203
zmo@google.coma574f782011-10-03 21:45:23 +0000204 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000205 }
206
207 if (length)
208 {
209 *length = index;
210 }
211}
212
Geoff Lang536d7262013-08-26 17:04:20 -0400213void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000214{
Jamie Madill15243d92016-04-26 13:41:35 -0400215 getSourceImpl(mState.mSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000216}
217
Geoff Lang536d7262013-08-26 17:04:20 -0400218void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000219{
Jamie Madill15243d92016-04-26 13:41:35 -0400220 getSourceImpl(mState.mTranslatedSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000221}
222
Tibor den Ouden97049c62014-10-06 21:39:16 +0200223void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
224{
Jamie Madill847638a2015-11-20 13:01:41 -0500225 const std::string &debugInfo = mImplementation->getDebugInfo();
Tibor den Ouden97049c62014-10-06 21:39:16 +0200226 getSourceImpl(debugInfo, bufSize, length, buffer);
227}
228
Geoff Lang492a7e42014-11-05 13:27:06 -0500229void Shader::compile(Compiler *compiler)
Jamie Madillbf9cce22014-07-18 10:33:09 -0400230{
Jamie Madill15243d92016-04-26 13:41:35 -0400231 mState.mTranslatedSource.clear();
Jamie Madill006cbc52015-09-23 16:47:54 -0400232 mInfoLog.clear();
Jamie Madill15243d92016-04-26 13:41:35 -0400233 mState.mShaderVersion = 100;
234 mState.mVaryings.clear();
235 mState.mUniforms.clear();
236 mState.mInterfaceBlocks.clear();
237 mState.mActiveAttributes.clear();
238 mState.mActiveOutputVariables.clear();
Jamie Madill91445bc2015-09-23 16:47:53 -0400239
Jamie Madill15243d92016-04-26 13:41:35 -0400240 ShHandle compilerHandle = compiler->getCompilerHandle(mState.mShaderType);
Jamie Madill006cbc52015-09-23 16:47:54 -0400241
242 std::stringstream sourceStream;
243
Jamie Madilld2c52e32015-10-14 17:07:05 -0400244 std::string sourcePath;
245 int additionalOptions =
246 mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
Jamie Madill006cbc52015-09-23 16:47:54 -0400247 int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
248
249 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
250 // in fragment shaders. Shader compilation will fail. To provide a better error message we can
251 // instruct the compiler to pre-validate.
252 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
253 {
254 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
255 }
256
257 std::string sourceString = sourceStream.str();
Jamie Madilld2c52e32015-10-14 17:07:05 -0400258 std::vector<const char *> sourceCStrings;
259
260 if (!sourcePath.empty())
261 {
262 sourceCStrings.push_back(sourcePath.c_str());
263 }
264
265 sourceCStrings.push_back(sourceString.c_str());
266
267 bool result =
268 ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
Jamie Madill006cbc52015-09-23 16:47:54 -0400269
270 if (!result)
271 {
272 mInfoLog = ShGetInfoLog(compilerHandle);
273 TRACE("\n%s", mInfoLog.c_str());
274 mCompiled = false;
275 return;
276 }
277
Jamie Madill15243d92016-04-26 13:41:35 -0400278 mState.mTranslatedSource = ShGetObjectCode(compilerHandle);
Jamie Madill006cbc52015-09-23 16:47:54 -0400279
280#ifndef NDEBUG
281 // Prefix translated shader with commented out un-translated shader.
282 // Useful in diagnostics tools which capture the shader source.
283 std::ostringstream shaderStream;
284 shaderStream << "// GLSL\n";
285 shaderStream << "//\n";
286
287 size_t curPos = 0;
288 while (curPos != std::string::npos)
289 {
Jamie Madill15243d92016-04-26 13:41:35 -0400290 size_t nextLine = mState.mSource.find("\n", curPos);
Jamie Madill006cbc52015-09-23 16:47:54 -0400291 size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
292
Jamie Madill15243d92016-04-26 13:41:35 -0400293 shaderStream << "// " << mState.mSource.substr(curPos, len);
Jamie Madill006cbc52015-09-23 16:47:54 -0400294
295 curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
296 }
297 shaderStream << "\n\n";
Jamie Madill15243d92016-04-26 13:41:35 -0400298 shaderStream << mState.mTranslatedSource;
299 mState.mTranslatedSource = shaderStream.str();
Jamie Madill006cbc52015-09-23 16:47:54 -0400300#endif
301
302 // Gather the shader information
Jamie Madill15243d92016-04-26 13:41:35 -0400303 mState.mShaderVersion = ShGetShaderVersion(compilerHandle);
Jamie Madill006cbc52015-09-23 16:47:54 -0400304
Jamie Madill15243d92016-04-26 13:41:35 -0400305 mState.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
306 mState.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
307 mState.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
Jamie Madill006cbc52015-09-23 16:47:54 -0400308
Jamie Madill15243d92016-04-26 13:41:35 -0400309 if (mState.mShaderType == GL_VERTEX_SHADER)
Jamie Madill006cbc52015-09-23 16:47:54 -0400310 {
Jamie Madill15243d92016-04-26 13:41:35 -0400311 mState.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
Jamie Madill006cbc52015-09-23 16:47:54 -0400312 }
313 else
314 {
Jamie Madill15243d92016-04-26 13:41:35 -0400315 ASSERT(mState.mShaderType == GL_FRAGMENT_SHADER);
Jamie Madill006cbc52015-09-23 16:47:54 -0400316
317 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
Jamie Madill15243d92016-04-26 13:41:35 -0400318 std::sort(mState.mVaryings.begin(), mState.mVaryings.end(), CompareShaderVar);
319 mState.mActiveOutputVariables =
Jamie Madill006cbc52015-09-23 16:47:54 -0400320 GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
321 }
322
Jamie Madill15243d92016-04-26 13:41:35 -0400323 ASSERT(!mState.mTranslatedSource.empty());
Jamie Madill006cbc52015-09-23 16:47:54 -0400324
325 mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000326}
327
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000328void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000329{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000330 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331}
332
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000333void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000334{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000335 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000336
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000337 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000338 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000339 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000340 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000341}
342
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000343unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000344{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000345 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346}
347
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000348bool Shader::isFlaggedForDeletion() const
349{
350 return mDeleteStatus;
351}
352
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000353void Shader::flagForDeletion()
354{
355 mDeleteStatus = true;
356}
357
Jamie Madill80a6fc02015-08-21 16:53:16 -0400358int Shader::getShaderVersion() const
359{
Jamie Madill15243d92016-04-26 13:41:35 -0400360 return mState.mShaderVersion;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400361}
362
Jamie Madill4cff2472015-08-21 16:53:18 -0400363const std::vector<sh::Varying> &Shader::getVaryings() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400364{
Jamie Madill15243d92016-04-26 13:41:35 -0400365 return mState.getVaryings();
Jamie Madilld15250e2014-09-03 09:40:44 -0400366}
367
368const std::vector<sh::Uniform> &Shader::getUniforms() const
369{
Jamie Madill15243d92016-04-26 13:41:35 -0400370 return mState.getUniforms();
Jamie Madilld15250e2014-09-03 09:40:44 -0400371}
372
373const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
374{
Jamie Madill15243d92016-04-26 13:41:35 -0400375 return mState.getInterfaceBlocks();
Jamie Madilld15250e2014-09-03 09:40:44 -0400376}
377
378const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
379{
Jamie Madill15243d92016-04-26 13:41:35 -0400380 return mState.getActiveAttributes();
Jamie Madilld15250e2014-09-03 09:40:44 -0400381}
382
Jamie Madilla0a9e122015-09-02 15:54:30 -0400383const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400384{
Jamie Madill15243d92016-04-26 13:41:35 -0400385 return mState.getActiveOutputVariables();
Jamie Madilld15250e2014-09-03 09:40:44 -0400386}
387
Jamie Madill437d2662014-12-05 14:23:35 -0500388int Shader::getSemanticIndex(const std::string &attributeName) const
389{
390 if (!attributeName.empty())
391 {
Jamie Madill15243d92016-04-26 13:41:35 -0400392 const auto &activeAttributes = mState.getActiveAttributes();
Jamie Madill437d2662014-12-05 14:23:35 -0500393
394 int semanticIndex = 0;
395 for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
396 {
397 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
398
399 if (attribute.name == attributeName)
400 {
401 return semanticIndex;
402 }
403
404 semanticIndex += gl::VariableRegisterCount(attribute.type);
405 }
406 }
407
408 return -1;
409}
410
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000411}