blob: a52cf5b9fb3532d118e4ae27225751a530590a07 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00002//
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Shader.cpp: Implements the gl::Shader class and its derived classes
9// VertexShader and FragmentShader. Implements GL shader objects and related
10// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
11
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000012#include "libGLESv2/Shader.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000013
daniel@transgaming.com29ab9522012-08-27 16:25:37 +000014#include "GLSLANG/ShaderLang.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/utilities.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000016#include "libGLESv2/renderer/Renderer.h"
17#include "libGLESv2/Constants.h"
18#include "libGLESv2/ResourceManager.h"
daniel@transgaming.combbf56f72010-04-20 18:52:13 +000019
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000020namespace gl
21{
22void *Shader::mFragmentCompiler = NULL;
23void *Shader::mVertexCompiler = NULL;
24
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +000025Shader::Shader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
26 : mHandle(handle), mRenderer(renderer), mResourceManager(manager)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000027{
28 mSource = NULL;
29 mHlsl = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000030 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000031
daniel@transgaming.com938009c2012-02-17 18:02:15 +000032 uncompile();
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +000033 initializeCompiler();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000034
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +000035 mRefCount = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000036 mDeleteStatus = false;
37}
38
39Shader::~Shader()
40{
41 delete[] mSource;
42 delete[] mHlsl;
daniel@transgaming.comcba50572010-03-28 19:36:09 +000043 delete[] mInfoLog;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000044}
45
daniel@transgaming.com6c785212010-03-30 03:36:17 +000046GLuint Shader::getHandle() const
47{
48 return mHandle;
49}
50
shannon.woods%transgaming.com@gtempaccount.com5f339332013-04-13 03:29:02 +000051void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000052{
53 delete[] mSource;
54 int totalLength = 0;
55
56 for (int i = 0; i < count; i++)
57 {
58 if (length && length[i] >= 0)
59 {
60 totalLength += length[i];
61 }
62 else
63 {
64 totalLength += (int)strlen(string[i]);
65 }
66 }
67
68 mSource = new char[totalLength + 1];
69 char *code = mSource;
70
71 for (int i = 0; i < count; i++)
72 {
73 int stringLength;
74
75 if (length && length[i] >= 0)
76 {
77 stringLength = length[i];
78 }
79 else
80 {
81 stringLength = (int)strlen(string[i]);
82 }
83
84 strncpy(code, string[i], stringLength);
85 code += stringLength;
86 }
87
88 mSource[totalLength] = '\0';
89}
90
daniel@transgaming.comcba50572010-03-28 19:36:09 +000091int Shader::getInfoLogLength() const
92{
93 if (!mInfoLog)
94 {
95 return 0;
96 }
97 else
98 {
99 return strlen(mInfoLog) + 1;
100 }
101}
102
103void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
104{
105 int index = 0;
106
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000107 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000108 {
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000109 if (mInfoLog)
110 {
111 index = std::min(bufSize - 1, (int)strlen(mInfoLog));
112 memcpy(infoLog, mInfoLog, index);
113 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000114
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000115 infoLog[index] = '\0';
116 }
117
118 if (length)
119 {
120 *length = index;
121 }
122}
123
124int Shader::getSourceLength() const
125{
126 if (!mSource)
127 {
128 return 0;
129 }
130 else
131 {
132 return strlen(mSource) + 1;
133 }
134}
135
zmo@google.coma574f782011-10-03 21:45:23 +0000136int Shader::getTranslatedSourceLength() const
137{
138 if (!mHlsl)
139 {
140 return 0;
141 }
142 else
143 {
144 return strlen(mHlsl) + 1;
145 }
146}
147
148void Shader::getSourceImpl(char *source, GLsizei bufSize, GLsizei *length, char *buffer)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000149{
150 int index = 0;
151
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000152 if (bufSize > 0)
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000153 {
daniel@transgaming.com807d8c32012-04-04 15:06:04 +0000154 if (source)
155 {
156 index = std::min(bufSize - 1, (int)strlen(source));
157 memcpy(buffer, source, index);
158 }
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000159
zmo@google.coma574f782011-10-03 21:45:23 +0000160 buffer[index] = '\0';
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000161 }
162
163 if (length)
164 {
165 *length = index;
166 }
167}
168
zmo@google.coma574f782011-10-03 21:45:23 +0000169void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer)
170{
171 getSourceImpl(mSource, bufSize, length, buffer);
172}
173
174void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
175{
176 getSourceImpl(mHlsl, bufSize, length, buffer);
177}
178
daniel@transgaming.comc5c9e3c2012-12-20 21:12:32 +0000179const sh::ActiveUniforms &Shader::getUniforms()
180{
181 return mActiveUniforms;
182}
183
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +0000184const sh::ActiveInterfaceBlocks &Shader::getInterfaceBlocks()
185{
186 return mActiveInterfaceBlocks;
187}
188
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000189bool Shader::isCompiled()
190{
191 return mHlsl != NULL;
192}
193
daniel@transgaming.com0e3358a2010-04-05 20:32:42 +0000194const char *Shader::getHLSL()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000195{
196 return mHlsl;
197}
198
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000199void Shader::addRef()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000200{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000201 mRefCount++;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000202}
203
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000204void Shader::release()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000205{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000206 mRefCount--;
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000207
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000208 if (mRefCount == 0 && mDeleteStatus)
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000209 {
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000210 mResourceManager->deleteShader(mHandle);
daniel@transgaming.com71cd8682010-04-29 03:35:25 +0000211 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000212}
213
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000214unsigned int Shader::getRefCount() const
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000215{
daniel@transgaming.comda13f3e2010-07-28 19:20:56 +0000216 return mRefCount;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000217}
218
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000219bool Shader::isFlaggedForDeletion() const
220{
221 return mDeleteStatus;
222}
223
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000224void Shader::flagForDeletion()
225{
226 mDeleteStatus = true;
227}
228
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000229// Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
230void Shader::initializeCompiler()
231{
232 if (!mFragmentCompiler)
233 {
234 int result = ShInitialize();
235
236 if (result)
237 {
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +0000238 ShShaderOutput hlslVersion = (mRenderer->getMajorShaderModel() >= 4) ? SH_HLSL11_OUTPUT : SH_HLSL9_OUTPUT;
239
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000240 ShBuiltInResources resources;
241 ShInitBuiltInResources(&resources);
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000242
243 resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
shannon.woods@transgaming.com4e482042013-01-25 21:54:18 +0000244 resources.MaxVertexUniformVectors = mRenderer->getMaxVertexUniformVectors();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000245 resources.MaxVaryingVectors = mRenderer->getMaxVaryingVectors();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000246 resources.MaxVertexTextureImageUnits = mRenderer->getMaxVertexTextureImageUnits();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000247 resources.MaxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000248 resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
shannon.woods@transgaming.com254317d2013-01-25 21:54:09 +0000249 resources.MaxFragmentUniformVectors = mRenderer->getMaxFragmentUniformVectors();
shannon.woods%transgaming.com@gtempaccount.come266c832013-04-13 03:31:48 +0000250 resources.MaxDrawBuffers = mRenderer->getMaxRenderTargets();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000251 resources.OES_standard_derivatives = mRenderer->getDerivativeInstructionSupport();
shannon.woods%transgaming.com@gtempaccount.come266c832013-04-13 03:31:48 +0000252 resources.EXT_draw_buffers = mRenderer->getMaxRenderTargets() > 1;
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000253 // resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported.
shannon.woods%transgaming.com@gtempaccount.com331192d2013-04-13 03:27:57 +0000254 resources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp
shannonwoods@chromium.org74b86cf2013-05-30 00:02:58 +0000255 // GLSL ES 3.0 constants
256 resources.MaxVertexOutputVectors = mRenderer->getMaxVaryingVectors();
257 resources.MaxFragmentInputVectors = mRenderer->getMaxVaryingVectors();
258 resources.MinProgramTexelOffset = -8; // D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE
259 resources.MaxProgramTexelOffset = 7; // D3D10_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000260
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +0000261 mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, hlslVersion, &resources);
262 mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, hlslVersion, &resources);
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000263 }
264 }
265}
266
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000267void Shader::releaseCompiler()
268{
269 ShDestruct(mFragmentCompiler);
270 ShDestruct(mVertexCompiler);
271
272 mFragmentCompiler = NULL;
273 mVertexCompiler = NULL;
alokp@chromium.org90033b92010-05-24 15:02:43 +0000274
275 ShFinalize();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000276}
277
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000278void Shader::parseVaryings()
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000279{
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000280 if (mHlsl)
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000281 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000282 const char *input = strstr(mHlsl, "// Varyings") + 12;
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000283
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000284 while(true)
285 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000286 char string1[256];
287 char string2[256];
288 char string3[256];
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000289
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000290 int matches = sscanf(input, "static %255s %255s %255s", string1, string2, string3);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000291
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000292 char *interpolation = "linear"; // Default
293 char *type = string1;
294 char *name = string2;
295
296 if (matches == 0)
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000297 {
298 break;
299 }
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000300 else if (matches == 3)
301 {
302 if (string3[0] != '=') // Explicit interpolation qualifier
303 {
304 type = string2;
305 name = string3;
306 }
307 }
308 else UNREACHABLE();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000309
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000310 char *array = strstr(name, "[");
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000311 int size = 1;
312
313 if (array)
314 {
315 size = atoi(array + 1);
316 *array = '\0';
317 }
318
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000319 mVaryings.push_back(Varying(parseInterpolation(interpolation), parseType(type), name, size, array != NULL));
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000320
321 input = strstr(input, ";") + 2;
322 }
323
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000324 mUsesMultipleRenderTargets = strstr(mHlsl, "GL_USES_MRT") != NULL;
325 mUsesFragColor = strstr(mHlsl, "GL_USES_FRAG_COLOR") != NULL;
326 mUsesFragData = strstr(mHlsl, "GL_USES_FRAG_DATA") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000327 mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
328 mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
daniel@transgaming.combe5a0862010-07-28 19:20:37 +0000329 mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
330 mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000331 mUsesDepthRange = strstr(mHlsl, "GL_USES_DEPTH_RANGE") != NULL;
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000332 }
daniel@transgaming.com09fbfef2010-04-22 13:35:31 +0000333}
334
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000335void Shader::resetVaryingsRegisterAssignment()
336{
337 for (VaryingList::iterator var = mVaryings.begin(); var != mVaryings.end(); var++)
338 {
339 var->reg = -1;
340 var->col = -1;
341 }
342}
343
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000344// initialize/clean up previous state
345void Shader::uncompile()
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000346{
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000347 // set by compileToHLSL
348 delete[] mHlsl;
349 mHlsl = NULL;
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000350 delete[] mInfoLog;
351 mInfoLog = NULL;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000352
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000353 // set by parseVaryings
354 mVaryings.clear();
355
shannon.woods%transgaming.com@gtempaccount.comaa8b5cf2013-04-13 03:31:55 +0000356 mUsesMultipleRenderTargets = false;
357 mUsesFragColor = false;
358 mUsesFragData = false;
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000359 mUsesFragCoord = false;
360 mUsesFrontFacing = false;
361 mUsesPointSize = false;
362 mUsesPointCoord = false;
shannonwoods@chromium.org03299882013-05-30 00:05:26 +0000363 mUsesDepthRange = false;
daniel@transgaming.comc5c9e3c2012-12-20 21:12:32 +0000364
365 mActiveUniforms.clear();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +0000366 mActiveInterfaceBlocks.clear();
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000367}
368
369void Shader::compileToHLSL(void *compiler)
370{
371 // ensure we don't pass a NULL source to the compiler
daniel@transgaming.come3e826d2012-11-28 19:42:35 +0000372 const char *source = "\0";
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000373 if (mSource)
374 {
375 source = mSource;
376 }
377
daniel@transgaming.com0725e7d2012-02-17 18:02:20 +0000378 // ensure the compiler is loaded
379 initializeCompiler();
380
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000381 int compileOptions = SH_OBJECT_CODE;
382 std::string sourcePath;
383 if (perfActive())
384 {
385 sourcePath = getTempPath();
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000386 writeFile(sourcePath.c_str(), source, strlen(source));
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000387 compileOptions |= SH_LINE_DIRECTIVES;
388 }
389
390 int result;
391 if (sourcePath.empty())
392 {
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000393 result = ShCompile(compiler, &source, 1, compileOptions);
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000394 }
395 else
396 {
397 const char* sourceStrings[2] =
398 {
399 sourcePath.c_str(),
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000400 source
apatrick@chromium.org0f4cefe2011-01-26 19:30:57 +0000401 };
402
403 result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
404 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000405
shannon.woods%transgaming.com@gtempaccount.com0bbed382013-04-13 03:38:07 +0000406 size_t shaderVersion = 100;
407 ShGetInfo(compiler, SH_SHADER_VERSION, &shaderVersion);
408
409 if (shaderVersion == 300 && mRenderer->getCurrentClientVersion() < 3)
410 {
411 const char versionError[] = "GLSL ES 3.00 is not supported by OpenGL ES 2.0 contexts";
412 mInfoLog = new char[sizeof(versionError) + 1];
413 strcpy(mInfoLog, versionError);
414
415 TRACE("\n%s", mInfoLog);
416 }
417 else if (result)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000418 {
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000419 size_t objCodeLen = 0;
alokp@chromium.org7beea402010-09-15 21:18:34 +0000420 ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
421 mHlsl = new char[objCodeLen];
422 ShGetObjectCode(compiler, mHlsl);
daniel@transgaming.comc5c9e3c2012-12-20 21:12:32 +0000423
424 void *activeUniforms;
425 ShGetInfoPointer(compiler, SH_ACTIVE_UNIFORMS_ARRAY, &activeUniforms);
426 mActiveUniforms = *(sh::ActiveUniforms*)activeUniforms;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000427 }
428 else
429 {
shannon.woods@transgaming.comd64b3da2013-02-28 23:19:26 +0000430 size_t infoLogLen = 0;
alokp@chromium.org7beea402010-09-15 21:18:34 +0000431 ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
432 mInfoLog = new char[infoLogLen];
433 ShGetInfoLog(compiler, mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000434
daniel@transgaming.comcba50572010-03-28 19:36:09 +0000435 TRACE("\n%s", mInfoLog);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000436 }
437}
438
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +0000439Interpolation Shader::parseInterpolation(const std::string &type)
440{
441 if (type == "linear")
442 {
443 return Smooth;
444 }
445 else if (type == "centroid")
446 {
447 return Centroid;
448 }
449 else if (type == "nointerpolation")
450 {
451 return Flat;
452 }
453 else UNREACHABLE();
454
455 return Smooth;
456}
457
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000458GLenum Shader::parseType(const std::string &type)
459{
460 if (type == "float")
461 {
462 return GL_FLOAT;
463 }
464 else if (type == "float2")
465 {
466 return GL_FLOAT_VEC2;
467 }
468 else if (type == "float3")
469 {
470 return GL_FLOAT_VEC3;
471 }
472 else if (type == "float4")
473 {
474 return GL_FLOAT_VEC4;
475 }
476 else if (type == "float2x2")
477 {
478 return GL_FLOAT_MAT2;
479 }
480 else if (type == "float3x3")
481 {
482 return GL_FLOAT_MAT3;
483 }
484 else if (type == "float4x4")
485 {
486 return GL_FLOAT_MAT4;
487 }
488 else UNREACHABLE();
489
490 return GL_NONE;
491}
492
493// true if varying x has a higher priority in packing than y
494bool Shader::compareVarying(const Varying &x, const Varying &y)
495{
496 if(x.type == y.type)
497 {
498 return x.size > y.size;
499 }
500
501 switch (x.type)
502 {
503 case GL_FLOAT_MAT4: return true;
504 case GL_FLOAT_MAT2:
505 switch(y.type)
506 {
507 case GL_FLOAT_MAT4: return false;
508 case GL_FLOAT_MAT2: return true;
509 case GL_FLOAT_VEC4: return true;
510 case GL_FLOAT_MAT3: return true;
511 case GL_FLOAT_VEC3: return true;
512 case GL_FLOAT_VEC2: return true;
513 case GL_FLOAT: return true;
514 default: UNREACHABLE();
515 }
516 break;
517 case GL_FLOAT_VEC4:
518 switch(y.type)
519 {
520 case GL_FLOAT_MAT4: return false;
521 case GL_FLOAT_MAT2: return false;
522 case GL_FLOAT_VEC4: return true;
523 case GL_FLOAT_MAT3: return true;
524 case GL_FLOAT_VEC3: return true;
525 case GL_FLOAT_VEC2: return true;
526 case GL_FLOAT: return true;
527 default: UNREACHABLE();
528 }
529 break;
530 case GL_FLOAT_MAT3:
531 switch(y.type)
532 {
533 case GL_FLOAT_MAT4: return false;
534 case GL_FLOAT_MAT2: return false;
535 case GL_FLOAT_VEC4: return false;
536 case GL_FLOAT_MAT3: return true;
537 case GL_FLOAT_VEC3: return true;
538 case GL_FLOAT_VEC2: return true;
539 case GL_FLOAT: return true;
540 default: UNREACHABLE();
541 }
542 break;
543 case GL_FLOAT_VEC3:
544 switch(y.type)
545 {
546 case GL_FLOAT_MAT4: return false;
547 case GL_FLOAT_MAT2: return false;
548 case GL_FLOAT_VEC4: return false;
549 case GL_FLOAT_MAT3: return false;
550 case GL_FLOAT_VEC3: return true;
551 case GL_FLOAT_VEC2: return true;
552 case GL_FLOAT: return true;
553 default: UNREACHABLE();
554 }
555 break;
556 case GL_FLOAT_VEC2:
557 switch(y.type)
558 {
559 case GL_FLOAT_MAT4: return false;
560 case GL_FLOAT_MAT2: return false;
561 case GL_FLOAT_VEC4: return false;
562 case GL_FLOAT_MAT3: return false;
563 case GL_FLOAT_VEC3: return false;
564 case GL_FLOAT_VEC2: return true;
565 case GL_FLOAT: return true;
566 default: UNREACHABLE();
567 }
568 break;
569 case GL_FLOAT: return false;
570 default: UNREACHABLE();
571 }
572
573 return false;
574}
575
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +0000576VertexShader::VertexShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
577 : Shader(manager, renderer, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000578{
579}
580
581VertexShader::~VertexShader()
582{
583}
584
585GLenum VertexShader::getType()
586{
587 return GL_VERTEX_SHADER;
588}
589
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000590void VertexShader::uncompile()
591{
592 Shader::uncompile();
593
594 // set by ParseAttributes
595 mAttributes.clear();
daniel@transgaming.come3e826d2012-11-28 19:42:35 +0000596}
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000597
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000598void VertexShader::compile()
599{
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000600 uncompile();
601
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000602 compileToHLSL(mVertexCompiler);
603 parseAttributes();
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000604 parseVaryings();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000605}
606
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000607int VertexShader::getSemanticIndex(const std::string &attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000608{
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000609 if (!attributeName.empty())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000610 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000611 int semanticIndex = 0;
612 for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000613 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000614 if (attribute->name == attributeName)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000615 {
daniel@transgaming.comb4ff1f82010-04-22 13:35:18 +0000616 return semanticIndex;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000617 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000618
619 semanticIndex += VariableRowCount(attribute->type);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000620 }
621 }
622
623 return -1;
624}
625
626void VertexShader::parseAttributes()
627{
daniel@transgaming.com2cdf8332012-02-17 18:00:50 +0000628 const char *hlsl = getHLSL();
629 if (hlsl)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000630 {
daniel@transgaming.com2cdf8332012-02-17 18:00:50 +0000631 const char *input = strstr(hlsl, "// Attributes") + 14;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000633 while(true)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000634 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000635 char attributeType[256];
636 char attributeName[256];
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000637
daniel@transgaming.com7ea933f2010-12-12 08:52:42 +0000638 int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000639
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000640 if (matches != 2)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000641 {
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000642 break;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000643 }
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000644
645 mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
646
647 input = strstr(input, ";") + 2;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000648 }
649 }
650}
651
shannon.woods@transgaming.comb73964e2013-01-25 21:49:14 +0000652FragmentShader::FragmentShader(ResourceManager *manager, const rx::Renderer *renderer, GLuint handle)
653 : Shader(manager, renderer, handle)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000654{
655}
656
657FragmentShader::~FragmentShader()
658{
659}
660
661GLenum FragmentShader::getType()
662{
663 return GL_FRAGMENT_SHADER;
664}
665
666void FragmentShader::compile()
667{
daniel@transgaming.com938009c2012-02-17 18:02:15 +0000668 uncompile();
669
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000670 compileToHLSL(mFragmentCompiler);
daniel@transgaming.com4af7acc2010-05-14 17:30:53 +0000671 parseVaryings();
daniel@transgaming.comcde6a612012-02-17 18:01:10 +0000672 mVaryings.sort(compareVarying);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000673}
674}