blob: d7d5d94494228aa328f98b9e96ad7cf822cf50ee [file] [log] [blame]
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001//
Geoff Lang48dcae72014-02-05 16:28:24 -05002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +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// Program.cpp: Implements the gl::Program class. Implements GL program objects
8// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000010#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000011#include "libGLESv2/ProgramBinary.h"
Geoff Lang04fb89a2014-06-09 15:05:36 -040012#include "libGLESv2/Framebuffer.h"
Jamie Madillaef95de2014-09-05 10:12:41 -040013#include "libGLESv2/FramebufferAttachment.h"
Geoff Lang04fb89a2014-06-09 15:05:36 -040014#include "libGLESv2/Renderbuffer.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000015#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000016
17#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000018#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000019#include "common/utilities.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020#include "common/platform.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000021
22#include "libGLESv2/main.h"
23#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000024#include "libGLESv2/Program.h"
Brandon Jonesc9610c52014-08-25 17:02:59 -070025#include "libGLESv2/renderer/ProgramImpl.h"
Brandon Jonesf05cdee2014-08-27 15:24:07 -070026#include "libGLESv2/renderer/d3d/ShaderD3D.h"
Nicolas Capense6050882013-07-08 10:43:10 -040027#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000028#include "libGLESv2/Buffer.h"
Jamie Madillc600c8c2014-05-16 11:22:21 -040029#include "common/blocklayout.h"
Jamie Madillc2141fb2013-08-30 13:21:08 -040030
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031namespace gl
32{
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000033
Jamie Madill1b2a8f92014-05-14 13:09:39 -040034namespace
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000035{
36
Geoff Lang76b10c92014-09-05 16:28:14 -040037GLenum GetTextureType(GLenum samplerType)
Jamie Madill66d43d22014-07-11 17:02:03 -040038{
39 switch (samplerType)
40 {
41 case GL_SAMPLER_2D:
42 case GL_INT_SAMPLER_2D:
43 case GL_UNSIGNED_INT_SAMPLER_2D:
44 case GL_SAMPLER_2D_SHADOW:
Geoff Lang76b10c92014-09-05 16:28:14 -040045 return GL_TEXTURE_2D;
Jamie Madill66d43d22014-07-11 17:02:03 -040046 case GL_SAMPLER_3D:
47 case GL_INT_SAMPLER_3D:
48 case GL_UNSIGNED_INT_SAMPLER_3D:
Geoff Lang76b10c92014-09-05 16:28:14 -040049 return GL_TEXTURE_3D;
Jamie Madill66d43d22014-07-11 17:02:03 -040050 case GL_SAMPLER_CUBE:
51 case GL_SAMPLER_CUBE_SHADOW:
Geoff Lang76b10c92014-09-05 16:28:14 -040052 return GL_TEXTURE_CUBE_MAP;
Jamie Madill66d43d22014-07-11 17:02:03 -040053 case GL_INT_SAMPLER_CUBE:
54 case GL_UNSIGNED_INT_SAMPLER_CUBE:
Geoff Lang76b10c92014-09-05 16:28:14 -040055 return GL_TEXTURE_CUBE_MAP;
Jamie Madill66d43d22014-07-11 17:02:03 -040056 case GL_SAMPLER_2D_ARRAY:
57 case GL_INT_SAMPLER_2D_ARRAY:
58 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
59 case GL_SAMPLER_2D_ARRAY_SHADOW:
Geoff Lang76b10c92014-09-05 16:28:14 -040060 return GL_TEXTURE_2D_ARRAY;
Jamie Madill66d43d22014-07-11 17:02:03 -040061 default: UNREACHABLE();
62 }
63
Geoff Lang76b10c92014-09-05 16:28:14 -040064 return GL_TEXTURE_2D;
Jamie Madill66d43d22014-07-11 17:02:03 -040065}
66
Jamie Madill8ff21ae2014-02-04 16:04:05 -050067unsigned int ParseAndStripArrayIndex(std::string* name)
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000068{
69 unsigned int subscript = GL_INVALID_INDEX;
70
71 // Strip any trailing array operator and retrieve the subscript
72 size_t open = name->find_last_of('[');
73 size_t close = name->find_last_of(']');
74 if (open != std::string::npos && close == name->length() - 1)
75 {
76 subscript = atoi(name->substr(open + 1).c_str());
77 name->erase(open);
78 }
79
80 return subscript;
81}
82
Jamie Madill3f2e61d2014-09-05 10:38:05 -040083void GetDefaultInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
Jamie Madillc5a83002014-02-14 16:41:25 -050084{
Jamie Madill3b7e2052014-03-17 09:47:43 -040085 size_t layoutIndex = 0;
Jamie Madillc5a83002014-02-14 16:41:25 -050086 for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
87 {
Jamie Madill3b7e2052014-03-17 09:47:43 -040088 ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS);
89
Jamie Madillf2575982014-06-25 16:04:54 -040090 const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -050091
92 if (shaderAttr.type != GL_NONE)
93 {
Jamie Madillac0a2672014-04-11 13:33:56 -040094 GLenum transposedType = TransposeMatrixType(shaderAttr.type);
95
96 for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++)
Jamie Madill3b7e2052014-03-17 09:47:43 -040097 {
98 VertexFormat *defaultFormat = &inputLayout[layoutIndex];
99
Jamie Madillf2575982014-06-25 16:04:54 -0400100 defaultFormat->mType = VariableComponentType(transposedType);
Jamie Madill3b7e2052014-03-17 09:47:43 -0400101 defaultFormat->mNormalized = false;
102 defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
Jamie Madillac0a2672014-04-11 13:33:56 -0400103 defaultFormat->mComponents = VariableColumnCount(transposedType);
Jamie Madill3b7e2052014-03-17 09:47:43 -0400104 }
Jamie Madillc5a83002014-02-14 16:41:25 -0500105 }
106 }
107}
108
Jamie Madillf6be8d72014-09-05 10:38:07 -0400109std::vector<GLenum> GetDefaultOutputLayoutFromShader(const std::vector<rx::PixelShaderOutputVariable> &shaderOutputVars)
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400110{
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400111 std::vector<GLenum> defaultPixelOutput(1);
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400112
113 ASSERT(!shaderOutputVars.empty());
114 defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex;
115
116 return defaultPixelOutput;
117}
118
Jamie Madilla6f267f2014-08-27 11:44:15 -0400119bool IsRowMajorLayout(const sh::InterfaceBlockField &var)
120{
121 return var.isRowMajorLayout;
122}
123
124bool IsRowMajorLayout(const sh::ShaderVariable &var)
125{
126 return false;
127}
128
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000129}
130
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400131VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000132 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000133{
134}
135
Geoff Lang04fb89a2014-06-09 15:05:36 -0400136ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[],
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400137 const GLenum signature[],
Jamie Madillc5a83002014-02-14 16:41:25 -0500138 rx::ShaderExecutable *shaderExecutable)
139 : mShaderExecutable(shaderExecutable)
140{
141 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
142 {
143 mInputs[attributeIndex] = inputLayout[attributeIndex];
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400144 mSignature[attributeIndex] = signature[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -0500145 }
146}
147
Jamie Madill8b4f8f82014-03-26 14:01:58 -0400148ProgramBinary::VertexExecutable::~VertexExecutable()
149{
Geoff Lang04fb89a2014-06-09 15:05:36 -0400150 SafeDelete(mShaderExecutable);
Jamie Madill8b4f8f82014-03-26 14:01:58 -0400151}
152
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400153bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const
Jamie Madillc5a83002014-02-14 16:41:25 -0500154{
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400155 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Jamie Madillc5a83002014-02-14 16:41:25 -0500156 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400157 if (mSignature[attributeIndex] != signature[attributeIndex])
Jamie Madillc5a83002014-02-14 16:41:25 -0500158 {
159 return false;
160 }
161 }
162
163 return true;
164}
165
Geoff Lang04fb89a2014-06-09 15:05:36 -0400166ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable)
167 : mOutputSignature(outputSignature),
168 mShaderExecutable(shaderExecutable)
169{
170}
171
172ProgramBinary::PixelExecutable::~PixelExecutable()
173{
174 SafeDelete(mShaderExecutable);
175}
176
Geoff Lang48dcae72014-02-05 16:28:24 -0500177LinkedVarying::LinkedVarying()
178{
179}
180
181LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
182 unsigned int semanticIndex, unsigned int semanticIndexCount)
183 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
184{
185}
186
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000187unsigned int ProgramBinary::mCurrentSerial = 1;
188
Brandon Jonesc9610c52014-08-25 17:02:59 -0700189ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500190 : RefCountObject(0),
Brandon Jonesc9610c52014-08-25 17:02:59 -0700191 mProgram(impl),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500192 mGeometryExecutable(NULL),
193 mUsedVertexSamplerRange(0),
194 mUsedPixelSamplerRange(0),
Jamie Madilld4cfa572014-07-08 10:00:32 -0400195 mDirtySamplerMapping(true),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500196 mValidated(false),
197 mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000198{
Brandon Jonesc9610c52014-08-25 17:02:59 -0700199 ASSERT(impl);
200
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000201 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
202 {
203 mSemanticIndex[index] = -1;
204 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000205}
206
207ProgramBinary::~ProgramBinary()
208{
Geoff Lang04fb89a2014-06-09 15:05:36 -0400209 reset();
Brandon Jonesc9610c52014-08-25 17:02:59 -0700210 SafeDelete(mProgram);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000211}
212
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000213unsigned int ProgramBinary::getSerial() const
214{
215 return mSerial;
216}
217
218unsigned int ProgramBinary::issueSerial()
219{
220 return mCurrentSerial++;
221}
222
Geoff Lang04fb89a2014-06-09 15:05:36 -0400223rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000224{
Jamie Madillaef95de2014-09-05 10:12:41 -0400225 std::vector<GLenum> outputs;
226
227 const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender();
228
229 for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
Geoff Lang04fb89a2014-06-09 15:05:36 -0400230 {
Jamie Madillaef95de2014-09-05 10:12:41 -0400231 const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
232
233 if (colorbuffer)
Geoff Lang04fb89a2014-06-09 15:05:36 -0400234 {
Jamie Madillaef95de2014-09-05 10:12:41 -0400235 outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding());
Geoff Lang04fb89a2014-06-09 15:05:36 -0400236 }
237 else
238 {
Jamie Madillaef95de2014-09-05 10:12:41 -0400239 outputs.push_back(GL_NONE);
Geoff Lang04fb89a2014-06-09 15:05:36 -0400240 }
241 }
242
243 return getPixelExecutableForOutputLayout(outputs);
244}
245
246rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
247{
248 for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
249 {
250 if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
251 {
252 return mPixelExecutables[executableIndex]->shaderExecutable();
253 }
254 }
255
Geoff Lang04fb89a2014-06-09 15:05:36 -0400256 InfoLog tempInfoLog;
Brandon Jones22502d52014-08-29 16:58:36 -0700257 rx::ShaderExecutable *pixelExecutable = mProgram->getPixelExecutableForOutputLayout(tempInfoLog, outputSignature,
258 mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Geoff Lang04fb89a2014-06-09 15:05:36 -0400259
260 if (!pixelExecutable)
261 {
262 std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
263 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
264 ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
265 }
266 else
267 {
268 mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
269 }
270
271 return pixelExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000272}
273
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400274rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000275{
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400276 GLenum signature[MAX_VERTEX_ATTRIBS];
Brandon Jones44151a92014-09-10 11:32:25 -0700277 mProgram->getInputLayoutSignature(inputLayout, signature);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400278
Jamie Madillc5a83002014-02-14 16:41:25 -0500279 for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
280 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400281 if (mVertexExecutables[executableIndex]->matchesSignature(signature))
Jamie Madillc5a83002014-02-14 16:41:25 -0500282 {
283 return mVertexExecutables[executableIndex]->shaderExecutable();
284 }
285 }
286
Jamie Madillc5a83002014-02-14 16:41:25 -0500287 InfoLog tempInfoLog;
Brandon Jones22502d52014-08-29 16:58:36 -0700288 rx::ShaderExecutable *vertexExecutable = mProgram->getVertexExecutableForInputLayout(tempInfoLog, inputLayout, mShaderAttributes,
289 mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -0500290
291 if (!vertexExecutable)
292 {
293 std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
294 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
295 ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
296 }
297 else
298 {
Geoff Lang04fb89a2014-06-09 15:05:36 -0400299 mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
Jamie Madillc5a83002014-02-14 16:41:25 -0500300 }
301
302 return vertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000303}
304
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500305rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000306{
307 return mGeometryExecutable;
308}
309
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000310GLuint ProgramBinary::getAttributeLocation(const char *name)
311{
312 if (name)
313 {
314 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
315 {
316 if (mLinkedAttribute[index].name == std::string(name))
317 {
318 return index;
319 }
320 }
321 }
322
323 return -1;
324}
325
326int ProgramBinary::getSemanticIndex(int attributeIndex)
327{
328 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400329
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000330 return mSemanticIndex[attributeIndex];
331}
332
333// Returns one more than the highest sampler index used.
334GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
335{
336 switch (type)
337 {
338 case SAMPLER_PIXEL:
339 return mUsedPixelSamplerRange;
340 case SAMPLER_VERTEX:
341 return mUsedVertexSamplerRange;
342 default:
343 UNREACHABLE();
344 return 0;
345 }
346}
347
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000348bool ProgramBinary::usesPointSize() const
349{
Brandon Jones44151a92014-09-10 11:32:25 -0700350 return mProgram->usesPointSize();
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000351}
352
Brandon Jones43a53e22014-08-28 16:23:22 -0700353GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000354{
355 GLint logicalTextureUnit = -1;
356
357 switch (type)
358 {
359 case SAMPLER_PIXEL:
Geoff Lang76b10c92014-09-05 16:28:14 -0400360 ASSERT(samplerIndex < caps.maxTextureImageUnits);
361 if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000362 {
363 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
364 }
365 break;
366 case SAMPLER_VERTEX:
Geoff Lang76b10c92014-09-05 16:28:14 -0400367 ASSERT(samplerIndex < caps.maxVertexTextureImageUnits);
368 if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000369 {
370 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
371 }
372 break;
373 default: UNREACHABLE();
374 }
375
Brandon Jones43a53e22014-08-28 16:23:22 -0700376 if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377 {
378 return logicalTextureUnit;
379 }
380
381 return -1;
382}
383
384// Returns the texture type for a given Direct3D 9 sampler type and
385// index (0-15 for the pixel shader and 0-3 for the vertex shader).
Geoff Lang76b10c92014-09-05 16:28:14 -0400386GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000387{
388 switch (type)
389 {
390 case SAMPLER_PIXEL:
Geoff Lang76b10c92014-09-05 16:28:14 -0400391 ASSERT(samplerIndex < mSamplersPS.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000392 ASSERT(mSamplersPS[samplerIndex].active);
393 return mSamplersPS[samplerIndex].textureType;
394 case SAMPLER_VERTEX:
Geoff Lang76b10c92014-09-05 16:28:14 -0400395 ASSERT(samplerIndex < mSamplersVS.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000396 ASSERT(mSamplersVS[samplerIndex].active);
397 return mSamplersVS[samplerIndex].textureType;
398 default: UNREACHABLE();
399 }
400
Geoff Lang76b10c92014-09-05 16:28:14 -0400401 return GL_TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000402}
403
404GLint ProgramBinary::getUniformLocation(std::string name)
405{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500406 unsigned int subscript = ParseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000407
408 unsigned int numUniforms = mUniformIndex.size();
409 for (unsigned int location = 0; location < numUniforms; location++)
410 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000411 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000412 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000413 const int index = mUniformIndex[location].index;
414 const bool isArray = mUniforms[index]->isArray();
415
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400416 if ((isArray && mUniformIndex[location].element == subscript) ||
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000417 (subscript == GL_INVALID_INDEX))
418 {
419 return location;
420 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000421 }
422 }
423
424 return -1;
425}
426
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000427GLuint ProgramBinary::getUniformIndex(std::string name)
428{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500429 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000430
431 // The app is not allowed to specify array indices other than 0 for arrays of basic types
432 if (subscript != 0 && subscript != GL_INVALID_INDEX)
433 {
434 return GL_INVALID_INDEX;
435 }
436
437 unsigned int numUniforms = mUniforms.size();
438 for (unsigned int index = 0; index < numUniforms; index++)
439 {
440 if (mUniforms[index]->name == name)
441 {
442 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
443 {
444 return index;
445 }
446 }
447 }
448
449 return GL_INVALID_INDEX;
450}
451
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000452GLuint ProgramBinary::getUniformBlockIndex(std::string name)
453{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500454 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000455
456 unsigned int numUniformBlocks = mUniformBlocks.size();
457 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
458 {
459 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
460 if (uniformBlock.name == name)
461 {
462 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
463 if (subscript == uniformBlock.elementIndex || arrayElementZero)
464 {
465 return blockIndex;
466 }
467 }
468 }
469
470 return GL_INVALID_INDEX;
471}
472
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000473UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
474{
475 ASSERT(blockIndex < mUniformBlocks.size());
476 return mUniformBlocks[blockIndex];
477}
478
Jamie Madilld1e78c92013-06-20 11:55:50 -0400479GLint ProgramBinary::getFragDataLocation(const char *name) const
480{
481 std::string baseName(name);
482 unsigned int arrayIndex;
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500483 arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madilld1e78c92013-06-20 11:55:50 -0400484
485 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
486 {
487 const VariableLocation &outputVariable = locationIt->second;
488
489 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
490 {
491 return static_cast<GLint>(locationIt->first);
492 }
493 }
494
495 return -1;
496}
497
Geoff Lang48dcae72014-02-05 16:28:24 -0500498size_t ProgramBinary::getTransformFeedbackVaryingCount() const
499{
500 return mTransformFeedbackLinkedVaryings.size();
501}
502
503const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
504{
505 return mTransformFeedbackLinkedVaryings[idx];
506}
507
508GLenum ProgramBinary::getTransformFeedbackBufferMode() const
509{
510 return mTransformFeedbackBufferMode;
511}
512
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000513template <typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400514static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
515{
516 ASSERT(dest != NULL);
517 ASSERT(dirtyFlag != NULL);
518
519 *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
520 *dest = source;
521}
522
523template <typename T>
Jamie Madill36398922014-05-20 14:51:53 -0400524void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000525{
Jamie Madillf2575982014-06-25 16:04:54 -0400526 const int components = VariableComponentCount(targetUniformType);
527 const GLenum targetBoolType = VariableBoolVectorType(targetUniformType);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000528
Jamie Madill36398922014-05-20 14:51:53 -0400529 LinkedUniform *targetUniform = getUniformByLocation(location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000530
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000531 int elementCount = targetUniform->elementCount();
532
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000533 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
534
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000535 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000536 {
Geoff Langbe4fdb32014-09-16 14:11:40 -0400537 T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000538
539 for (int i = 0; i < count; i++)
540 {
Geoff Lang61f54182014-09-16 14:10:02 -0400541 T *dest = target + (i * 4);
542 const T *source = v + (i * components);
543
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000544 for (int c = 0; c < components; c++)
545 {
Geoff Lang61f54182014-09-16 14:10:02 -0400546 SetIfDirty(dest + c, source[c], &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000547 }
548 for (int c = components; c < 4; c++)
549 {
Geoff Lang61f54182014-09-16 14:10:02 -0400550 SetIfDirty(dest + c, T(0), &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000551 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000552 }
553 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000554 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000555 {
Geoff Langbe4fdb32014-09-16 14:11:40 -0400556 GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000557
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000558 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000559 {
Geoff Lang61f54182014-09-16 14:10:02 -0400560 GLint *dest = boolParams + (i * 4);
561 const T *source = v + (i * components);
562
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000563 for (int c = 0; c < components; c++)
564 {
Geoff Lang61f54182014-09-16 14:10:02 -0400565 SetIfDirty(dest + c, (source[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE, &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000566 }
567 for (int c = components; c < 4; c++)
568 {
Geoff Lang61f54182014-09-16 14:10:02 -0400569 SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000570 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000571 }
572 }
Geoff Langbe4fdb32014-09-16 14:11:40 -0400573 else if (IsSampler(targetUniform->type))
574 {
575 ASSERT(targetUniformType == GL_INT);
576
577 GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
578
579 bool wasDirty = targetUniform->dirty;
580
581 for (int i = 0; i < count; i++)
582 {
583 GLint *dest = target + (i * 4);
584 const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
585
586 SetIfDirty(dest + 0, source[0], &targetUniform->dirty);
587 SetIfDirty(dest + 1, 0, &targetUniform->dirty);
588 SetIfDirty(dest + 2, 0, &targetUniform->dirty);
589 SetIfDirty(dest + 3, 0, &targetUniform->dirty);
590 }
591
592 if (!wasDirty && targetUniform->dirty)
593 {
594 mDirtySamplerMapping = true;
595 }
596 }
Jamie Madill36398922014-05-20 14:51:53 -0400597 else UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000598}
599
Jamie Madill36398922014-05-20 14:51:53 -0400600void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000601{
Jamie Madill36398922014-05-20 14:51:53 -0400602 setUniform(location, count, v, GL_FLOAT);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000603}
604
Jamie Madill36398922014-05-20 14:51:53 -0400605void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000606{
Jamie Madill36398922014-05-20 14:51:53 -0400607 setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000608}
609
Jamie Madill36398922014-05-20 14:51:53 -0400610void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000611{
Jamie Madill36398922014-05-20 14:51:53 -0400612 setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613}
614
Jamie Madill36398922014-05-20 14:51:53 -0400615void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000616{
Jamie Madill36398922014-05-20 14:51:53 -0400617 setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000618}
619
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000620template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400621bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000622{
Geoff Langae1990c2014-05-12 16:57:14 -0400623 bool dirty = false;
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000624 int copyWidth = std::min(targetHeight, srcWidth);
625 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000626
627 for (int x = 0; x < copyWidth; x++)
628 {
629 for (int y = 0; y < copyHeight; y++)
630 {
Geoff Langae1990c2014-05-12 16:57:14 -0400631 SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000632 }
633 }
634 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000635 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000636 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000637 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000638 {
Geoff Langae1990c2014-05-12 16:57:14 -0400639 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000640 }
641 }
642 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000643 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000644 {
645 for (int x = 0; x < targetWidth; x++)
646 {
Geoff Langae1990c2014-05-12 16:57:14 -0400647 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000648 }
649 }
Geoff Langae1990c2014-05-12 16:57:14 -0400650
651 return dirty;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000652}
653
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000654template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400655bool expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000656{
Geoff Langae1990c2014-05-12 16:57:14 -0400657 bool dirty = false;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000658 int copyWidth = std::min(targetWidth, srcWidth);
659 int copyHeight = std::min(targetHeight, srcHeight);
660
661 for (int y = 0; y < copyHeight; y++)
662 {
663 for (int x = 0; x < copyWidth; x++)
664 {
Geoff Langae1990c2014-05-12 16:57:14 -0400665 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000666 }
667 }
668 // clear unfilled right side
669 for (int y = 0; y < copyHeight; y++)
670 {
671 for (int x = copyWidth; x < targetWidth; x++)
672 {
Geoff Langae1990c2014-05-12 16:57:14 -0400673 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000674 }
675 }
676 // clear unfilled bottom.
677 for (int y = copyHeight; y < targetHeight; y++)
678 {
679 for (int x = 0; x < targetWidth; x++)
680 {
Geoff Langae1990c2014-05-12 16:57:14 -0400681 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000682 }
683 }
Geoff Langae1990c2014-05-12 16:57:14 -0400684
685 return dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000686}
687
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000688template <int cols, int rows>
Jamie Madill36398922014-05-20 14:51:53 -0400689void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000690{
Jamie Madill36398922014-05-20 14:51:53 -0400691 LinkedUniform *targetUniform = getUniformByLocation(location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000693 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000694
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000695 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000696 const unsigned int targetMatrixStride = (4 * rows);
697 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000698
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000699 for (int i = 0; i < count; i++)
700 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000701 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
702 if (transpose == GL_FALSE)
703 {
Geoff Langae1990c2014-05-12 16:57:14 -0400704 targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000705 }
706 else
707 {
Geoff Langae1990c2014-05-12 16:57:14 -0400708 targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000709 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000710 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000711 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000712 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000713}
714
Jamie Madill36398922014-05-20 14:51:53 -0400715void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000716{
Jamie Madill36398922014-05-20 14:51:53 -0400717 setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000718}
719
Jamie Madill36398922014-05-20 14:51:53 -0400720void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000721{
Jamie Madill36398922014-05-20 14:51:53 -0400722 setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000723}
724
Jamie Madill36398922014-05-20 14:51:53 -0400725void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000726{
Jamie Madill36398922014-05-20 14:51:53 -0400727 setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000728}
729
Jamie Madill36398922014-05-20 14:51:53 -0400730void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000731{
Jamie Madill36398922014-05-20 14:51:53 -0400732 setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000733}
734
Jamie Madill36398922014-05-20 14:51:53 -0400735void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000736{
Jamie Madill36398922014-05-20 14:51:53 -0400737 setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000738}
739
Jamie Madill36398922014-05-20 14:51:53 -0400740void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000741{
Jamie Madill36398922014-05-20 14:51:53 -0400742 setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000743}
744
Jamie Madill36398922014-05-20 14:51:53 -0400745void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000746{
Jamie Madill36398922014-05-20 14:51:53 -0400747 setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000748}
749
Jamie Madill36398922014-05-20 14:51:53 -0400750void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000751{
Jamie Madill36398922014-05-20 14:51:53 -0400752 setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000753}
754
Jamie Madill36398922014-05-20 14:51:53 -0400755void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000756{
Jamie Madill36398922014-05-20 14:51:53 -0400757 setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000758}
759
Jamie Madill36398922014-05-20 14:51:53 -0400760void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000761{
Geoff Langbe4fdb32014-09-16 14:11:40 -0400762 setUniform(location, count, v, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000763}
764
Jamie Madill36398922014-05-20 14:51:53 -0400765void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000766{
Jamie Madill36398922014-05-20 14:51:53 -0400767 setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000768}
769
Jamie Madill36398922014-05-20 14:51:53 -0400770void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000771{
Jamie Madill36398922014-05-20 14:51:53 -0400772 setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000773}
774
Jamie Madill36398922014-05-20 14:51:53 -0400775void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000776{
Jamie Madill36398922014-05-20 14:51:53 -0400777 setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000778}
779
Jamie Madill36398922014-05-20 14:51:53 -0400780void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000781{
Jamie Madill36398922014-05-20 14:51:53 -0400782 setUniform(location, count, v, GL_UNSIGNED_INT);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000783}
784
Jamie Madill36398922014-05-20 14:51:53 -0400785void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000786{
Jamie Madill36398922014-05-20 14:51:53 -0400787 setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000788}
789
Jamie Madill36398922014-05-20 14:51:53 -0400790void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000791{
Jamie Madill36398922014-05-20 14:51:53 -0400792 setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000793}
794
Jamie Madill36398922014-05-20 14:51:53 -0400795void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000796{
Jamie Madill36398922014-05-20 14:51:53 -0400797 setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000798}
799
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000800template <typename T>
Jamie Madill99a1e982014-08-25 15:47:54 -0400801void ProgramBinary::getUniformv(GLint location, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000802{
Jamie Madill834e8b72014-04-11 13:33:58 -0400803 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000804
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000805 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000806 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000807 const int rows = VariableRowCount(targetUniform->type);
808 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400809 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, rows, cols, 4, rows);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000810 }
Jamie Madillf2575982014-06-25 16:04:54 -0400811 else if (uniformType == VariableComponentType(targetUniform->type))
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000812 {
Jamie Madillf2575982014-06-25 16:04:54 -0400813 unsigned int size = VariableComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000814 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
815 size * sizeof(T));
816 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000817 else
818 {
Jamie Madillf2575982014-06-25 16:04:54 -0400819 unsigned int size = VariableComponentCount(targetUniform->type);
820 switch (VariableComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000821 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000822 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000823 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000824 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000825
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000826 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000827 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000828 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000829 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000830 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000831 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000832
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000833 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000834 {
835 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
836
837 for (unsigned int i = 0; i < size; i++)
838 {
839 params[i] = static_cast<T>(floatParams[i]);
840 }
841 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000842 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000843
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000844 case GL_INT:
845 {
846 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
847
848 for (unsigned int i = 0; i < size; i++)
849 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000850 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000851 }
852 }
853 break;
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400854
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000855 case GL_UNSIGNED_INT:
856 {
857 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000858
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000859 for (unsigned int i = 0; i < size; i++)
860 {
861 params[i] = static_cast<T>(uintParams[i]);
862 }
863 }
864 break;
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400865
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000866 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000867 }
868 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000869}
870
Jamie Madill99a1e982014-08-25 15:47:54 -0400871void ProgramBinary::getUniformfv(GLint location, GLfloat *params)
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000872{
Jamie Madill99a1e982014-08-25 15:47:54 -0400873 getUniformv(location, params, GL_FLOAT);
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000874}
875
Jamie Madill99a1e982014-08-25 15:47:54 -0400876void ProgramBinary::getUniformiv(GLint location, GLint *params)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000877{
Jamie Madill99a1e982014-08-25 15:47:54 -0400878 getUniformv(location, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000879}
880
Jamie Madill99a1e982014-08-25 15:47:54 -0400881void ProgramBinary::getUniformuiv(GLint location, GLuint *params)
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000882{
Jamie Madill99a1e982014-08-25 15:47:54 -0400883 getUniformv(location, params, GL_UNSIGNED_INT);
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000884}
885
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000886void ProgramBinary::dirtyAllUniforms()
887{
888 unsigned int numUniforms = mUniforms.size();
889 for (unsigned int index = 0; index < numUniforms; index++)
890 {
891 mUniforms[index]->dirty = true;
892 }
893}
894
Jamie Madilld4cfa572014-07-08 10:00:32 -0400895void ProgramBinary::updateSamplerMapping()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000896{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400897 if (!mDirtySamplerMapping)
898 {
899 return;
900 }
901
902 mDirtySamplerMapping = false;
903
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000904 // Retrieve sampler uniform values
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500905 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000906 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400907 LinkedUniform *targetUniform = mUniforms[uniformIndex];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000908
909 if (targetUniform->dirty)
910 {
Nicolas Capense6050882013-07-08 10:43:10 -0400911 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000912 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000913 int count = targetUniform->elementCount();
Jamie Madilld4cfa572014-07-08 10:00:32 -0400914 GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000915
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000916 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000917 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000918 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000919
920 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000921 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000922 unsigned int samplerIndex = firstIndex + i;
923
Geoff Lang76b10c92014-09-05 16:28:14 -0400924 if (samplerIndex < mSamplersPS.size())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000925 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000926 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000927 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000928 }
929 }
930 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000931
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000932 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000933 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000934 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000935
936 for (int i = 0; i < count; i++)
937 {
938 unsigned int samplerIndex = firstIndex + i;
939
Geoff Lang76b10c92014-09-05 16:28:14 -0400940 if (samplerIndex < mSamplersVS.size())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000941 {
942 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000943 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000944 }
945 }
946 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000947 }
948 }
949 }
Jamie Madilld4cfa572014-07-08 10:00:32 -0400950}
951
952// Applies all the uniforms set for this program object to the renderer
Geoff Langc77e8c32014-09-08 16:28:24 -0400953Error ProgramBinary::applyUniforms()
Jamie Madilld4cfa572014-07-08 10:00:32 -0400954{
955 updateSamplerMapping();
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000956
Brandon Jones18bd4102014-09-22 14:21:44 -0700957 Error error = mProgram->applyUniforms(mUniforms);
Geoff Langc77e8c32014-09-08 16:28:24 -0400958 if (error.isError())
959 {
960 return error;
961 }
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500962
963 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
964 {
965 mUniforms[uniformIndex]->dirty = false;
966 }
Geoff Langc77e8c32014-09-08 16:28:24 -0400967
968 return gl::Error(GL_NO_ERROR);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000969}
970
Geoff Langc77e8c32014-09-08 16:28:24 -0400971Error ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000972{
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000973 ASSERT(boundBuffers.size() == mUniformBlocks.size());
Brandon Jones18bd4102014-09-22 14:21:44 -0700974 return mProgram->applyUniformBuffers(mUniformBlocks, boundBuffers, caps);
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000975}
976
Brandon Jones71620962014-08-20 14:04:59 -0700977bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000978{
Jamie Madilld15250e2014-09-03 09:40:44 -0400979 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
980 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
Jamie Madill5f562732014-02-14 16:41:24 -0500981
982 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000983 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -0400984 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000985 bool matched = false;
986
Jamie Madill54ad4f82014-09-03 09:40:46 -0400987 // Built-in varyings obey special rules
988 if (input->isBuiltIn())
989 {
990 continue;
991 }
992
Jamie Madill5f562732014-02-14 16:41:24 -0500993 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000994 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -0400995 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000996 if (output->name == input->name)
997 {
Jamie Madill42bcf322014-08-25 16:20:46 -0400998 if (!linkValidateVaryings(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000999 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001000 return false;
1001 }
1002
Jamie Madill139b9092013-08-30 13:21:06 -04001003 output->registerIndex = input->registerIndex;
Austin Kinrossaf875522014-08-25 21:06:07 -07001004 output->columnIndex = input->columnIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001005
1006 matched = true;
1007 break;
1008 }
1009 }
1010
Jamie Madill54ad4f82014-09-03 09:40:46 -04001011 // We permit unmatched, unreferenced varyings
1012 if (!matched && input->staticUse)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001013 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001014 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001015 return false;
1016 }
1017 }
1018
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001019 return true;
1020}
1021
Geoff Lang900013c2014-07-07 11:32:19 -04001022bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001023{
Jamie Madill9c4b24a2014-06-12 13:41:17 -04001024#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
1025 return false;
1026#else
Brandon Jones22502d52014-08-29 16:58:36 -07001027 ASSERT(binaryFormat == mProgram->getBinaryFormat());
Geoff Lang900013c2014-07-07 11:32:19 -04001028
Geoff Lang04fb89a2014-06-09 15:05:36 -04001029 reset();
1030
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001031 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001032
Brandon Jones22502d52014-08-29 16:58:36 -07001033 GLenum format = stream.readInt<GLenum>();
1034 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001035 {
1036 infoLog.append("Invalid program binary format.");
1037 return false;
1038 }
1039
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001040 int majorVersion = stream.readInt<int>();
1041 int minorVersion = stream.readInt<int>();
Jamie Madill0aa84f62014-02-13 13:17:23 -05001042 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
Jamie Madill049108d2013-11-19 10:41:49 -05001043 {
1044 infoLog.append("Invalid program binary version.");
1045 return false;
1046 }
1047
Jamie Madill0aa84f62014-02-13 13:17:23 -05001048 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001049 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001050 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001051 {
1052 infoLog.append("Invalid program binary version.");
1053 return false;
1054 }
1055
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001056 int compileFlags = stream.readInt<int>();
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001057 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1058 {
1059 infoLog.append("Mismatched compilation flags.");
1060 return false;
1061 }
1062
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001063 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1064 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001065 stream.readInt(&mLinkedAttribute[i].type);
1066 stream.readString(&mLinkedAttribute[i].name);
1067 stream.readInt(&mShaderAttributes[i].type);
1068 stream.readString(&mShaderAttributes[i].name);
1069 stream.readInt(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001070 }
1071
Al Patrick3f2daa82013-08-07 12:58:57 -07001072 initAttributesByLayout();
1073
Geoff Lang76b10c92014-09-05 16:28:14 -04001074 const unsigned int psSamplerCount = stream.readInt<unsigned int>();
1075 for (unsigned int i = 0; i < psSamplerCount; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001076 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001077 Sampler sampler;
1078 stream.readBool(&sampler.active);
1079 stream.readInt(&sampler.logicalTextureUnit);
1080 stream.readInt(&sampler.textureType);
1081 mSamplersPS.push_back(sampler);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001082 }
Geoff Lang76b10c92014-09-05 16:28:14 -04001083 const unsigned int vsSamplerCount = stream.readInt<unsigned int>();
1084 for (unsigned int i = 0; i < vsSamplerCount; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001085 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001086 Sampler sampler;
1087 stream.readBool(&sampler.active);
1088 stream.readInt(&sampler.logicalTextureUnit);
1089 stream.readInt(&sampler.textureType);
1090 mSamplersVS.push_back(sampler);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001091 }
1092
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001093 stream.readInt(&mUsedVertexSamplerRange);
1094 stream.readInt(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001095
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001096 const unsigned int uniformCount = stream.readInt<unsigned int>();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001097 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001098 {
1099 infoLog.append("Invalid program binary.");
1100 return false;
1101 }
1102
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001103 mUniforms.resize(uniformCount);
1104 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001105 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001106 GLenum type = stream.readInt<GLenum>();
1107 GLenum precision = stream.readInt<GLenum>();
1108 std::string name = stream.readString();
1109 unsigned int arraySize = stream.readInt<unsigned int>();
1110 int blockIndex = stream.readInt<int>();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001111
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001112 int offset = stream.readInt<int>();
1113 int arrayStride = stream.readInt<int>();
1114 int matrixStride = stream.readInt<int>();
1115 bool isRowMajorMatrix = stream.readBool();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001116
Jamie Madillf2575982014-06-25 16:04:54 -04001117 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001118
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001119 LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
1120
1121 stream.readInt(&uniform->psRegisterIndex);
1122 stream.readInt(&uniform->vsRegisterIndex);
1123 stream.readInt(&uniform->registerCount);
1124 stream.readInt(&uniform->registerElement);
1125
1126 mUniforms[uniformIndex] = uniform;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001127 }
1128
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001129 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001130 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001131 {
1132 infoLog.append("Invalid program binary.");
1133 return false;
1134 }
1135
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001136 mUniformBlocks.resize(uniformBlockCount);
1137 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001138 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001139 std::string name = stream.readString();
1140 unsigned int elementIndex = stream.readInt<unsigned int>();
1141 unsigned int dataSize = stream.readInt<unsigned int>();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001142
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001143 UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001144
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001145 stream.readInt(&uniformBlock->psRegisterIndex);
1146 stream.readInt(&uniformBlock->vsRegisterIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001147
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001148 unsigned int numMembers = stream.readInt<unsigned int>();
1149 uniformBlock->memberUniformIndexes.resize(numMembers);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001150 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1151 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001152 stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001153 }
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001154
1155 mUniformBlocks[uniformBlockIndex] = uniformBlock;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001156 }
1157
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001158 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001159 if (stream.error())
1160 {
1161 infoLog.append("Invalid program binary.");
1162 return false;
1163 }
1164
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001165 mUniformIndex.resize(uniformIndexCount);
1166 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001167 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001168 stream.readString(&mUniformIndex[uniformIndexIndex].name);
1169 stream.readInt(&mUniformIndex[uniformIndexIndex].element);
1170 stream.readInt(&mUniformIndex[uniformIndexIndex].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001171 }
1172
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001173 stream.readInt(&mTransformFeedbackBufferMode);
1174 const unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
1175 mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
1176 for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001177 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001178 LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex];
Geoff Lang48dcae72014-02-05 16:28:24 -05001179
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001180 stream.readString(&varying.name);
1181 stream.readInt(&varying.type);
1182 stream.readInt(&varying.size);
1183 stream.readString(&varying.semanticName);
1184 stream.readInt(&varying.semanticIndex);
1185 stream.readInt(&varying.semanticIndexCount);
Geoff Lang48dcae72014-02-05 16:28:24 -05001186 }
1187
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001188 const unsigned int vertexShaderCount = stream.readInt<unsigned int>();
Jamie Madillc5a83002014-02-14 16:41:25 -05001189 for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
1190 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001191 VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
Jamie Madillc5a83002014-02-14 16:41:25 -05001192
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001193 for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++)
Jamie Madillc5a83002014-02-14 16:41:25 -05001194 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001195 VertexFormat *vertexInput = &inputLayout[inputIndex];
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001196 stream.readInt(&vertexInput->mType);
1197 stream.readInt(&vertexInput->mNormalized);
1198 stream.readInt(&vertexInput->mComponents);
1199 stream.readBool(&vertexInput->mPureInteger);
Jamie Madillc5a83002014-02-14 16:41:25 -05001200 }
1201
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001202 unsigned int vertexShaderSize = stream.readInt<unsigned int>();
Geoff Lang04fb89a2014-06-09 15:05:36 -04001203 const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
Brandon Jones18bd4102014-09-22 14:21:44 -07001204 rx::ShaderExecutable *shaderExecutable = mProgram->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
1205 vertexShaderSize, rx::SHADER_VERTEX,
1206 mTransformFeedbackLinkedVaryings,
1207 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001208 if (!shaderExecutable)
1209 {
1210 infoLog.append("Could not create vertex shader.");
1211 return false;
1212 }
1213
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001214 // generated converted input layout
1215 GLenum signature[MAX_VERTEX_ATTRIBS];
Brandon Jones44151a92014-09-10 11:32:25 -07001216 mProgram->getInputLayoutSignature(inputLayout, signature);
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001217
1218 // add new binary
Geoff Lang04fb89a2014-06-09 15:05:36 -04001219 mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
Jamie Madillc5a83002014-02-14 16:41:25 -05001220
1221 stream.skip(vertexShaderSize);
1222 }
1223
Geoff Lang04fb89a2014-06-09 15:05:36 -04001224 const size_t pixelShaderCount = stream.readInt<unsigned int>();
1225 for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
1226 {
1227 const size_t outputCount = stream.readInt<unsigned int>();
1228 std::vector<GLenum> outputs(outputCount);
1229 for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
1230 {
1231 stream.readInt(&outputs[outputIndex]);
1232 }
1233
1234 const size_t pixelShaderSize = stream.readInt<unsigned int>();
1235 const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
Brandon Jones18bd4102014-09-22 14:21:44 -07001236 rx::ShaderExecutable *shaderExecutable = mProgram->loadExecutable(pixelShaderFunction, pixelShaderSize,
Brandon Jonesc9610c52014-08-25 17:02:59 -07001237 rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings,
1238 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
1239
Geoff Lang04fb89a2014-06-09 15:05:36 -04001240 if (!shaderExecutable)
1241 {
1242 infoLog.append("Could not create pixel shader.");
1243 return false;
1244 }
1245
1246 // add new binary
1247 mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
1248
1249 stream.skip(pixelShaderSize);
1250 }
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001251
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001252 unsigned int geometryShaderSize = stream.readInt<unsigned int>();
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001253
Jamie Madillc5a83002014-02-14 16:41:25 -05001254 if (geometryShaderSize > 0)
1255 {
1256 const char *geometryShaderFunction = (const char*) binary + stream.offset();
Brandon Jones18bd4102014-09-22 14:21:44 -07001257 mGeometryExecutable = mProgram->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
Brandon Jonesc9610c52014-08-25 17:02:59 -07001258 geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
1259 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
1260
Jamie Madillc5a83002014-02-14 16:41:25 -05001261 if (!mGeometryExecutable)
1262 {
1263 infoLog.append("Could not create geometry shader.");
Jamie Madillc5a83002014-02-14 16:41:25 -05001264 return false;
1265 }
1266 stream.skip(geometryShaderSize);
1267 }
1268
Brandon Jones22502d52014-08-29 16:58:36 -07001269 if (!mProgram->load(infoLog, &stream))
1270 {
1271 return false;
1272 }
1273
Brandon Jonesc9610c52014-08-25 17:02:59 -07001274 mProgram->initializeUniformStorage(mUniforms);
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001275
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001276 return true;
Jamie Madill9c4b24a2014-06-12 13:41:17 -04001277#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001278}
1279
Geoff Lang900013c2014-07-07 11:32:19 -04001280bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001281{
Geoff Lang900013c2014-07-07 11:32:19 -04001282 if (binaryFormat)
1283 {
Brandon Jones22502d52014-08-29 16:58:36 -07001284 *binaryFormat = mProgram->getBinaryFormat();
Geoff Lang900013c2014-07-07 11:32:19 -04001285 }
1286
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001287 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001288
Brandon Jones22502d52014-08-29 16:58:36 -07001289 stream.writeInt(mProgram->getBinaryFormat());
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001290 stream.writeInt(ANGLE_MAJOR_VERSION);
1291 stream.writeInt(ANGLE_MINOR_VERSION);
Ehsan Akhgariaa7e1662014-07-05 21:13:11 -04001292 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001293 stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001294
1295 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1296 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001297 stream.writeInt(mLinkedAttribute[i].type);
1298 stream.writeString(mLinkedAttribute[i].name);
1299 stream.writeInt(mShaderAttributes[i].type);
1300 stream.writeString(mShaderAttributes[i].name);
1301 stream.writeInt(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001302 }
1303
Geoff Lang76b10c92014-09-05 16:28:14 -04001304 stream.writeInt(mSamplersPS.size());
1305 for (unsigned int i = 0; i < mSamplersPS.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001306 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001307 stream.writeInt(mSamplersPS[i].active);
1308 stream.writeInt(mSamplersPS[i].logicalTextureUnit);
1309 stream.writeInt(mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001310 }
1311
Geoff Lang76b10c92014-09-05 16:28:14 -04001312 stream.writeInt(mSamplersVS.size());
1313 for (unsigned int i = 0; i < mSamplersVS.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001314 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001315 stream.writeInt(mSamplersVS[i].active);
1316 stream.writeInt(mSamplersVS[i].logicalTextureUnit);
1317 stream.writeInt(mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001318 }
1319
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001320 stream.writeInt(mUsedVertexSamplerRange);
1321 stream.writeInt(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001322
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001323 stream.writeInt(mUniforms.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001324 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001325 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001326 const LinkedUniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001327
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001328 stream.writeInt(uniform.type);
1329 stream.writeInt(uniform.precision);
1330 stream.writeString(uniform.name);
1331 stream.writeInt(uniform.arraySize);
1332 stream.writeInt(uniform.blockIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001333
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001334 stream.writeInt(uniform.blockInfo.offset);
1335 stream.writeInt(uniform.blockInfo.arrayStride);
1336 stream.writeInt(uniform.blockInfo.matrixStride);
1337 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001338
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001339 stream.writeInt(uniform.psRegisterIndex);
1340 stream.writeInt(uniform.vsRegisterIndex);
1341 stream.writeInt(uniform.registerCount);
1342 stream.writeInt(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001343 }
1344
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001345 stream.writeInt(mUniformBlocks.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001346 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001347 {
1348 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1349
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001350 stream.writeString(uniformBlock.name);
1351 stream.writeInt(uniformBlock.elementIndex);
1352 stream.writeInt(uniformBlock.dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001353
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001354 stream.writeInt(uniformBlock.memberUniformIndexes.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001355 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1356 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001357 stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001358 }
1359
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001360 stream.writeInt(uniformBlock.psRegisterIndex);
1361 stream.writeInt(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001362 }
1363
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001364 stream.writeInt(mUniformIndex.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001365 for (size_t i = 0; i < mUniformIndex.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001366 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001367 stream.writeString(mUniformIndex[i].name);
1368 stream.writeInt(mUniformIndex[i].element);
1369 stream.writeInt(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001370 }
1371
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001372 stream.writeInt(mTransformFeedbackBufferMode);
1373 stream.writeInt(mTransformFeedbackLinkedVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001374 for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
1375 {
1376 const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
1377
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001378 stream.writeString(varying.name);
1379 stream.writeInt(varying.type);
1380 stream.writeInt(varying.size);
1381 stream.writeString(varying.semanticName);
1382 stream.writeInt(varying.semanticIndex);
1383 stream.writeInt(varying.semanticIndexCount);
Geoff Lang48dcae72014-02-05 16:28:24 -05001384 }
1385
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001386 stream.writeInt(mVertexExecutables.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001387 for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
1388 {
1389 VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
1390
1391 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1392 {
1393 const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001394 stream.writeInt(vertexInput.mType);
1395 stream.writeInt(vertexInput.mNormalized);
1396 stream.writeInt(vertexInput.mComponents);
1397 stream.writeInt(vertexInput.mPureInteger);
Jamie Madillc5a83002014-02-14 16:41:25 -05001398 }
1399
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001400 size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
1401 stream.writeInt(vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001402
Jamie Madillcafa2102014-07-23 16:43:22 -04001403 const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction();
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001404 stream.writeBytes(vertexBlob, vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001405 }
1406
Geoff Lang04fb89a2014-06-09 15:05:36 -04001407 stream.writeInt(mPixelExecutables.size());
1408 for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
1409 {
1410 PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
1411
1412 const std::vector<GLenum> outputs = pixelExecutable->outputSignature();
1413 stream.writeInt(outputs.size());
1414 for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++)
1415 {
1416 stream.writeInt(outputs[outputIndex]);
1417 }
1418
1419 size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength();
1420 stream.writeInt(pixelShaderSize);
1421
Jamie Madillcafa2102014-07-23 16:43:22 -04001422 const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction();
Geoff Lang04fb89a2014-06-09 15:05:36 -04001423 stream.writeBytes(pixelBlob, pixelShaderSize);
1424 }
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001425
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001426 size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1427 stream.writeInt(geometryShaderSize);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001428
Jamie Madillc5a83002014-02-14 16:41:25 -05001429 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1430 {
Jamie Madillcafa2102014-07-23 16:43:22 -04001431 const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001432 stream.writeBytes(geometryBlob, geometryShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001433 }
1434
Brandon Jones22502d52014-08-29 16:58:36 -07001435 if (!mProgram->save(&stream))
1436 {
1437 if (length)
1438 {
1439 *length = 0;
1440 }
1441
1442 return false;
1443 }
1444
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001445 GLsizei streamLength = stream.length();
1446 const void *streamData = stream.data();
1447
Brandon Jones18bd4102014-09-22 14:21:44 -07001448 if (streamLength > bufSize)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001449 {
1450 if (length)
1451 {
1452 *length = 0;
1453 }
1454
1455 return false;
1456 }
1457
1458 if (binary)
1459 {
1460 char *ptr = (char*) binary;
1461
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001462 memcpy(ptr, streamData, streamLength);
1463 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001464
Brandon Jones18bd4102014-09-22 14:21:44 -07001465 ASSERT(ptr - streamLength == binary);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001466 }
1467
1468 if (length)
1469 {
Brandon Jones18bd4102014-09-22 14:21:44 -07001470 *length = streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001471 }
1472
1473 return true;
1474}
1475
1476GLint ProgramBinary::getLength()
1477{
1478 GLint length;
Geoff Lang900013c2014-07-07 11:32:19 -04001479 if (save(NULL, NULL, INT_MAX, &length))
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001480 {
1481 return length;
1482 }
1483 else
1484 {
1485 return 0;
1486 }
1487}
1488
Brandon Jones71620962014-08-20 14:04:59 -07001489bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
Brandon Jones43a53e22014-08-28 16:23:22 -07001490 const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001491{
1492 if (!fragmentShader || !fragmentShader->isCompiled())
1493 {
1494 return false;
1495 }
Brandon Jones71620962014-08-20 14:04:59 -07001496 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001497
1498 if (!vertexShader || !vertexShader->isCompiled())
1499 {
1500 return false;
1501 }
Brandon Jones71620962014-08-20 14:04:59 -07001502 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001503
Geoff Lang04fb89a2014-06-09 15:05:36 -04001504 reset();
1505
Geoff Lang76b10c92014-09-05 16:28:14 -04001506 mSamplersPS.resize(caps.maxTextureImageUnits);
1507 mSamplersVS.resize(caps.maxVertexTextureImageUnits);
1508
Geoff Lang48dcae72014-02-05 16:28:24 -05001509 mTransformFeedbackBufferMode = transformFeedbackBufferMode;
1510
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001511 rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
1512 rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001513
Brandon Jones22502d52014-08-29 16:58:36 -07001514 int registers;
1515 std::vector<LinkedVarying> linkedVaryings;
1516 if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, &registers, &linkedVaryings, &mOutputVariables))
Jamie Madill5f562732014-02-14 16:41:24 -05001517 {
1518 return false;
1519 }
1520
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001521 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001522
Jamie Madilld15250e2014-09-03 09:40:44 -04001523 if (!linkAttributes(infoLog, attributeBindings, vertexShader))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001524 {
1525 success = false;
1526 }
1527
Brandon Jones43a53e22014-08-28 16:23:22 -07001528 if (!linkUniforms(infoLog, *vertexShader, *fragmentShader, caps))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001529 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001530 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001531 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001532
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001533 // special case for gl_DepthRange, the only built-in uniform (also a struct)
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001534 if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange())
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001535 {
Jamie Madille04a5b72014-07-18 10:33:12 -04001536 const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo();
1537
1538 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo));
1539 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo));
1540 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001541 }
1542
Brandon Jones43a53e22014-08-28 16:23:22 -07001543 if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001544 {
1545 success = false;
1546 }
1547
Geoff Lang48dcae72014-02-05 16:28:24 -05001548 if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
Brandon Jones43a53e22014-08-28 16:23:22 -07001549 transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings, caps))
Geoff Lang48dcae72014-02-05 16:28:24 -05001550 {
1551 success = false;
1552 }
1553
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001554 if (success)
1555 {
Jamie Madillc5a83002014-02-14 16:41:25 -05001556 VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
Jamie Madill3f2e61d2014-09-05 10:38:05 -04001557 GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout);
Jamie Madillc5a83002014-02-14 16:41:25 -05001558 rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
Geoff Lang04fb89a2014-06-09 15:05:36 -04001559
Brandon Jones22502d52014-08-29 16:58:36 -07001560 std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(mProgram->getPixelShaderKey());
Geoff Lang04fb89a2014-06-09 15:05:36 -04001561 rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001562
Brandon Jones44151a92014-09-10 11:32:25 -07001563 if (mProgram->usesGeometryShader())
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001564 {
Brandon Jones44151a92014-09-10 11:32:25 -07001565 mGeometryExecutable = mProgram->getGeometryExecutable(infoLog, fragmentShader, vertexShader,
1566 mTransformFeedbackLinkedVaryings,
1567 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
1568 registers);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001569 }
1570
Brandon Jones44151a92014-09-10 11:32:25 -07001571 if (!defaultVertexExecutable || !defaultPixelExecutable || (mProgram->usesGeometryShader() && !mGeometryExecutable))
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001572 {
1573 infoLog.append("Failed to create D3D shaders.");
1574 success = false;
Geoff Lang04fb89a2014-06-09 15:05:36 -04001575 reset();
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001576 }
1577 }
1578
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001579 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001580}
1581
1582// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madilld15250e2014-09-03 09:40:44 -04001583bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001584{
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001585 const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001586
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001587 unsigned int usedLocations = 0;
Jamie Madill54ad4f82014-09-03 09:40:46 -04001588 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001589
1590 // Link attributes that have a binding location
Jamie Madill54ad4f82014-09-03 09:40:46 -04001591 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001592 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001593 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1594
1595 ASSERT(attribute.staticUse);
1596
Jamie Madilleba4eff2013-06-20 11:55:51 -04001597 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001598
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001599 mShaderAttributes[attributeIndex] = attribute;
1600
Jamie Madilleba4eff2013-06-20 11:55:51 -04001601 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001602 {
Jamie Madillf2575982014-06-25 16:04:54 -04001603 const int rows = VariableRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001604
1605 if (rows + location > MAX_VERTEX_ATTRIBS)
1606 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001607 infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001608
1609 return false;
1610 }
1611
Jamie Madilleba4eff2013-06-20 11:55:51 -04001612 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001613 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001614 const int rowLocation = location + row;
Jamie Madillf2575982014-06-25 16:04:54 -04001615 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001616
1617 // In GLSL 3.00, attribute aliasing produces a link error
1618 // In GLSL 1.00, attribute aliasing is allowed
Brandon Jones44151a92014-09-10 11:32:25 -07001619 if (mProgram->getShaderVersion() >= 300)
Jamie Madilleba4eff2013-06-20 11:55:51 -04001620 {
1621 if (!linkedAttribute.name.empty())
1622 {
1623 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1624 return false;
1625 }
1626 }
1627
1628 linkedAttribute = attribute;
1629 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001630 }
1631 }
1632 }
1633
1634 // Link attributes that don't have a binding location
Jamie Madill54ad4f82014-09-03 09:40:46 -04001635 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001636 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001637 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1638
1639 ASSERT(attribute.staticUse);
1640
Jamie Madilleba4eff2013-06-20 11:55:51 -04001641 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001642
Jamie Madilleba4eff2013-06-20 11:55:51 -04001643 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001644 {
Jamie Madillf2575982014-06-25 16:04:54 -04001645 int rows = VariableRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001646 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1647
1648 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1649 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001650 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001651
1652 return false; // Fail to link
1653 }
1654
Jamie Madilldefb6742013-06-20 11:55:51 -04001655 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001656 }
1657 }
1658
1659 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1660 {
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001661 int index = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillf2575982014-06-25 16:04:54 -04001662 int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001663
1664 for (int r = 0; r < rows; r++)
1665 {
1666 mSemanticIndex[attributeIndex++] = index++;
1667 }
1668 }
1669
Al Patrick3f2daa82013-08-07 12:58:57 -07001670 initAttributesByLayout();
1671
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001672 return true;
1673}
1674
Jamie Madillf2575982014-06-25 16:04:54 -04001675bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1676 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001677{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001678 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001679 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001680 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001681 return false;
1682 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001683 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001684 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001685 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001686 return false;
1687 }
Jamie Madill28167c62013-08-30 13:21:10 -04001688 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001689 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001690 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04001691 return false;
1692 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001693
Jamie Madill42bcf322014-08-25 16:20:46 -04001694 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001695 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001696 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001697 return false;
1698 }
Jamie Madill42bcf322014-08-25 16:20:46 -04001699 const unsigned int numMembers = vertexVariable.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001700 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1701 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001702 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1703 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001704
1705 if (vertexMember.name != fragmentMember.name)
1706 {
Jamie Madill28167c62013-08-30 13:21:10 -04001707 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
Jamie Madill42bcf322014-08-25 16:20:46 -04001708 memberIndex, variableName.c_str(),
1709 vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001710 return false;
1711 }
1712
Jamie Madill42bcf322014-08-25 16:20:46 -04001713 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1714 vertexMember.name + "'";
1715
1716 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001717 {
1718 return false;
1719 }
1720 }
1721
1722 return true;
1723}
1724
Jamie Madill42bcf322014-08-25 16:20:46 -04001725bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001726{
Jamie Madill28167c62013-08-30 13:21:10 -04001727 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001728 {
1729 return false;
1730 }
1731
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001732 return true;
1733}
1734
Jamie Madill42bcf322014-08-25 16:20:46 -04001735bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
Jamie Madill28167c62013-08-30 13:21:10 -04001736{
1737 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1738 {
1739 return false;
1740 }
1741
1742 if (vertexVarying.interpolation != fragmentVarying.interpolation)
1743 {
1744 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1745 return false;
1746 }
1747
Jamie Madill28167c62013-08-30 13:21:10 -04001748 return true;
1749}
1750
Jamie Madill42bcf322014-08-25 16:20:46 -04001751bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001752{
Jamie Madill28167c62013-08-30 13:21:10 -04001753 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001754 {
1755 return false;
1756 }
1757
Jamie Madilla6f267f2014-08-27 11:44:15 -04001758 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001759 {
1760 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1761 return false;
1762 }
1763
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001764 return true;
1765}
1766
Brandon Jones43a53e22014-08-28 16:23:22 -07001767bool ProgramBinary::linkUniforms(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001768{
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001769 const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader.getImplementation());
1770 const rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader.getImplementation());
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001771
Jamie Madilld15250e2014-09-03 09:40:44 -04001772 const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms();
1773 const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms();
Jamie Madillbf9cce22014-07-18 10:33:09 -04001774
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001775 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madillf2575982014-06-25 16:04:54 -04001776 typedef std::map<std::string, const sh::Uniform*> UniformMap;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001777 UniformMap linkedUniforms;
1778
1779 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
1780 {
Jamie Madillf2575982014-06-25 16:04:54 -04001781 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001782 linkedUniforms[vertexUniform.name] = &vertexUniform;
1783 }
1784
1785 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
1786 {
Jamie Madillf2575982014-06-25 16:04:54 -04001787 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001788 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
1789 if (entry != linkedUniforms.end())
1790 {
Jamie Madillf2575982014-06-25 16:04:54 -04001791 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04001792 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill42bcf322014-08-25 16:20:46 -04001793 if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001794 {
1795 return false;
1796 }
1797 }
1798 }
1799
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001800 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001801 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001802 const sh::Uniform &uniform = vertexUniforms[uniformIndex];
Jamie Madill54ad4f82014-09-03 09:40:46 -04001803
1804 if (uniform.staticUse)
1805 {
1806 defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShaderD3D->getUniformRegister(uniform.name));
1807 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001808 }
1809
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001810 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001811 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001812 const sh::Uniform &uniform = fragmentUniforms[uniformIndex];
Jamie Madill54ad4f82014-09-03 09:40:46 -04001813
1814 if (uniform.staticUse)
1815 {
1816 defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShaderD3D->getUniformRegister(uniform.name));
1817 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001818 }
1819
Brandon Jones43a53e22014-08-28 16:23:22 -07001820 if (!indexUniforms(infoLog, caps))
Jamie Madill66d43d22014-07-11 17:02:03 -04001821 {
1822 return false;
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001823 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001824
Brandon Jonesc9610c52014-08-25 17:02:59 -07001825 mProgram->initializeUniformStorage(mUniforms);
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001826
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001827 return true;
1828}
1829
Jamie Madillbf9cce22014-07-18 10:33:09 -04001830void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001831{
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001832 ShShaderOutput outputType = rx::ShaderD3D::getCompilerOutputType(shader);
Jamie Madille04a5b72014-07-18 10:33:12 -04001833 sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
Jamie Madillbf9cce22014-07-18 10:33:09 -04001834 encoder.skipRegisters(uniformRegister);
1835
1836 defineUniform(shader, uniform, uniform.name, &encoder);
Jamie Madill5b130dc2014-07-11 17:02:05 -04001837}
1838
Jamie Madill42bcf322014-08-25 16:20:46 -04001839void ProgramBinary::defineUniform(GLenum shader, const sh::ShaderVariable &uniform,
Jamie Madillbf9cce22014-07-18 10:33:09 -04001840 const std::string &fullName, sh::HLSLBlockEncoder *encoder)
Jamie Madill5b130dc2014-07-11 17:02:05 -04001841{
1842 if (uniform.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001843 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001844 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001845 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001846 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001847
Jamie Madillbf9cce22014-07-18 10:33:09 -04001848 encoder->enterAggregateType();
Jamie Madillc600c8c2014-05-16 11:22:21 -04001849
Jamie Madill5b130dc2014-07-11 17:02:05 -04001850 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001851 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001852 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
Jamie Madillbf9cce22014-07-18 10:33:09 -04001853 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
1854
1855 defineUniform(shader, field, fieldFullName, encoder);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001856 }
Jamie Madillbf9cce22014-07-18 10:33:09 -04001857
1858 encoder->exitAggregateType();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001859 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001860 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001861 else // Not a struct
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001862 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001863 // Arrays are treated as aggregate types
1864 if (uniform.isArray())
1865 {
1866 encoder->enterAggregateType();
1867 }
1868
Jamie Madill5b130dc2014-07-11 17:02:05 -04001869 LinkedUniform *linkedUniform = getUniformByName(fullName);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001870
Jamie Madill66d43d22014-07-11 17:02:03 -04001871 if (!linkedUniform)
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001872 {
Jamie Madill5b130dc2014-07-11 17:02:05 -04001873 linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
Jamie Madill66d43d22014-07-11 17:02:03 -04001874 -1, sh::BlockMemberInfo::getDefaultBlockInfo());
1875 ASSERT(linkedUniform);
Jamie Madillbf9cce22014-07-18 10:33:09 -04001876 linkedUniform->registerElement = encoder->getCurrentElement();
Jamie Madill66d43d22014-07-11 17:02:03 -04001877 mUniforms.push_back(linkedUniform);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001878 }
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001879
Jamie Madillbf9cce22014-07-18 10:33:09 -04001880 ASSERT(linkedUniform->registerElement == encoder->getCurrentElement());
1881
Jamie Madill66d43d22014-07-11 17:02:03 -04001882 if (shader == GL_FRAGMENT_SHADER)
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001883 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001884 linkedUniform->psRegisterIndex = encoder->getCurrentRegister();
Jamie Madill66d43d22014-07-11 17:02:03 -04001885 }
1886 else if (shader == GL_VERTEX_SHADER)
1887 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001888 linkedUniform->vsRegisterIndex = encoder->getCurrentRegister();
Jamie Madill66d43d22014-07-11 17:02:03 -04001889 }
1890 else UNREACHABLE();
Jamie Madillbf9cce22014-07-18 10:33:09 -04001891
1892 // Advance the uniform offset, to track registers allocation for structs
1893 encoder->encodeType(uniform.type, uniform.arraySize, false);
1894
1895 // Arrays are treated as aggregate types
1896 if (uniform.isArray())
1897 {
1898 encoder->exitAggregateType();
1899 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001900 }
1901}
1902
Brandon Jones43a53e22014-08-28 16:23:22 -07001903bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog, const Caps &caps)
Jamie Madill66d43d22014-07-11 17:02:03 -04001904{
1905 ASSERT(IsSampler(uniform.type));
1906 ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
1907
1908 if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
1909 {
1910 if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
Geoff Lang76b10c92014-09-05 16:28:14 -04001911 &mUsedVertexSamplerRange))
Jamie Madill66d43d22014-07-11 17:02:03 -04001912 {
1913 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).",
Geoff Lang76b10c92014-09-05 16:28:14 -04001914 mSamplersVS.size());
Jamie Madill66d43d22014-07-11 17:02:03 -04001915 return false;
1916 }
1917
Brandon Jones18bd4102014-09-22 14:21:44 -07001918 unsigned int maxVertexVectors = mProgram->getReservedUniformVectors(GL_VERTEX_SHADER) + caps.maxVertexUniformVectors;
Jamie Madill66d43d22014-07-11 17:02:03 -04001919 if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
1920 {
1921 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)",
Geoff Lang301d1612014-07-09 10:34:37 -04001922 caps.maxVertexUniformVectors);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001923 return false;
1924 }
1925 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001926
1927 if (uniform.psRegisterIndex != GL_INVALID_INDEX)
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001928 {
Jamie Madill66d43d22014-07-11 17:02:03 -04001929 if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
Geoff Lang76b10c92014-09-05 16:28:14 -04001930 &mUsedPixelSamplerRange))
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001931 {
Jamie Madill66d43d22014-07-11 17:02:03 -04001932 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).",
Geoff Lang76b10c92014-09-05 16:28:14 -04001933 mSamplersPS.size());
Jamie Madill66d43d22014-07-11 17:02:03 -04001934 return false;
1935 }
1936
Brandon Jones18bd4102014-09-22 14:21:44 -07001937 unsigned int maxFragmentVectors = mProgram->getReservedUniformVectors(GL_FRAGMENT_SHADER) + caps.maxFragmentUniformVectors;
Jamie Madill66d43d22014-07-11 17:02:03 -04001938 if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
1939 {
1940 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)",
Geoff Lang301d1612014-07-09 10:34:37 -04001941 caps.maxFragmentUniformVectors);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001942 return false;
1943 }
1944 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001945
1946 return true;
1947}
1948
Brandon Jones43a53e22014-08-28 16:23:22 -07001949bool ProgramBinary::indexUniforms(InfoLog &infoLog, const Caps &caps)
Jamie Madill66d43d22014-07-11 17:02:03 -04001950{
1951 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
1952 {
1953 const LinkedUniform &uniform = *mUniforms[uniformIndex];
1954
1955 if (IsSampler(uniform.type))
1956 {
Brandon Jones43a53e22014-08-28 16:23:22 -07001957 if (!indexSamplerUniform(uniform, infoLog, caps))
Jamie Madill66d43d22014-07-11 17:02:03 -04001958 {
1959 return false;
1960 }
1961 }
1962
1963 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++)
1964 {
1965 mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex));
1966 }
1967 }
1968
1969 return true;
1970}
1971
1972bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex,
1973 GLenum samplerType,
1974 unsigned int samplerCount,
Geoff Lang76b10c92014-09-05 16:28:14 -04001975 std::vector<Sampler> &outSamplers,
1976 GLuint *outUsedRange)
Jamie Madill66d43d22014-07-11 17:02:03 -04001977{
1978 unsigned int samplerIndex = startSamplerIndex;
1979
1980 do
1981 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001982 if (samplerIndex < outSamplers.size())
Jamie Madill66d43d22014-07-11 17:02:03 -04001983 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001984 Sampler& sampler = outSamplers[samplerIndex];
1985 sampler.active = true;
1986 sampler.textureType = GetTextureType(samplerType);
1987 sampler.logicalTextureUnit = 0;
1988 *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
Jamie Madill66d43d22014-07-11 17:02:03 -04001989 }
1990 else
1991 {
1992 return false;
1993 }
1994
1995 samplerIndex++;
1996 } while (samplerIndex < startSamplerIndex + samplerCount);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001997
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001998 return true;
1999}
2000
Jamie Madillf2575982014-06-25 16:04:54 -04002001bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002002{
2003 const char* blockName = vertexInterfaceBlock.name.c_str();
2004
2005 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002006 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002007 {
2008 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2009 return false;
2010 }
2011
2012 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2013 {
2014 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2015 return false;
2016 }
2017
Jamie Madill9060a4e2013-08-12 16:22:57 -07002018 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2019 {
2020 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2021 return false;
2022 }
2023
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002024 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002025 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2026 {
Jamie Madillf2575982014-06-25 16:04:54 -04002027 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2028 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002029
2030 if (vertexMember.name != fragmentMember.name)
2031 {
Jamie Madill28167c62013-08-30 13:21:10 -04002032 infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002033 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2034 return false;
2035 }
2036
Jamie Madill42bcf322014-08-25 16:20:46 -04002037 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2038 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002039 {
2040 return false;
2041 }
2042 }
2043
2044 return true;
2045}
2046
Brandon Jones43a53e22014-08-28 16:23:22 -07002047bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002048{
Jamie Madilld15250e2014-09-03 09:40:44 -04002049 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2050 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madilld4116ff2014-07-11 17:02:01 -04002051
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002052 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jamie Madillf2575982014-06-25 16:04:54 -04002053 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002054 UniformBlockMap linkedUniformBlocks;
2055
2056 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2057 {
Jamie Madillf2575982014-06-25 16:04:54 -04002058 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002059 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2060 }
2061
2062 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2063 {
Jamie Madillf2575982014-06-25 16:04:54 -04002064 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002065 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2066 if (entry != linkedUniformBlocks.end())
2067 {
Jamie Madillf2575982014-06-25 16:04:54 -04002068 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002069 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2070 {
2071 return false;
2072 }
2073 }
2074 }
2075
2076 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2077 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002078 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
2079
Jamie Madill04668672014-09-03 09:40:49 -04002080 // Note: shared and std140 layouts are always considered active
2081 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002082 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002083 if (!defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
2084 {
2085 return false;
2086 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002087 }
2088 }
2089
2090 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2091 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002092 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
2093
Jamie Madill04668672014-09-03 09:40:49 -04002094 // Note: shared and std140 layouts are always considered active
2095 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002096 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002097 if (!defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
2098 {
2099 return false;
2100 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002101 }
2102 }
2103
2104 return true;
2105}
2106
Geoff Lang48dcae72014-02-05 16:28:24 -05002107bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
2108 const std::vector<std::string> &transformFeedbackVaryingNames,
2109 GLenum transformFeedbackBufferMode,
Brandon Jones43a53e22014-08-28 16:23:22 -07002110 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
2111 const Caps &caps) const
Geoff Lang48dcae72014-02-05 16:28:24 -05002112{
2113 size_t totalComponents = 0;
Geoff Lang05881a02014-07-10 14:05:30 -04002114
Geoff Lang48dcae72014-02-05 16:28:24 -05002115 // Gather the linked varyings that are used for transform feedback, they should all exist.
2116 outTransformFeedbackLinkedVaryings->clear();
2117 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
2118 {
2119 bool found = false;
2120 for (size_t j = 0; j < linkedVaryings.size(); j++)
2121 {
2122 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
2123 {
2124 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
2125 {
2126 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
2127 {
2128 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
2129 return false;
2130 }
2131 }
2132
2133 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
2134 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang05881a02014-07-10 14:05:30 -04002135 componentCount > caps.maxTransformFeedbackSeparateComponents)
Geoff Lang48dcae72014-02-05 16:28:24 -05002136 {
2137 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
Geoff Lang05881a02014-07-10 14:05:30 -04002138 linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
Geoff Lang48dcae72014-02-05 16:28:24 -05002139 return false;
2140 }
2141
2142 totalComponents += componentCount;
2143
2144 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
2145 found = true;
2146 break;
2147 }
2148 }
2149
2150 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2151 ASSERT(found);
2152 }
2153
Geoff Lang05881a02014-07-10 14:05:30 -04002154 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang48dcae72014-02-05 16:28:24 -05002155 {
2156 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
Geoff Lang05881a02014-07-10 14:05:30 -04002157 totalComponents, caps.maxTransformFeedbackInterleavedComponents);
Geoff Lang48dcae72014-02-05 16:28:24 -05002158 return false;
2159 }
2160
2161 return true;
2162}
2163
Jamie Madill42bcf322014-08-25 16:20:46 -04002164template <typename VarT>
2165void ProgramBinary::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
Jamie Madilla6f267f2014-08-27 11:44:15 -04002166 sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
2167 bool inRowMajorLayout)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002168{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002169 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002170 {
Jamie Madill42bcf322014-08-25 16:20:46 -04002171 const VarT &field = fields[uniformIndex];
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002172 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002173
Jamie Madille04a5b72014-07-18 10:33:12 -04002174 if (field.isStruct())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002175 {
Jamie Madilla6f267f2014-08-27 11:44:15 -04002176 bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
2177
Jamie Madille04a5b72014-07-18 10:33:12 -04002178 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002179 {
Jamie Madille04a5b72014-07-18 10:33:12 -04002180 encoder->enterAggregateType();
2181
2182 const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
Jamie Madilla6f267f2014-08-27 11:44:15 -04002183 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout);
Jamie Madille04a5b72014-07-18 10:33:12 -04002184
2185 encoder->exitAggregateType();
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002186 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002187 }
2188 else
2189 {
Jamie Madilla6f267f2014-08-27 11:44:15 -04002190 bool isRowMajorMatrix = (IsMatrixType(field.type) && inRowMajorLayout);
2191
2192 sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
Jamie Madille04a5b72014-07-18 10:33:12 -04002193
Jamie Madill834e8b72014-04-11 13:33:58 -04002194 LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
Jamie Madille04a5b72014-07-18 10:33:12 -04002195 blockIndex, memberInfo);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002196
2197 // add to uniform list, but not index, since uniform block uniforms have no location
2198 blockUniformIndexes->push_back(mUniforms.size());
2199 mUniforms.push_back(newUniform);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002200 }
2201 }
2202}
2203
Brandon Jones43a53e22014-08-28 16:23:22 -07002204bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002205{
Brandon Jonesf05cdee2014-08-27 15:24:07 -07002206 const rx::ShaderD3D* shaderD3D = rx::ShaderD3D::makeShaderD3D(shader.getImplementation());
2207
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002208 // create uniform block entries if they do not exist
2209 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2210 {
2211 std::vector<unsigned int> blockUniformIndexes;
2212 const unsigned int blockIndex = mUniformBlocks.size();
2213
2214 // define member uniforms
Jamie Madille04a5b72014-07-18 10:33:12 -04002215 sh::BlockLayoutEncoder *encoder = NULL;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002216
Jamie Madille04a5b72014-07-18 10:33:12 -04002217 if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
2218 {
2219 encoder = new sh::Std140BlockEncoder;
2220 }
2221 else
2222 {
2223 encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
2224 }
2225 ASSERT(encoder);
2226
Jamie Madilla6f267f2014-08-27 11:44:15 -04002227 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout);
Jamie Madille04a5b72014-07-18 10:33:12 -04002228
2229 size_t dataSize = encoder->getBlockSize();
Jamie Madillfc43d272014-07-11 17:02:02 -04002230
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002231 // create all the uniform blocks
2232 if (interfaceBlock.arraySize > 0)
2233 {
2234 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2235 {
Jamie Madillfc43d272014-07-11 17:02:02 -04002236 UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002237 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2238 mUniformBlocks.push_back(newUniformBlock);
2239 }
2240 }
2241 else
2242 {
Jamie Madillfc43d272014-07-11 17:02:02 -04002243 UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002244 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2245 mUniformBlocks.push_back(newUniformBlock);
2246 }
2247 }
2248
Jamie Madill04668672014-09-03 09:40:49 -04002249 if (interfaceBlock.staticUse)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002250 {
Jamie Madill04668672014-09-03 09:40:49 -04002251 // Assign registers to the uniform blocks
2252 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2253 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2254 ASSERT(blockIndex != GL_INVALID_INDEX);
2255 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002256
Jamie Madill04668672014-09-03 09:40:49 -04002257 unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name);
2258
2259 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002260 {
Jamie Madill04668672014-09-03 09:40:49 -04002261 UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2262 ASSERT(uniformBlock->name == interfaceBlock.name);
2263
Brandon Jones18bd4102014-09-22 14:21:44 -07002264 if (!mProgram->assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(),
2265 interfaceBlockRegister + uniformBlockElement, caps))
Jamie Madill04668672014-09-03 09:40:49 -04002266 {
2267 return false;
2268 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002269 }
2270 }
2271
2272 return true;
2273}
2274
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002275bool ProgramBinary::isValidated() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002276{
2277 return mValidated;
2278}
2279
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002280void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002281{
2282 // Skip over inactive attributes
2283 unsigned int activeAttribute = 0;
2284 unsigned int attribute;
2285 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2286 {
2287 if (mLinkedAttribute[attribute].name.empty())
2288 {
2289 continue;
2290 }
2291
2292 if (activeAttribute == index)
2293 {
2294 break;
2295 }
2296
2297 activeAttribute++;
2298 }
2299
2300 if (bufsize > 0)
2301 {
2302 const char *string = mLinkedAttribute[attribute].name.c_str();
2303
2304 strncpy(name, string, bufsize);
2305 name[bufsize - 1] = '\0';
2306
2307 if (length)
2308 {
2309 *length = strlen(name);
2310 }
2311 }
2312
2313 *size = 1; // Always a single 'type' instance
2314
2315 *type = mLinkedAttribute[attribute].type;
2316}
2317
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002318GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002319{
2320 int count = 0;
2321
2322 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2323 {
2324 if (!mLinkedAttribute[attributeIndex].name.empty())
2325 {
2326 count++;
2327 }
2328 }
2329
2330 return count;
2331}
2332
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002333GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002334{
2335 int maxLength = 0;
2336
2337 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2338 {
2339 if (!mLinkedAttribute[attributeIndex].name.empty())
2340 {
2341 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2342 }
2343 }
2344
2345 return maxLength;
2346}
2347
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002348void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002349{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002350 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002351
2352 if (bufsize > 0)
2353 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002354 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002355
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002356 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002357 {
2358 string += "[0]";
2359 }
2360
2361 strncpy(name, string.c_str(), bufsize);
2362 name[bufsize - 1] = '\0';
2363
2364 if (length)
2365 {
2366 *length = strlen(name);
2367 }
2368 }
2369
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002370 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002371
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002372 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002373}
2374
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002375GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002376{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002377 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002378}
2379
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002380GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002381{
2382 int maxLength = 0;
2383
2384 unsigned int numUniforms = mUniforms.size();
2385 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2386 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002387 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002388 {
2389 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2390 if (mUniforms[uniformIndex]->isArray())
2391 {
2392 length += 3; // Counting in "[0]".
2393 }
2394 maxLength = std::max(length, maxLength);
2395 }
2396 }
2397
2398 return maxLength;
2399}
2400
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002401GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2402{
Jamie Madill834e8b72014-04-11 13:33:58 -04002403 const gl::LinkedUniform& uniform = *mUniforms[index];
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002404
2405 switch (pname)
2406 {
2407 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2408 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002409 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002410 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002411
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002412 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2413 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2414 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2415 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002416
2417 default:
2418 UNREACHABLE();
2419 break;
2420 }
2421 return 0;
2422}
2423
Jamie Madill36398922014-05-20 14:51:53 -04002424bool ProgramBinary::isValidUniformLocation(GLint location) const
2425{
2426 ASSERT(rx::IsIntegerCastSafe<GLint>(mUniformIndex.size()));
2427 return (location >= 0 && location < static_cast<GLint>(mUniformIndex.size()));
2428}
2429
2430LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const
2431{
2432 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformIndex.size());
2433 return mUniforms[mUniformIndex[location].index];
2434}
2435
Jamie Madill66d43d22014-07-11 17:02:03 -04002436LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const
2437{
2438 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2439 {
2440 if (mUniforms[uniformIndex]->name == name)
2441 {
2442 return mUniforms[uniformIndex];
2443 }
2444 }
2445
2446 return NULL;
2447}
2448
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002449void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2450{
2451 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2452
2453 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2454
2455 if (bufSize > 0)
2456 {
2457 std::string string = uniformBlock.name;
2458
2459 if (uniformBlock.isArrayElement())
2460 {
Jamie Madill5f562732014-02-14 16:41:24 -05002461 string += ArrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002462 }
2463
2464 strncpy(uniformBlockName, string.c_str(), bufSize);
2465 uniformBlockName[bufSize - 1] = '\0';
2466
2467 if (length)
2468 {
2469 *length = strlen(uniformBlockName);
2470 }
2471 }
2472}
2473
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002474void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2475{
2476 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2477
2478 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2479
2480 switch (pname)
2481 {
2482 case GL_UNIFORM_BLOCK_DATA_SIZE:
2483 *params = static_cast<GLint>(uniformBlock.dataSize);
2484 break;
2485 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002486 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002487 break;
2488 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2489 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2490 break;
2491 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2492 {
2493 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2494 {
2495 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2496 }
2497 }
2498 break;
2499 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2500 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2501 break;
2502 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2503 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2504 break;
2505 default: UNREACHABLE();
2506 }
2507}
2508
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002509GLuint ProgramBinary::getActiveUniformBlockCount() const
2510{
2511 return mUniformBlocks.size();
2512}
2513
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002514GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2515{
2516 unsigned int maxLength = 0;
2517
2518 unsigned int numUniformBlocks = mUniformBlocks.size();
2519 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2520 {
2521 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2522 if (!uniformBlock.name.empty())
2523 {
2524 const unsigned int length = uniformBlock.name.length() + 1;
2525
2526 // Counting in "[0]".
2527 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2528
2529 maxLength = std::max(length + arrayLength, maxLength);
2530 }
2531 }
2532
2533 return maxLength;
2534}
2535
Brandon Jones43a53e22014-08-28 16:23:22 -07002536void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002537{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002538 applyUniforms();
Brandon Jones43a53e22014-08-28 16:23:22 -07002539 if (!validateSamplers(&infoLog, caps))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002540 {
2541 mValidated = false;
2542 }
2543 else
2544 {
2545 mValidated = true;
2546 }
2547}
2548
Brandon Jones43a53e22014-08-28 16:23:22 -07002549bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002550{
2551 // if any two active samplers in a program are of different types, but refer to the same
2552 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2553 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madilld4cfa572014-07-08 10:00:32 -04002554 updateSamplerMapping();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002555
Geoff Lang76b10c92014-09-05 16:28:14 -04002556 std::vector<GLenum> textureUnitTypes(caps.maxCombinedTextureImageUnits, GL_NONE);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002557
2558 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2559 {
2560 if (mSamplersPS[i].active)
2561 {
2562 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002563
Geoff Lang76b10c92014-09-05 16:28:14 -04002564 if (unit >= textureUnitTypes.size())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002565 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002566 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002567 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002568 infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002569 }
2570
2571 return false;
2572 }
2573
Geoff Lang76b10c92014-09-05 16:28:14 -04002574 if (textureUnitTypes[unit] != GL_NONE)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002575 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002576 if (mSamplersPS[i].textureType != textureUnitTypes[unit])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002577 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002578 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002579 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002580 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002581 }
2582
2583 return false;
2584 }
2585 }
2586 else
2587 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002588 textureUnitTypes[unit] = mSamplersPS[i].textureType;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002589 }
2590 }
2591 }
2592
2593 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2594 {
2595 if (mSamplersVS[i].active)
2596 {
2597 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002598
Geoff Lang76b10c92014-09-05 16:28:14 -04002599 if (unit >= textureUnitTypes.size())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002600 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002601 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002602 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002603 infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002604 }
2605
2606 return false;
2607 }
2608
Geoff Lang76b10c92014-09-05 16:28:14 -04002609 if (textureUnitTypes[unit] != GL_NONE)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002610 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002611 if (mSamplersVS[i].textureType != textureUnitTypes[unit])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002612 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002613 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002614 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002615 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002616 }
2617
2618 return false;
2619 }
2620 }
2621 else
2622 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002623 textureUnitTypes[unit] = mSamplersVS[i].textureType;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002624 }
2625 }
2626 }
2627
2628 return true;
2629}
2630
Geoff Lang76b10c92014-09-05 16:28:14 -04002631ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002632{
2633}
2634
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002635struct AttributeSorter
2636{
2637 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2638 : originalIndices(semanticIndices)
2639 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002640 }
2641
2642 bool operator()(int a, int b)
2643 {
Jamie Madill03181ab2013-12-18 12:56:06 -05002644 if (originalIndices[a] == -1) return false;
2645 if (originalIndices[b] == -1) return true;
2646 return (originalIndices[a] < originalIndices[b]);
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002647 }
2648
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002649 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2650};
2651
Al Patrick3f2daa82013-08-07 12:58:57 -07002652void ProgramBinary::initAttributesByLayout()
2653{
2654 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2655 {
2656 mAttributesByLayout[i] = i;
2657 }
2658
2659 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
2660}
2661
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002662void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2663{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002664 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2665
2666 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2667 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002668 oldTranslatedAttributes[i] = attributes[i];
2669 }
2670
2671 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2672 {
Al Patrick3f2daa82013-08-07 12:58:57 -07002673 int oldIndex = mAttributesByLayout[i];
2674 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002675 attributes[i] = oldTranslatedAttributes[oldIndex];
2676 }
2677}
2678
Geoff Lang04fb89a2014-06-09 15:05:36 -04002679void ProgramBinary::reset()
2680{
Geoff Lang04fb89a2014-06-09 15:05:36 -04002681 SafeDeleteContainer(mVertexExecutables);
Geoff Lang04fb89a2014-06-09 15:05:36 -04002682 SafeDeleteContainer(mPixelExecutables);
Geoff Lang04fb89a2014-06-09 15:05:36 -04002683 SafeDelete(mGeometryExecutable);
2684
2685 mTransformFeedbackBufferMode = GL_NONE;
2686 mTransformFeedbackLinkedVaryings.clear();
2687
Geoff Lang76b10c92014-09-05 16:28:14 -04002688 mSamplersPS.clear();
2689 mSamplersVS.clear();
2690
Geoff Lang04fb89a2014-06-09 15:05:36 -04002691 mUsedVertexSamplerRange = 0;
2692 mUsedPixelSamplerRange = 0;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002693 mDirtySamplerMapping = true;
Geoff Lang04fb89a2014-06-09 15:05:36 -04002694
2695 SafeDeleteContainer(mUniforms);
2696 SafeDeleteContainer(mUniformBlocks);
2697 mUniformIndex.clear();
2698 mOutputVariables.clear();
Brandon Jonesc9610c52014-08-25 17:02:59 -07002699
2700 mProgram->reset();
Geoff Lang04fb89a2014-06-09 15:05:36 -04002701
2702 mValidated = false;
2703}
2704
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002705}