blob: 0b9b4f0080cdb843aa4a96a612b4d9da585e8efe [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
Jamie Madilld2c52e32015-10-14 17:07:05 -0400222 std::string sourcePath;
223 int additionalOptions =
224 mImplementation->prepareSourceAndReturnOptions(&sourceStream, &sourcePath);
Jamie Madill006cbc52015-09-23 16:47:54 -0400225 int compileOptions = (SH_OBJECT_CODE | SH_VARIABLES | additionalOptions);
226
227 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop indexes
228 // in fragment shaders. Shader compilation will fail. To provide a better error message we can
229 // instruct the compiler to pre-validate.
230 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
231 {
232 compileOptions |= SH_VALIDATE_LOOP_INDEXING;
233 }
234
235 std::string sourceString = sourceStream.str();
Jamie Madilld2c52e32015-10-14 17:07:05 -0400236 std::vector<const char *> sourceCStrings;
237
238 if (!sourcePath.empty())
239 {
240 sourceCStrings.push_back(sourcePath.c_str());
241 }
242
243 sourceCStrings.push_back(sourceString.c_str());
244
245 bool result =
246 ShCompile(compilerHandle, &sourceCStrings[0], sourceCStrings.size(), compileOptions);
Jamie Madill006cbc52015-09-23 16:47:54 -0400247
248 if (!result)
249 {
250 mInfoLog = ShGetInfoLog(compilerHandle);
251 TRACE("\n%s", mInfoLog.c_str());
252 mCompiled = false;
253 return;
254 }
255
256 mData.mTranslatedSource = ShGetObjectCode(compilerHandle);
257
258#ifndef NDEBUG
259 // Prefix translated shader with commented out un-translated shader.
260 // Useful in diagnostics tools which capture the shader source.
261 std::ostringstream shaderStream;
262 shaderStream << "// GLSL\n";
263 shaderStream << "//\n";
264
265 size_t curPos = 0;
266 while (curPos != std::string::npos)
267 {
268 size_t nextLine = mData.mSource.find("\n", curPos);
269 size_t len = (nextLine == std::string::npos) ? std::string::npos : (nextLine - curPos + 1);
270
271 shaderStream << "// " << mData.mSource.substr(curPos, len);
272
273 curPos = (nextLine == std::string::npos) ? std::string::npos : (nextLine + 1);
274 }
275 shaderStream << "\n\n";
276 shaderStream << mData.mTranslatedSource;
277 mData.mTranslatedSource = shaderStream.str();
278#endif
279
280 // Gather the shader information
281 mData.mShaderVersion = ShGetShaderVersion(compilerHandle);
282
283 mData.mVaryings = GetShaderVariables(ShGetVaryings(compilerHandle));
284 mData.mUniforms = GetShaderVariables(ShGetUniforms(compilerHandle));
285 mData.mInterfaceBlocks = GetShaderVariables(ShGetInterfaceBlocks(compilerHandle));
286
287 if (mData.mShaderType == GL_VERTEX_SHADER)
288 {
289 mData.mActiveAttributes = GetActiveShaderVariables(ShGetAttributes(compilerHandle));
290 }
291 else
292 {
293 ASSERT(mData.mShaderType == GL_FRAGMENT_SHADER);
294
295 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
296 std::sort(mData.mVaryings.begin(), mData.mVaryings.end(), CompareVarying);
297 mData.mActiveOutputVariables =
298 GetActiveShaderVariables(ShGetOutputVariables(compilerHandle));
299 }
300
301 ASSERT(!mData.mTranslatedSource.empty());
302
303 mCompiled = mImplementation->postTranslateCompile(compiler, &mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000304}
305
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000306void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000307{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000308 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000309}
310
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000311void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000312{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000313 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000314
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000315 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000316 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000317 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000318 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000319}
320
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000321unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000322{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000323 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000324}
325
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000326bool Shader::isFlaggedForDeletion() const
327{
328 return mDeleteStatus;
329}
330
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000331void Shader::flagForDeletion()
332{
333 mDeleteStatus = true;
334}
335
Jamie Madill80a6fc02015-08-21 16:53:16 -0400336int Shader::getShaderVersion() const
337{
Jamie Madill91445bc2015-09-23 16:47:53 -0400338 return mData.mShaderVersion;
Jamie Madill80a6fc02015-08-21 16:53:16 -0400339}
340
Jamie Madill4cff2472015-08-21 16:53:18 -0400341const std::vector<sh::Varying> &Shader::getVaryings() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400342{
Jamie Madill91445bc2015-09-23 16:47:53 -0400343 return mData.getVaryings();
Jamie Madilld15250e2014-09-03 09:40:44 -0400344}
345
346const std::vector<sh::Uniform> &Shader::getUniforms() const
347{
Jamie Madill91445bc2015-09-23 16:47:53 -0400348 return mData.getUniforms();
Jamie Madilld15250e2014-09-03 09:40:44 -0400349}
350
351const std::vector<sh::InterfaceBlock> &Shader::getInterfaceBlocks() const
352{
Jamie Madill91445bc2015-09-23 16:47:53 -0400353 return mData.getInterfaceBlocks();
Jamie Madilld15250e2014-09-03 09:40:44 -0400354}
355
356const std::vector<sh::Attribute> &Shader::getActiveAttributes() const
357{
Jamie Madill91445bc2015-09-23 16:47:53 -0400358 return mData.getActiveAttributes();
Jamie Madilld15250e2014-09-03 09:40:44 -0400359}
360
Jamie Madilla0a9e122015-09-02 15:54:30 -0400361const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables() const
Jamie Madilld15250e2014-09-03 09:40:44 -0400362{
Jamie Madill91445bc2015-09-23 16:47:53 -0400363 return mData.getActiveOutputVariables();
Jamie Madilld15250e2014-09-03 09:40:44 -0400364}
365
Jamie Madill437d2662014-12-05 14:23:35 -0500366int Shader::getSemanticIndex(const std::string &attributeName) const
367{
368 if (!attributeName.empty())
369 {
Jamie Madill91445bc2015-09-23 16:47:53 -0400370 const auto &activeAttributes = mData.getActiveAttributes();
Jamie Madill437d2662014-12-05 14:23:35 -0500371
372 int semanticIndex = 0;
373 for (size_t attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
374 {
375 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
376
377 if (attribute.name == attributeName)
378 {
379 return semanticIndex;
380 }
381
382 semanticIndex += gl::VariableRegisterCount(attribute.type);
383 }
384 }
385
386 return -1;
387}
388
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000389}