blob: 904345d582ac45d57631dca12fa12342df48230a [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{
Martin Radev4c4c8e72016-08-04 12:25:34 +030078 mLocalSize.fill(-1);
Jamie Madill91445bc2015-09-23 16:47:53 -040079}
80
Jamie Madill15243d92016-04-26 13:41:35 -040081ShaderState::~ShaderState()
Jamie Madill91445bc2015-09-23 16:47:53 -040082{
83}
84
Jamie Madill006cbc52015-09-23 16:47:54 -040085Shader::Shader(ResourceManager *manager,
Jamie Madill7aea7e02016-05-10 10:39:45 -040086 rx::GLImplFactory *implFactory,
Jamie Madill006cbc52015-09-23 16:47:54 -040087 const gl::Limitations &rendererLimitations,
88 GLenum type,
89 GLuint handle)
Jamie Madill15243d92016-04-26 13:41:35 -040090 : mState(type),
91 mImplementation(implFactory->createShader(mState)),
Jamie Madill006cbc52015-09-23 16:47:54 -040092 mRendererLimitations(rendererLimitations),
Brandon Jonesf05cdee2014-08-27 15:24:07 -070093 mHandle(handle),
Corentin Wallezbc99bb62015-05-14 17:42:20 -040094 mType(type),
Brandon Jonesf05cdee2014-08-27 15:24:07 -070095 mRefCount(0),
96 mDeleteStatus(false),
Corentin Wallezbc99bb62015-05-14 17:42:20 -040097 mCompiled(false),
98 mResourceManager(manager)
Jamie Madille294bb82014-07-17 14:16:26 -040099{
Jamie Madill91445bc2015-09-23 16:47:53 -0400100 ASSERT(mImplementation);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000101}
102
103Shader::~Shader()
104{
Jamie Madill91445bc2015-09-23 16:47:53 -0400105 SafeDelete(mImplementation);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000106}
107
Geoff Lang70d0f492015-12-10 17:45:46 -0500108void Shader::setLabel(const std::string &label)
109{
Jamie Madill15243d92016-04-26 13:41:35 -0400110 mState.mLabel = label;
Geoff Lang70d0f492015-12-10 17:45:46 -0500111}
112
113const std::string &Shader::getLabel() const
114{
Jamie Madill15243d92016-04-26 13:41:35 -0400115 return mState.mLabel;
Geoff Lang70d0f492015-12-10 17:45:46 -0500116}
117
daniel@transgaming.com6c785212010-03-30 03:36:17 +0000118GLuint Shader::getHandle() const
119{
120 return mHandle;
121}
122
shannon.woods%transgaming.com@gtempaccount.com5f339332013-04-13 03:29:02 +0000123void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124{
Geoff Lang536d7262013-08-26 17:04:20 -0400125 std::ostringstream stream;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000126
127 for (int i = 0; i < count; i++)
128 {
Geoff Langf60fab62014-11-24 11:21:20 -0500129 if (length == nullptr || length[i] < 0)
130 {
Jamie Madille7cfb3d2014-12-03 10:58:56 -0500131 stream.write(string[i], strlen(string[i]));
Geoff Langf60fab62014-11-24 11:21:20 -0500132 }
133 else
134 {
135 stream.write(string[i], length[i]);
136 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000137 }
138
Jamie Madill15243d92016-04-26 13:41:35 -0400139 mState.mSource = stream.str();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000140}
141
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000142int Shader::getInfoLogLength() const
143{
Jamie Madill006cbc52015-09-23 16:47:54 -0400144 if (mInfoLog.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400145 {
146 return 0;
147 }
148
Jamie Madill006cbc52015-09-23 16:47:54 -0400149 return (static_cast<int>(mInfoLog.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000150}
151
Geoff Lang536d7262013-08-26 17:04:20 -0400152void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000153{
154 int index = 0;
155
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000156 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000157 {
Jamie Madill006cbc52015-09-23 16:47:54 -0400158 index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
159 memcpy(infoLog, mInfoLog.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000160
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000161 infoLog[index] = '\0';
162 }
163
164 if (length)
165 {
166 *length = index;
167 }
168}
169
170int Shader::getSourceLength() const
171{
Jamie Madill15243d92016-04-26 13:41:35 -0400172 return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000173}
174
zmo@google.coma574f782011-10-03 21:45:23 +0000175int Shader::getTranslatedSourceLength() const
176{
Jamie Madill15243d92016-04-26 13:41:35 -0400177 if (mState.mTranslatedSource.empty())
Jamie Madill91445bc2015-09-23 16:47:53 -0400178 {
179 return 0;
180 }
181
Jamie Madill15243d92016-04-26 13:41:35 -0400182 return (static_cast<int>(mState.mTranslatedSource.length()) + 1);
zmo@google.coma574f782011-10-03 21:45:23 +0000183}
184
Jamie Madill847638a2015-11-20 13:01:41 -0500185int Shader::getTranslatedSourceWithDebugInfoLength() const
186{
187 const std::string &debugInfo = mImplementation->getDebugInfo();
188 if (debugInfo.empty())
189 {
190 return 0;
191 }
192
193 return (static_cast<int>(debugInfo.length()) + 1);
194}
195
Brandon Jonesf05cdee2014-08-27 15:24:07 -0700196void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000197{
198 int index = 0;
199
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000200 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000201 {
Geoff Lang536d7262013-08-26 17:04:20 -0400202 index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
203 memcpy(buffer, source.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000204
zmo@google.coma574f782011-10-03 21:45:23 +0000205 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000206 }
207
208 if (length)
209 {
210 *length = index;
211 }
212}
213
Geoff Lang536d7262013-08-26 17:04:20 -0400214void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000215{
Jamie Madill15243d92016-04-26 13:41:35 -0400216 getSourceImpl(mState.mSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000217}
218
Geoff Lang536d7262013-08-26 17:04:20 -0400219void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000220{
Jamie Madill15243d92016-04-26 13:41:35 -0400221 getSourceImpl(mState.mTranslatedSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000222}
223
Tibor den Ouden97049c62014-10-06 21:39:16 +0200224void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
225{
Jamie Madill847638a2015-11-20 13:01:41 -0500226 const std::string &debugInfo = mImplementation->getDebugInfo();
Tibor den Ouden97049c62014-10-06 21:39:16 +0200227 getSourceImpl(debugInfo, bufSize, length, buffer);
228}
229
Geoff Lang492a7e42014-11-05 13:27:06 -0500230void Shader::compile(Compiler *compiler)
Jamie Madillbf9cce22014-07-18 10:33:09 -0400231{
Jamie Madill15243d92016-04-26 13:41:35 -0400232 mState.mTranslatedSource.clear();
Jamie Madill006cbc52015-09-23 16:47:54 -0400233 mInfoLog.clear();
Jamie Madill15243d92016-04-26 13:41:35 -0400234 mState.mShaderVersion = 100;
235 mState.mVaryings.clear();
236 mState.mUniforms.clear();
237 mState.mInterfaceBlocks.clear();
238 mState.mActiveAttributes.clear();
239 mState.mActiveOutputVariables.clear();
Jamie Madill91445bc2015-09-23 16:47:53 -0400240
Jamie Madill15243d92016-04-26 13:41:35 -0400241 ShHandle compilerHandle = compiler->getCompilerHandle(mState.mShaderType);
Jamie Madill006cbc52015-09-23 16:47:54 -0400242
243 std::stringstream sourceStream;
244
Jamie Madilld2c52e32015-10-14 17:07:05 -0400245 std::string sourcePath;
246 int additionalOptions =
247 mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
Jamie Madill006cbc52015-09-23 16:47:54 -0400248 int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
249
250 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
251 // in fragment shaders. Shader compilation will fail. To provide a better error message we can
252 // instruct the compiler to pre-validate.
253 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
254 {
255 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
256 }
257
258 std::string sourceString = sourceStream.str();
Jamie Madilld2c52e32015-10-14 17:07:05 -0400259 std::vector<const char *> sourceCStrings;
260
261 if (!sourcePath.empty())
262 {
263 sourceCStrings.push_back(sourcePath.c_str());
264 }
265
266 sourceCStrings.push_back(sourceString.c_str());
267
268 bool result =
269 ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
Jamie Madill006cbc52015-09-23 16:47:54 -0400270
271 if (!result)
272 {
273 mInfoLog = ShGetInfoLog(compilerHandle);
274 TRACE("\n%s", mInfoLog.c_str());
275 mCompiled = false;
276 return;
277 }
278
Jamie Madill15243d92016-04-26 13:41:35 -0400279 mState.mTranslatedSource = ShGetObjectCode(compilerHandle);
Jamie Madill006cbc52015-09-23 16:47:54 -0400280
281#ifndef NDEBUG
282 // Prefix translated shader with commented out un-translated shader.
283 // Useful in diagnostics tools which capture the shader source.
284 std::ostringstream shaderStream;
285 shaderStream << "// GLSL\n";
286 shaderStream << "//\n";
287
288 size_t curPos = 0;
289 while (curPos != std::string::npos)
290 {
Jamie Madill15243d92016-04-26 13:41:35 -0400291 size_t nextLine = mState.mSource.find("\n", curPos);
Jamie Madill006cbc52015-09-23 16:47:54 -0400292 size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
293
Jamie Madill15243d92016-04-26 13:41:35 -0400294 shaderStream << "// " << mState.mSource.substr(curPos, len);
Jamie Madill006cbc52015-09-23 16:47:54 -0400295
296 curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
297 }
298 shaderStream << "\n\n";
Jamie Madill15243d92016-04-26 13:41:35 -0400299 shaderStream << mState.mTranslatedSource;
300 mState.mTranslatedSource = shaderStream.str();
Jamie Madill006cbc52015-09-23 16:47:54 -0400301#endif
302
303 // Gather the shader information
Jamie Madill15243d92016-04-26 13:41:35 -0400304 mState.mShaderVersion = ShGetShaderVersion(compilerHandle);
Jamie Madill006cbc52015-09-23 16:47:54 -0400305
Jamie Madill15243d92016-04-26 13:41:35 -0400306 mState.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
307 mState.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
308 mState.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
Jamie Madill006cbc52015-09-23 16:47:54 -0400309
Martin Radev4c4c8e72016-08-04 12:25:34 +0300310 switch (mState.mShaderType)
Jamie Madill006cbc52015-09-23 16:47:54 -0400311 {
Martin Radev4c4c8e72016-08-04 12:25:34 +0300312 case GL_COMPUTE_SHADER:
313 {
314 mState.mLocalSize = ShGetComputeShaderLocalGroupSize(compilerHandle);
315 break;
316 }
317 case GL_VERTEX_SHADER:
318 {
319 mState.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
320 break;
321 }
322 case GL_FRAGMENT_SHADER:
323 {
324 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
325 std::sort(mState.mVaryings.begin(), mState.mVaryings.end(), CompareShaderVar);
326 mState.mActiveOutputVariables =
327 GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
328 break;
329 }
330 default:
331 UNREACHABLE();
Jamie Madill006cbc52015-09-23 16:47:54 -0400332 }
333
Jamie Madill15243d92016-04-26 13:41:35 -0400334 ASSERT(!mState.mTranslatedSource.empty());
Jamie Madill006cbc52015-09-23 16:47:54 -0400335
336 mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337}
338
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000339void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000340{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000341 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000342}
343
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000344void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000345{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000346 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000347
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000348 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000349 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000350 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000351 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352}
353
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000354unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000355{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000356 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000357}
358
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000359bool Shader::isFlaggedForDeletion() const
360{
361 return mDeleteStatus;
362}
363
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000364void Shader::flagForDeletion()
365{
366 mDeleteStatus = true;
367}
368
Jamie Madill80a6fc02015-08-21 16:53:16 -0400369int Shader::getShaderVersion() const
370{
Jamie Madill15243d92016-04-26 13:41:35 -0400371 return mState.mShaderVersion;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400372}
373
Jamie Madill4cff2472015-08-21 16:53:18 -0400374const std::vector<sh::Varying> &Shader::getVaryings() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400375{
Jamie Madill15243d92016-04-26 13:41:35 -0400376 return mState.getVaryings();
Jamie Madilld15250e2014-09-03 09:40:44 -0400377}
378
379const std::vector<sh::Uniform> &Shader::getUniforms() const
380{
Jamie Madill15243d92016-04-26 13:41:35 -0400381 return mState.getUniforms();
Jamie Madilld15250e2014-09-03 09:40:44 -0400382}
383
384const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
385{
Jamie Madill15243d92016-04-26 13:41:35 -0400386 return mState.getInterfaceBlocks();
Jamie Madilld15250e2014-09-03 09:40:44 -0400387}
388
389const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
390{
Jamie Madill15243d92016-04-26 13:41:35 -0400391 return mState.getActiveAttributes();
Jamie Madilld15250e2014-09-03 09:40:44 -0400392}
393
Jamie Madilla0a9e122015-09-02 15:54:30 -0400394const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400395{
Jamie Madill15243d92016-04-26 13:41:35 -0400396 return mState.getActiveOutputVariables();
Jamie Madilld15250e2014-09-03 09:40:44 -0400397}
398
Jamie Madill437d2662014-12-05 14:23:35 -0500399int Shader::getSemanticIndex(const std::string &attributeName) const
400{
401 if (!attributeName.empty())
402 {
Jamie Madill15243d92016-04-26 13:41:35 -0400403 const auto &activeAttributes = mState.getActiveAttributes();
Jamie Madill437d2662014-12-05 14:23:35 -0500404
405 int semanticIndex = 0;
406 for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
407 {
408 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
409
410 if (attribute.name == attributeName)
411 {
412 return semanticIndex;
413 }
414
415 semanticIndex += gl::VariableRegisterCount(attribute.type);
416 }
417 }
418
419 return -1;
420}
421
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000422}