blob: 98fcdca80244c0c57a3b949238920493016c3356 [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
51// true if varying x has a higher priority in packing than y
52bool CompareVarying(const sh::Varying &x, const sh::Varying &y)
53{
54 if (x.type == y.type)
55 {
56 return x.arraySize > y.arraySize;
57 }
58
59 // Special case for handling structs: we sort these to the end of the list
60 if (x.type == GL_STRUCT_ANGLEX)
61 {
62 return false;
63 }
64
65 if (y.type == GL_STRUCT_ANGLEX)
66 {
67 return true;
68 }
69
70 return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
71}
72
73} // anonymous namespace
74
Jamie Madill91445bc2015-09-23 16:47:53 -040075Shader::Data::Data(GLenum shaderType) : mShaderType(shaderType), mShaderVersion(100)
76{
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
Brandon Jonesf05cdee2014-08-27 15:24:07 -0700173void Shader::getSourceImpl(const std::string &source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000174{
175 int index = 0;
176
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000177 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000178 {
Geoff Lang536d7262013-08-26 17:04:20 -0400179 index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
180 memcpy(buffer, source.c_str(), index);
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000181
zmo@google.coma574f782011-10-03 21:45:23 +0000182 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000183 }
184
185 if (length)
186 {
187 *length = index;
188 }
189}
190
Geoff Lang536d7262013-08-26 17:04:20 -0400191void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000192{
Jamie Madill006cbc52015-09-23 16:47:54 -0400193 getSourceImpl(mData.mSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000194}
195
Geoff Lang536d7262013-08-26 17:04:20 -0400196void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer) const
zmo@google.coma574f782011-10-03 21:45:23 +0000197{
Jamie Madill91445bc2015-09-23 16:47:53 -0400198 getSourceImpl(mData.mTranslatedSource, bufSize, length, buffer);
zmo@google.coma574f782011-10-03 21:45:23 +0000199}
200
Tibor den Ouden97049c62014-10-06 21:39:16 +0200201void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer) const
202{
Jamie Madill91445bc2015-09-23 16:47:53 -0400203 std::string debugInfo(mImplementation->getDebugInfo());
Tibor den Ouden97049c62014-10-06 21:39:16 +0200204 getSourceImpl(debugInfo, bufSize, length, buffer);
205}
206
Geoff Lang492a7e42014-11-05 13:27:06 -0500207void Shader::compile(Compiler *compiler)
Jamie Madillbf9cce22014-07-18 10:33:09 -0400208{
Jamie Madill91445bc2015-09-23 16:47:53 -0400209 mData.mTranslatedSource.clear();
Jamie Madill006cbc52015-09-23 16:47:54 -0400210 mInfoLog.clear();
Jamie Madill91445bc2015-09-23 16:47:53 -0400211 mData.mShaderVersion = 100;
212 mData.mVaryings.clear();
213 mData.mUniforms.clear();
214 mData.mInterfaceBlocks.clear();
215 mData.mActiveAttributes.clear();
216 mData.mActiveOutputVariables.clear();
217
Jamie Madill006cbc52015-09-23 16:47:54 -0400218 ShHandle compilerHandle = compiler->getCompilerHandle(mData.mShaderType);
219
220 std::stringstream sourceStream;
221
222 int additionalOptions = mImplementation->prepareSourceAndReturnOptions(&sourceStream);
223 int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
224
225 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
226 // in fragment shaders. Shader compilation will fail. To provide a better error message we can
227 // instruct the compiler to pre-validate.
228 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
229 {
230 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
231 }
232
233 std::string sourceString = sourceStream.str();
234 const char *sourceCString = sourceString.c_str();
235 bool result = ShCompile(compilerHandle, &sourceCString, 1, compileOptions);
236
237 if (!result)
238 {
239 mInfoLog = ShGetInfoLog(compilerHandle);
240 TRACE("\n%s", mInfoLog.c_str());
241 mCompiled = false;
242 return;
243 }
244
245 mData.mTranslatedSource = ShGetObjectCode(compilerHandle);
246
247#ifndef NDEBUG
248 // Prefix translated shader with commented out un-translated shader.
249 // Useful in diagnostics tools which capture the shader source.
250 std::ostringstream shaderStream;
251 shaderStream << "// GLSL\n";
252 shaderStream << "//\n";
253
254 size_t curPos = 0;
255 while (curPos != std::string::npos)
256 {
257 size_t nextLine = mData.mSource.find("\n", curPos);
258 size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
259
260 shaderStream << "// " << mData.mSource.substr(curPos, len);
261
262 curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
263 }
264 shaderStream << "\n\n";
265 shaderStream << mData.mTranslatedSource;
266 mData.mTranslatedSource = shaderStream.str();
267#endif
268
269 // Gather the shader information
270 mData.mShaderVersion = ShGetShaderVersion(compilerHandle);
271
272 mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
273 mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
274 mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
275
276 if (mData.mShaderType == GL_VERTEX_SHADER)
277 {
278 mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
279 }
280 else
281 {
282 ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER);
283
284 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
285 std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareVarying);
286 mData.mActiveOutputVariables =
287 GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
288 }
289
290 ASSERT(!mData.mTranslatedSource.empty());
291
292 mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000293}
294
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000295void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000296{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000297 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000298}
299
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000300void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000301{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000302 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000303
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000304 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000305 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000306 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000307 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000308}
309
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000310unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000311{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000312 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000313}
314
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000315bool Shader::isFlaggedForDeletion() const
316{
317 return mDeleteStatus;
318}
319
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000320void Shader::flagForDeletion()
321{
322 mDeleteStatus = true;
323}
324
Jamie Madill80a6fc02015-08-21 16:53:16 -0400325int Shader::getShaderVersion() const
326{
Jamie Madill91445bc2015-09-23 16:47:53 -0400327 return mData.mShaderVersion;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400328}
329
Jamie Madill4cff2472015-08-21 16:53:18 -0400330const std::vector<sh::Varying> &Shader::getVaryings() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400331{
Jamie Madill91445bc2015-09-23 16:47:53 -0400332 return mData.getVaryings();
Jamie Madilld15250e2014-09-03 09:40:44 -0400333}
334
335const std::vector<sh::Uniform> &Shader::getUniforms() const
336{
Jamie Madill91445bc2015-09-23 16:47:53 -0400337 return mData.getUniforms();
Jamie Madilld15250e2014-09-03 09:40:44 -0400338}
339
340const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
341{
Jamie Madill91445bc2015-09-23 16:47:53 -0400342 return mData.getInterfaceBlocks();
Jamie Madilld15250e2014-09-03 09:40:44 -0400343}
344
345const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
346{
Jamie Madill91445bc2015-09-23 16:47:53 -0400347 return mData.getActiveAttributes();
Jamie Madilld15250e2014-09-03 09:40:44 -0400348}
349
Jamie Madilla0a9e122015-09-02 15:54:30 -0400350const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400351{
Jamie Madill91445bc2015-09-23 16:47:53 -0400352 return mData.getActiveOutputVariables();
Jamie Madilld15250e2014-09-03 09:40:44 -0400353}
354
Jamie Madill437d2662014-12-05 14:23:35 -0500355int Shader::getSemanticIndex(const std::string &attributeName) const
356{
357 if (!attributeName.empty())
358 {
Jamie Madill91445bc2015-09-23 16:47:53 -0400359 const auto &activeAttributes = mData.getActiveAttributes();
Jamie Madill437d2662014-12-05 14:23:35 -0500360
361 int semanticIndex = 0;
362 for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
363 {
364 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
365
366 if (attribute.name == attributeName)
367 {
368 return semanticIndex;
369 }
370
371 semanticIndex += gl::VariableRegisterCount(attribute.type);
372 }
373 }
374
375 return -1;
376}
377
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000378}