blob: b48100222b51360377aeb7df044c40fee753e791 [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
Jamie Madill15243d92016-04-26 13:41:35 -040075ShaderState::ShaderState(GLenum shaderType) : mLabel(), mShaderType(shaderType), mShaderVersion(100)
Jamie Madill91445bc2015-09-23 16:47:53 -040076{
77}
78
Jamie Madill15243d92016-04-26 13:41:35 -040079ShaderState::~ShaderState()
Jamie Madill91445bc2015-09-23 16:47:53 -040080{
81}
82
Jamie Madill006cbc52015-09-23 16:47:54 -040083Shader::Shader(ResourceManager *manager,
Jamie Madill7aea7e02016-05-10 10:39:45 -040084 rx::GLImplFactory *implFactory,
Jamie Madill006cbc52015-09-23 16:47:54 -040085 const gl::Limitations &rendererLimitations,
86 GLenum type,
87 GLuint handle)
Jamie Madill15243d92016-04-26 13:41:35 -040088 : mState(type),
89 mImplementation(implFactory->createShader(mState)),
Jamie Madill006cbc52015-09-23 16:47:54 -040090 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
Geoff Lang70d0f492015-12-10 17:45:46 -0500106void Shader::setLabel(const std::string &label)
107{
Jamie Madill15243d92016-04-26 13:41:35 -0400108 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500109}
110
111const std::string &Shader::getLabel() const
112{
Jamie Madill15243d92016-04-26 13:41:35 -0400113 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500114}
115
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000116GLuint Shader::getHandle() const
117{
118 return mHandle;
119}
120
shannon.woods%transgaming.com@gtempaccount.com5f339332013-04-13 03:29:02 +0000121void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000122{
Geoff Lang536d7262013-08-26 17:04:20 -0400123 std::ostringstream stream;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124
125 for (int i = 0; i < count; i++)
126 {
Geoff Langf60fab62014-11-24 11:21:20 -0500127 if (length == nullptr || length[i] < 0)
128 {
Jamie Madille7cfb3d2014-12-03 10:58:56 -0500129 stream.write(string[i], strlen(string[i]));
Geoff Langf60fab62014-11-24 11:21:20 -0500130 }
131 else
132 {
133 stream.write(string[i], length[i]);
134 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000135 }
136
Jamie Madill15243d92016-04-26 13:41:35 -0400137 mState.mSource = stream.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000138}
139
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000140int Shader::getInfoLogLength() const
141{
Jamie Madill006cbc52015-09-23 16:47:54 -0400142 if (mInfoLog.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400143 {
144 return 0;
145 }
146
Jamie Madill006cbc52015-09-23 16:47:54 -0400147 return (static_cast<int>(mInfoLog.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000148}
149
Geoff Lang536d7262013-08-26 17:04:20 -0400150void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000151{
152 int index = 0;
153
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000154 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000155 {
Jamie Madill006cbc52015-09-23 16:47:54 -0400156 index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
157 memcpy(infoLog, mInfoLog.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000158
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000159 infoLog[index] = '\0';
160 }
161
162 if (length)
163 {
164 *length = index;
165 }
166}
167
168int Shader::getSourceLength() const
169{
Jamie Madill15243d92016-04-26 13:41:35 -0400170 return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000171}
172
zmo@google.coma574f782011-10-03 21:45:23 +0000173int Shader::getTranslatedSourceLength() const
174{
Jamie Madill15243d92016-04-26 13:41:35 -0400175 if (mState.mTranslatedSource.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400176 {
177 return 0;
178 }
179
Jamie Madill15243d92016-04-26 13:41:35 -0400180 return (static_cast<int>(mState.mTranslatedSource.length()) + 1);
zmo@google.coma574f782011-10-03 21:45:23 +0000181}
182
Jamie Madill847638a2015-11-20 13:01:41 -0500183int Shader::getTranslatedSourceWithDebugInfoLength() const
184{
185 const std::string &debugInfo = mImplementation->getDebugInfo();
186 if (debugInfo.empty())
187 {
188 return 0;
189 }
190
191 return (static_cast<int>(debugInfo.length()) + 1);
192}
193
Brandon Jonesf05cdee2014-08-27 15:24:07 -0700194void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000195{
196 int index = 0;
197
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000198 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000199 {
Geoff Lang536d7262013-08-26 17:04:20 -0400200 index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
201 memcpy(buffer, source.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000202
zmo@google.coma574f782011-10-03 21:45:23 +0000203 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000204 }
205
206 if (length)
207 {
208 *length = index;
209 }
210}
211
Geoff Lang536d7262013-08-26 17:04:20 -0400212void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000213{
Jamie Madill15243d92016-04-26 13:41:35 -0400214 getSourceImpl(mState.mSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000215}
216
Geoff Lang536d7262013-08-26 17:04:20 -0400217void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000218{
Jamie Madill15243d92016-04-26 13:41:35 -0400219 getSourceImpl(mState.mTranslatedSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000220}
221
Tibor den Ouden97049c62014-10-06 21:39:16 +0200222void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
223{
Jamie Madill847638a2015-11-20 13:01:41 -0500224 const std::string &debugInfo = mImplementation->getDebugInfo();
Tibor den Ouden97049c62014-10-06 21:39:16 +0200225 getSourceImpl(debugInfo, bufSize, length, buffer);
226}
227
Geoff Lang492a7e42014-11-05 13:27:06 -0500228void Shader::compile(Compiler *compiler)
Jamie Madillbf9cce22014-07-18 10:33:09 -0400229{
Jamie Madill15243d92016-04-26 13:41:35 -0400230 mState.mTranslatedSource.clear();
Jamie Madill006cbc52015-09-23 16:47:54 -0400231 mInfoLog.clear();
Jamie Madill15243d92016-04-26 13:41:35 -0400232 mState.mShaderVersion = 100;
233 mState.mVaryings.clear();
234 mState.mUniforms.clear();
235 mState.mInterfaceBlocks.clear();
236 mState.mActiveAttributes.clear();
237 mState.mActiveOutputVariables.clear();
Jamie Madill91445bc2015-09-23 16:47:53 -0400238
Jamie Madill15243d92016-04-26 13:41:35 -0400239 ShHandle compilerHandle = compiler->getCompilerHandle(mState.mShaderType);
Jamie Madill006cbc52015-09-23 16:47:54 -0400240
241 std::stringstream sourceStream;
242
Jamie Madilld2c52e32015-10-14 17:07:05 -0400243 std::string sourcePath;
244 int additionalOptions =
245 mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
Jamie Madill006cbc52015-09-23 16:47:54 -0400246 int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
247
248 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
249 // in fragment shaders. Shader compilation will fail. To provide a better error message we can
250 // instruct the compiler to pre-validate.
251 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
252 {
253 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
254 }
255
256 std::string sourceString = sourceStream.str();
Jamie Madilld2c52e32015-10-14 17:07:05 -0400257 std::vector<const char *> sourceCStrings;
258
259 if (!sourcePath.empty())
260 {
261 sourceCStrings.push_back(sourcePath.c_str());
262 }
263
264 sourceCStrings.push_back(sourceString.c_str());
265
266 bool result =
267 ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
Jamie Madill006cbc52015-09-23 16:47:54 -0400268
269 if (!result)
270 {
271 mInfoLog = ShGetInfoLog(compilerHandle);
272 TRACE("\n%s", mInfoLog.c_str());
273 mCompiled = false;
274 return;
275 }
276
Jamie Madill15243d92016-04-26 13:41:35 -0400277 mState.mTranslatedSource = ShGetObjectCode(compilerHandle);
Jamie Madill006cbc52015-09-23 16:47:54 -0400278
279#ifndef NDEBUG
280 // Prefix translated shader with commented out un-translated shader.
281 // Useful in diagnostics tools which capture the shader source.
282 std::ostringstream shaderStream;
283 shaderStream << "// GLSL\n";
284 shaderStream << "//\n";
285
286 size_t curPos = 0;
287 while (curPos != std::string::npos)
288 {
Jamie Madill15243d92016-04-26 13:41:35 -0400289 size_t nextLine = mState.mSource.find("\n", curPos);
Jamie Madill006cbc52015-09-23 16:47:54 -0400290 size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
291
Jamie Madill15243d92016-04-26 13:41:35 -0400292 shaderStream << "// " << mState.mSource.substr(curPos, len);
Jamie Madill006cbc52015-09-23 16:47:54 -0400293
294 curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
295 }
296 shaderStream << "\n\n";
Jamie Madill15243d92016-04-26 13:41:35 -0400297 shaderStream << mState.mTranslatedSource;
298 mState.mTranslatedSource = shaderStream.str();
Jamie Madill006cbc52015-09-23 16:47:54 -0400299#endif
300
301 // Gather the shader information
Jamie Madill15243d92016-04-26 13:41:35 -0400302 mState.mShaderVersion = ShGetShaderVersion(compilerHandle);
Jamie Madill006cbc52015-09-23 16:47:54 -0400303
Jamie Madill15243d92016-04-26 13:41:35 -0400304 mState.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
305 mState.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
306 mState.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
Jamie Madill006cbc52015-09-23 16:47:54 -0400307
Jamie Madill15243d92016-04-26 13:41:35 -0400308 if (mState.mShaderType == GL_VERTEX_SHADER)
Jamie Madill006cbc52015-09-23 16:47:54 -0400309 {
Jamie Madill15243d92016-04-26 13:41:35 -0400310 mState.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
Jamie Madill006cbc52015-09-23 16:47:54 -0400311 }
312 else
313 {
Jamie Madill15243d92016-04-26 13:41:35 -0400314 ASSERT(mState.mShaderType == GL_FRAGMENT_SHADER);
Jamie Madill006cbc52015-09-23 16:47:54 -0400315
316 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
Jamie Madill15243d92016-04-26 13:41:35 -0400317 std::sort(mState.mVaryings.begin(), mState.mVaryings.end(), CompareShaderVar);
318 mState.mActiveOutputVariables =
Jamie Madill006cbc52015-09-23 16:47:54 -0400319 GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
320 }
321
Jamie Madill15243d92016-04-26 13:41:35 -0400322 ASSERT(!mState.mTranslatedSource.empty());
Jamie Madill006cbc52015-09-23 16:47:54 -0400323
324 mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000325}
326
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000327void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000328{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000329 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000330}
331
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000332void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000333{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000334 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000335
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000336 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000337 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000338 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000339 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340}
341
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000342unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000343{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000344 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345}
346
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000347bool Shader::isFlaggedForDeletion() const
348{
349 return mDeleteStatus;
350}
351
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352void Shader::flagForDeletion()
353{
354 mDeleteStatus = true;
355}
356
Jamie Madill80a6fc02015-08-21 16:53:16 -0400357int Shader::getShaderVersion() const
358{
Jamie Madill15243d92016-04-26 13:41:35 -0400359 return mState.mShaderVersion;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400360}
361
Jamie Madill4cff2472015-08-21 16:53:18 -0400362const std::vector<sh::Varying> &Shader::getVaryings() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400363{
Jamie Madill15243d92016-04-26 13:41:35 -0400364 return mState.getVaryings();
Jamie Madilld15250e2014-09-03 09:40:44 -0400365}
366
367const std::vector<sh::Uniform> &Shader::getUniforms() const
368{
Jamie Madill15243d92016-04-26 13:41:35 -0400369 return mState.getUniforms();
Jamie Madilld15250e2014-09-03 09:40:44 -0400370}
371
372const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
373{
Jamie Madill15243d92016-04-26 13:41:35 -0400374 return mState.getInterfaceBlocks();
Jamie Madilld15250e2014-09-03 09:40:44 -0400375}
376
377const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
378{
Jamie Madill15243d92016-04-26 13:41:35 -0400379 return mState.getActiveAttributes();
Jamie Madilld15250e2014-09-03 09:40:44 -0400380}
381
Jamie Madilla0a9e122015-09-02 15:54:30 -0400382const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400383{
Jamie Madill15243d92016-04-26 13:41:35 -0400384 return mState.getActiveOutputVariables();
Jamie Madilld15250e2014-09-03 09:40:44 -0400385}
386
Jamie Madill437d2662014-12-05 14:23:35 -0500387int Shader::getSemanticIndex(const std::string &attributeName) const
388{
389 if (!attributeName.empty())
390 {
Jamie Madill15243d92016-04-26 13:41:35 -0400391 const auto &activeAttributes = mState.getActiveAttributes();
Jamie Madill437d2662014-12-05 14:23:35 -0500392
393 int semanticIndex = 0;
394 for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
395 {
396 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
397
398 if (attribute.name == attributeName)
399 {
400 return semanticIndex;
401 }
402
403 semanticIndex += gl::VariableRegisterCount(attribute.type);
404 }
405 }
406
407 return -1;
408}
409
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000410}