blob: 1a8162053e6a06321cfb02350b9f1fb9ec2e615c [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 Madilla6f267f2014-08-27 11:44:15 -040083bool IsRowMajorLayout(const sh::InterfaceBlockField &var)
84{
85 return var.isRowMajorLayout;
86}
87
88bool IsRowMajorLayout(const sh::ShaderVariable &var)
89{
90 return false;
91}
92
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000093}
94
Jamie Madill1b2a8f92014-05-14 13:09:39 -040095VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +000096 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000097{
98}
99
Geoff Lang48dcae72014-02-05 16:28:24 -0500100LinkedVarying::LinkedVarying()
101{
102}
103
104LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
105 unsigned int semanticIndex, unsigned int semanticIndexCount)
106 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
107{
108}
109
Geoff Langb543aff2014-09-30 14:52:54 -0400110LinkResult::LinkResult(bool linkSuccess, const Error &error)
111 : linkSuccess(linkSuccess),
112 error(error)
113{
114}
115
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000116unsigned int ProgramBinary::mCurrentSerial = 1;
117
Brandon Jonesc9610c52014-08-25 17:02:59 -0700118ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500119 : RefCountObject(0),
Brandon Jonesc9610c52014-08-25 17:02:59 -0700120 mProgram(impl),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500121 mUsedVertexSamplerRange(0),
122 mUsedPixelSamplerRange(0),
Jamie Madilld4cfa572014-07-08 10:00:32 -0400123 mDirtySamplerMapping(true),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500124 mValidated(false),
125 mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000126{
Brandon Jonesc9610c52014-08-25 17:02:59 -0700127 ASSERT(impl);
128
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000129 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
130 {
131 mSemanticIndex[index] = -1;
132 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000133}
134
135ProgramBinary::~ProgramBinary()
136{
Geoff Lang04fb89a2014-06-09 15:05:36 -0400137 reset();
Brandon Jonesc9610c52014-08-25 17:02:59 -0700138 SafeDelete(mProgram);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000139}
140
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000141unsigned int ProgramBinary::getSerial() const
142{
143 return mSerial;
144}
145
146unsigned int ProgramBinary::issueSerial()
147{
148 return mCurrentSerial++;
149}
150
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000151GLuint ProgramBinary::getAttributeLocation(const char *name)
152{
153 if (name)
154 {
155 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
156 {
157 if (mLinkedAttribute[index].name == std::string(name))
158 {
159 return index;
160 }
161 }
162 }
163
164 return -1;
165}
166
167int ProgramBinary::getSemanticIndex(int attributeIndex)
168{
169 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400170
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000171 return mSemanticIndex[attributeIndex];
172}
173
174// Returns one more than the highest sampler index used.
175GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
176{
177 switch (type)
178 {
179 case SAMPLER_PIXEL:
180 return mUsedPixelSamplerRange;
181 case SAMPLER_VERTEX:
182 return mUsedVertexSamplerRange;
183 default:
184 UNREACHABLE();
185 return 0;
186 }
187}
188
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000189bool ProgramBinary::usesPointSize() const
190{
Brandon Jones44151a92014-09-10 11:32:25 -0700191 return mProgram->usesPointSize();
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000192}
193
Brandon Jones43a53e22014-08-28 16:23:22 -0700194GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000195{
196 GLint logicalTextureUnit = -1;
197
198 switch (type)
199 {
200 case SAMPLER_PIXEL:
Geoff Lang76b10c92014-09-05 16:28:14 -0400201 ASSERT(samplerIndex < caps.maxTextureImageUnits);
202 if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000203 {
204 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
205 }
206 break;
207 case SAMPLER_VERTEX:
Geoff Lang76b10c92014-09-05 16:28:14 -0400208 ASSERT(samplerIndex < caps.maxVertexTextureImageUnits);
209 if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000210 {
211 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
212 }
213 break;
214 default: UNREACHABLE();
215 }
216
Brandon Jones43a53e22014-08-28 16:23:22 -0700217 if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000218 {
219 return logicalTextureUnit;
220 }
221
222 return -1;
223}
224
225// Returns the texture type for a given Direct3D 9 sampler type and
226// index (0-15 for the pixel shader and 0-3 for the vertex shader).
Geoff Lang76b10c92014-09-05 16:28:14 -0400227GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000228{
229 switch (type)
230 {
231 case SAMPLER_PIXEL:
Geoff Lang76b10c92014-09-05 16:28:14 -0400232 ASSERT(samplerIndex < mSamplersPS.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000233 ASSERT(mSamplersPS[samplerIndex].active);
234 return mSamplersPS[samplerIndex].textureType;
235 case SAMPLER_VERTEX:
Geoff Lang76b10c92014-09-05 16:28:14 -0400236 ASSERT(samplerIndex < mSamplersVS.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000237 ASSERT(mSamplersVS[samplerIndex].active);
238 return mSamplersVS[samplerIndex].textureType;
239 default: UNREACHABLE();
240 }
241
Geoff Lang76b10c92014-09-05 16:28:14 -0400242 return GL_TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000243}
244
245GLint ProgramBinary::getUniformLocation(std::string name)
246{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500247 unsigned int subscript = ParseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000248
249 unsigned int numUniforms = mUniformIndex.size();
250 for (unsigned int location = 0; location < numUniforms; location++)
251 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000252 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000253 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000254 const int index = mUniformIndex[location].index;
255 const bool isArray = mUniforms[index]->isArray();
256
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400257 if ((isArray && mUniformIndex[location].element == subscript) ||
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000258 (subscript == GL_INVALID_INDEX))
259 {
260 return location;
261 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000262 }
263 }
264
265 return -1;
266}
267
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000268GLuint ProgramBinary::getUniformIndex(std::string name)
269{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500270 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000271
272 // The app is not allowed to specify array indices other than 0 for arrays of basic types
273 if (subscript != 0 && subscript != GL_INVALID_INDEX)
274 {
275 return GL_INVALID_INDEX;
276 }
277
278 unsigned int numUniforms = mUniforms.size();
279 for (unsigned int index = 0; index < numUniforms; index++)
280 {
281 if (mUniforms[index]->name == name)
282 {
283 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
284 {
285 return index;
286 }
287 }
288 }
289
290 return GL_INVALID_INDEX;
291}
292
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000293GLuint ProgramBinary::getUniformBlockIndex(std::string name)
294{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500295 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000296
297 unsigned int numUniformBlocks = mUniformBlocks.size();
298 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
299 {
300 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
301 if (uniformBlock.name == name)
302 {
303 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
304 if (subscript == uniformBlock.elementIndex || arrayElementZero)
305 {
306 return blockIndex;
307 }
308 }
309 }
310
311 return GL_INVALID_INDEX;
312}
313
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000314UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
315{
316 ASSERT(blockIndex < mUniformBlocks.size());
317 return mUniformBlocks[blockIndex];
318}
319
Jamie Madilld1e78c92013-06-20 11:55:50 -0400320GLint ProgramBinary::getFragDataLocation(const char *name) const
321{
322 std::string baseName(name);
323 unsigned int arrayIndex;
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500324 arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madilld1e78c92013-06-20 11:55:50 -0400325
326 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
327 {
328 const VariableLocation &outputVariable = locationIt->second;
329
330 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
331 {
332 return static_cast<GLint>(locationIt->first);
333 }
334 }
335
336 return -1;
337}
338
Geoff Lang48dcae72014-02-05 16:28:24 -0500339size_t ProgramBinary::getTransformFeedbackVaryingCount() const
340{
Brandon Joneseb994362014-09-24 10:27:28 -0700341 return mProgram->getTransformFeedbackLinkedVaryings().size();
Geoff Lang48dcae72014-02-05 16:28:24 -0500342}
343
344const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
345{
Brandon Joneseb994362014-09-24 10:27:28 -0700346 return mProgram->getTransformFeedbackLinkedVaryings()[idx];
Geoff Lang48dcae72014-02-05 16:28:24 -0500347}
348
349GLenum ProgramBinary::getTransformFeedbackBufferMode() const
350{
Brandon Joneseb994362014-09-24 10:27:28 -0700351 return mProgram->getTransformFeedbackBufferMode();
Geoff Lang48dcae72014-02-05 16:28:24 -0500352}
353
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000354template <typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400355static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
356{
357 ASSERT(dest != NULL);
358 ASSERT(dirtyFlag != NULL);
359
360 *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
361 *dest = source;
362}
363
364template <typename T>
Jamie Madill36398922014-05-20 14:51:53 -0400365void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000366{
Jamie Madillf2575982014-06-25 16:04:54 -0400367 const int components = VariableComponentCount(targetUniformType);
368 const GLenum targetBoolType = VariableBoolVectorType(targetUniformType);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000369
Jamie Madill36398922014-05-20 14:51:53 -0400370 LinkedUniform *targetUniform = getUniformByLocation(location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000371
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000372 int elementCount = targetUniform->elementCount();
373
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000374 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
375
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000376 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377 {
Geoff Langbe4fdb32014-09-16 14:11:40 -0400378 T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000379
380 for (int i = 0; i < count; i++)
381 {
Geoff Lang61f54182014-09-16 14:10:02 -0400382 T *dest = target + (i * 4);
383 const T *source = v + (i * components);
384
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000385 for (int c = 0; c < components; c++)
386 {
Geoff Lang61f54182014-09-16 14:10:02 -0400387 SetIfDirty(dest + c, source[c], &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000388 }
389 for (int c = components; c < 4; c++)
390 {
Geoff Lang61f54182014-09-16 14:10:02 -0400391 SetIfDirty(dest + c, T(0), &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000392 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000393 }
394 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000395 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000396 {
Geoff Langbe4fdb32014-09-16 14:11:40 -0400397 GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000399 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000400 {
Geoff Lang61f54182014-09-16 14:10:02 -0400401 GLint *dest = boolParams + (i * 4);
402 const T *source = v + (i * components);
403
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000404 for (int c = 0; c < components; c++)
405 {
Geoff Lang61f54182014-09-16 14:10:02 -0400406 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 +0000407 }
408 for (int c = components; c < 4; c++)
409 {
Geoff Lang61f54182014-09-16 14:10:02 -0400410 SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000411 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000412 }
413 }
Geoff Langbe4fdb32014-09-16 14:11:40 -0400414 else if (IsSampler(targetUniform->type))
415 {
416 ASSERT(targetUniformType == GL_INT);
417
418 GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
419
420 bool wasDirty = targetUniform->dirty;
421
422 for (int i = 0; i < count; i++)
423 {
424 GLint *dest = target + (i * 4);
425 const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
426
427 SetIfDirty(dest + 0, source[0], &targetUniform->dirty);
428 SetIfDirty(dest + 1, 0, &targetUniform->dirty);
429 SetIfDirty(dest + 2, 0, &targetUniform->dirty);
430 SetIfDirty(dest + 3, 0, &targetUniform->dirty);
431 }
432
433 if (!wasDirty && targetUniform->dirty)
434 {
435 mDirtySamplerMapping = true;
436 }
437 }
Jamie Madill36398922014-05-20 14:51:53 -0400438 else UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000439}
440
Jamie Madill36398922014-05-20 14:51:53 -0400441void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000442{
Jamie Madill36398922014-05-20 14:51:53 -0400443 setUniform(location, count, v, GL_FLOAT);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000444}
445
Jamie Madill36398922014-05-20 14:51:53 -0400446void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000447{
Jamie Madill36398922014-05-20 14:51:53 -0400448 setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000449}
450
Jamie Madill36398922014-05-20 14:51:53 -0400451void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000452{
Jamie Madill36398922014-05-20 14:51:53 -0400453 setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000454}
455
Jamie Madill36398922014-05-20 14:51:53 -0400456void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000457{
Jamie Madill36398922014-05-20 14:51:53 -0400458 setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000459}
460
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000461template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400462bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000463{
Geoff Langae1990c2014-05-12 16:57:14 -0400464 bool dirty = false;
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000465 int copyWidth = std::min(targetHeight, srcWidth);
466 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000467
468 for (int x = 0; x < copyWidth; x++)
469 {
470 for (int y = 0; y < copyHeight; y++)
471 {
Geoff Langae1990c2014-05-12 16:57:14 -0400472 SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000473 }
474 }
475 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000476 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000477 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000478 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000479 {
Geoff Langae1990c2014-05-12 16:57:14 -0400480 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000481 }
482 }
483 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000484 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000485 {
486 for (int x = 0; x < targetWidth; x++)
487 {
Geoff Langae1990c2014-05-12 16:57:14 -0400488 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000489 }
490 }
Geoff Langae1990c2014-05-12 16:57:14 -0400491
492 return dirty;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000493}
494
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000495template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400496bool 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 +0000497{
Geoff Langae1990c2014-05-12 16:57:14 -0400498 bool dirty = false;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000499 int copyWidth = std::min(targetWidth, srcWidth);
500 int copyHeight = std::min(targetHeight, srcHeight);
501
502 for (int y = 0; y < copyHeight; y++)
503 {
504 for (int x = 0; x < copyWidth; x++)
505 {
Geoff Langae1990c2014-05-12 16:57:14 -0400506 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000507 }
508 }
509 // clear unfilled right side
510 for (int y = 0; y < copyHeight; y++)
511 {
512 for (int x = copyWidth; x < targetWidth; x++)
513 {
Geoff Langae1990c2014-05-12 16:57:14 -0400514 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000515 }
516 }
517 // clear unfilled bottom.
518 for (int y = copyHeight; y < targetHeight; y++)
519 {
520 for (int x = 0; x < targetWidth; x++)
521 {
Geoff Langae1990c2014-05-12 16:57:14 -0400522 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000523 }
524 }
Geoff Langae1990c2014-05-12 16:57:14 -0400525
526 return dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000527}
528
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000529template <int cols, int rows>
Jamie Madill36398922014-05-20 14:51:53 -0400530void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000531{
Jamie Madill36398922014-05-20 14:51:53 -0400532 LinkedUniform *targetUniform = getUniformByLocation(location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000533
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000534 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000535
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000536 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000537 const unsigned int targetMatrixStride = (4 * rows);
538 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000539
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000540 for (int i = 0; i < count; i++)
541 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000542 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
543 if (transpose == GL_FALSE)
544 {
Geoff Langae1990c2014-05-12 16:57:14 -0400545 targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000546 }
547 else
548 {
Geoff Langae1990c2014-05-12 16:57:14 -0400549 targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000550 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000551 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000552 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000553 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000554}
555
Jamie Madill36398922014-05-20 14:51:53 -0400556void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000557{
Jamie Madill36398922014-05-20 14:51:53 -0400558 setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000559}
560
Jamie Madill36398922014-05-20 14:51:53 -0400561void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000562{
Jamie Madill36398922014-05-20 14:51:53 -0400563 setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000564}
565
Jamie Madill36398922014-05-20 14:51:53 -0400566void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000567{
Jamie Madill36398922014-05-20 14:51:53 -0400568 setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000569}
570
Jamie Madill36398922014-05-20 14:51:53 -0400571void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000572{
Jamie Madill36398922014-05-20 14:51:53 -0400573 setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000574}
575
Jamie Madill36398922014-05-20 14:51:53 -0400576void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000577{
Jamie Madill36398922014-05-20 14:51:53 -0400578 setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000579}
580
Jamie Madill36398922014-05-20 14:51:53 -0400581void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000582{
Jamie Madill36398922014-05-20 14:51:53 -0400583 setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000584}
585
Jamie Madill36398922014-05-20 14:51:53 -0400586void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000587{
Jamie Madill36398922014-05-20 14:51:53 -0400588 setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000589}
590
Jamie Madill36398922014-05-20 14:51:53 -0400591void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000592{
Jamie Madill36398922014-05-20 14:51:53 -0400593 setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000594}
595
Jamie Madill36398922014-05-20 14:51:53 -0400596void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000597{
Jamie Madill36398922014-05-20 14:51:53 -0400598 setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000599}
600
Jamie Madill36398922014-05-20 14:51:53 -0400601void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000602{
Geoff Langbe4fdb32014-09-16 14:11:40 -0400603 setUniform(location, count, v, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000604}
605
Jamie Madill36398922014-05-20 14:51:53 -0400606void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000607{
Jamie Madill36398922014-05-20 14:51:53 -0400608 setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000609}
610
Jamie Madill36398922014-05-20 14:51:53 -0400611void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000612{
Jamie Madill36398922014-05-20 14:51:53 -0400613 setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000614}
615
Jamie Madill36398922014-05-20 14:51:53 -0400616void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000617{
Jamie Madill36398922014-05-20 14:51:53 -0400618 setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000619}
620
Jamie Madill36398922014-05-20 14:51:53 -0400621void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000622{
Jamie Madill36398922014-05-20 14:51:53 -0400623 setUniform(location, count, v, GL_UNSIGNED_INT);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000624}
625
Jamie Madill36398922014-05-20 14:51:53 -0400626void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000627{
Jamie Madill36398922014-05-20 14:51:53 -0400628 setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000629}
630
Jamie Madill36398922014-05-20 14:51:53 -0400631void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000632{
Jamie Madill36398922014-05-20 14:51:53 -0400633 setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000634}
635
Jamie Madill36398922014-05-20 14:51:53 -0400636void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000637{
Jamie Madill36398922014-05-20 14:51:53 -0400638 setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000639}
640
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000641template <typename T>
Jamie Madill99a1e982014-08-25 15:47:54 -0400642void ProgramBinary::getUniformv(GLint location, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000643{
Jamie Madill834e8b72014-04-11 13:33:58 -0400644 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000645
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000646 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000647 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000648 const int rows = VariableRowCount(targetUniform->type);
649 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400650 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 +0000651 }
Jamie Madillf2575982014-06-25 16:04:54 -0400652 else if (uniformType == VariableComponentType(targetUniform->type))
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000653 {
Jamie Madillf2575982014-06-25 16:04:54 -0400654 unsigned int size = VariableComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000655 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
656 size * sizeof(T));
657 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000658 else
659 {
Jamie Madillf2575982014-06-25 16:04:54 -0400660 unsigned int size = VariableComponentCount(targetUniform->type);
661 switch (VariableComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000662 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000663 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000664 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000665 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000666
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000667 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000668 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000669 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000670 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000671 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000672 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000673
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000674 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000675 {
676 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
677
678 for (unsigned int i = 0; i < size; i++)
679 {
680 params[i] = static_cast<T>(floatParams[i]);
681 }
682 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000683 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000684
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000685 case GL_INT:
686 {
687 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
688
689 for (unsigned int i = 0; i < size; i++)
690 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000691 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000692 }
693 }
694 break;
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400695
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000696 case GL_UNSIGNED_INT:
697 {
698 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000699
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000700 for (unsigned int i = 0; i < size; i++)
701 {
702 params[i] = static_cast<T>(uintParams[i]);
703 }
704 }
705 break;
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400706
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000707 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000708 }
709 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000710}
711
Jamie Madill99a1e982014-08-25 15:47:54 -0400712void ProgramBinary::getUniformfv(GLint location, GLfloat *params)
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000713{
Jamie Madill99a1e982014-08-25 15:47:54 -0400714 getUniformv(location, params, GL_FLOAT);
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000715}
716
Jamie Madill99a1e982014-08-25 15:47:54 -0400717void ProgramBinary::getUniformiv(GLint location, GLint *params)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000718{
Jamie Madill99a1e982014-08-25 15:47:54 -0400719 getUniformv(location, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720}
721
Jamie Madill99a1e982014-08-25 15:47:54 -0400722void ProgramBinary::getUniformuiv(GLint location, GLuint *params)
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000723{
Jamie Madill99a1e982014-08-25 15:47:54 -0400724 getUniformv(location, params, GL_UNSIGNED_INT);
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000725}
726
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000727void ProgramBinary::dirtyAllUniforms()
728{
729 unsigned int numUniforms = mUniforms.size();
730 for (unsigned int index = 0; index < numUniforms; index++)
731 {
732 mUniforms[index]->dirty = true;
733 }
734}
735
Jamie Madilld4cfa572014-07-08 10:00:32 -0400736void ProgramBinary::updateSamplerMapping()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000737{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400738 if (!mDirtySamplerMapping)
739 {
740 return;
741 }
742
743 mDirtySamplerMapping = false;
744
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000745 // Retrieve sampler uniform values
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500746 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000747 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400748 LinkedUniform *targetUniform = mUniforms[uniformIndex];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000749
750 if (targetUniform->dirty)
751 {
Nicolas Capense6050882013-07-08 10:43:10 -0400752 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000753 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000754 int count = targetUniform->elementCount();
Jamie Madilld4cfa572014-07-08 10:00:32 -0400755 GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000756
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000757 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000758 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000759 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000760
761 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000762 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000763 unsigned int samplerIndex = firstIndex + i;
764
Geoff Lang76b10c92014-09-05 16:28:14 -0400765 if (samplerIndex < mSamplersPS.size())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000766 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000767 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000768 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000769 }
770 }
771 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000772
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000773 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000774 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000775 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000776
777 for (int i = 0; i < count; i++)
778 {
779 unsigned int samplerIndex = firstIndex + i;
780
Geoff Lang76b10c92014-09-05 16:28:14 -0400781 if (samplerIndex < mSamplersVS.size())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000782 {
783 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000784 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000785 }
786 }
787 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000788 }
789 }
790 }
Jamie Madilld4cfa572014-07-08 10:00:32 -0400791}
792
793// Applies all the uniforms set for this program object to the renderer
Geoff Langc77e8c32014-09-08 16:28:24 -0400794Error ProgramBinary::applyUniforms()
Jamie Madilld4cfa572014-07-08 10:00:32 -0400795{
796 updateSamplerMapping();
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000797
Brandon Jones18bd4102014-09-22 14:21:44 -0700798 Error error = mProgram->applyUniforms(mUniforms);
Geoff Langc77e8c32014-09-08 16:28:24 -0400799 if (error.isError())
800 {
801 return error;
802 }
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500803
804 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
805 {
806 mUniforms[uniformIndex]->dirty = false;
807 }
Geoff Langc77e8c32014-09-08 16:28:24 -0400808
809 return gl::Error(GL_NO_ERROR);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000810}
811
Geoff Langc77e8c32014-09-08 16:28:24 -0400812Error ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000813{
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000814 ASSERT(boundBuffers.size() == mUniformBlocks.size());
Brandon Jones18bd4102014-09-22 14:21:44 -0700815 return mProgram->applyUniformBuffers(mUniformBlocks, boundBuffers, caps);
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000816}
817
Brandon Jones71620962014-08-20 14:04:59 -0700818bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000819{
Jamie Madilld15250e2014-09-03 09:40:44 -0400820 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
821 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
Jamie Madill5f562732014-02-14 16:41:24 -0500822
823 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000824 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -0400825 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000826 bool matched = false;
827
Jamie Madill54ad4f82014-09-03 09:40:46 -0400828 // Built-in varyings obey special rules
829 if (input->isBuiltIn())
830 {
831 continue;
832 }
833
Jamie Madill5f562732014-02-14 16:41:24 -0500834 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000835 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -0400836 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000837 if (output->name == input->name)
838 {
Jamie Madill42bcf322014-08-25 16:20:46 -0400839 if (!linkValidateVaryings(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000840 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000841 return false;
842 }
843
Jamie Madill139b9092013-08-30 13:21:06 -0400844 output->registerIndex = input->registerIndex;
Austin Kinrossaf875522014-08-25 21:06:07 -0700845 output->columnIndex = input->columnIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000846
847 matched = true;
848 break;
849 }
850 }
851
Jamie Madill54ad4f82014-09-03 09:40:46 -0400852 // We permit unmatched, unreferenced varyings
853 if (!matched && input->staticUse)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000854 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000855 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000856 return false;
857 }
858 }
859
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000860 return true;
861}
862
Geoff Langb543aff2014-09-30 14:52:54 -0400863LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000864{
Jamie Madill9c4b24a2014-06-12 13:41:17 -0400865#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
Geoff Langb543aff2014-09-30 14:52:54 -0400866 return LinkResult(false, Error(GL_NO_ERROR));
Jamie Madill9c4b24a2014-06-12 13:41:17 -0400867#else
Brandon Jones22502d52014-08-29 16:58:36 -0700868 ASSERT(binaryFormat == mProgram->getBinaryFormat());
Geoff Lang900013c2014-07-07 11:32:19 -0400869
Geoff Lang04fb89a2014-06-09 15:05:36 -0400870 reset();
871
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +0000872 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000873
Brandon Jones22502d52014-08-29 16:58:36 -0700874 GLenum format = stream.readInt<GLenum>();
875 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000876 {
877 infoLog.append("Invalid program binary format.");
Geoff Langb543aff2014-09-30 14:52:54 -0400878 return LinkResult(false, Error(GL_NO_ERROR));
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000879 }
880
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400881 int majorVersion = stream.readInt<int>();
882 int minorVersion = stream.readInt<int>();
Jamie Madill0aa84f62014-02-13 13:17:23 -0500883 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
Jamie Madill049108d2013-11-19 10:41:49 -0500884 {
885 infoLog.append("Invalid program binary version.");
Geoff Langb543aff2014-09-30 14:52:54 -0400886 return LinkResult(false, Error(GL_NO_ERROR));
Jamie Madill049108d2013-11-19 10:41:49 -0500887 }
888
Jamie Madill0aa84f62014-02-13 13:17:23 -0500889 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400890 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
Jamie Madill0aa84f62014-02-13 13:17:23 -0500891 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000892 {
893 infoLog.append("Invalid program binary version.");
Geoff Langb543aff2014-09-30 14:52:54 -0400894 return LinkResult(false, Error(GL_NO_ERROR));
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000895 }
896
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400897 int compileFlags = stream.readInt<int>();
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +0000898 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
899 {
900 infoLog.append("Mismatched compilation flags.");
Geoff Langb543aff2014-09-30 14:52:54 -0400901 return LinkResult(false, Error(GL_NO_ERROR));
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +0000902 }
903
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000904 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
905 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400906 stream.readInt(&mLinkedAttribute[i].type);
907 stream.readString(&mLinkedAttribute[i].name);
Brandon Joneseb994362014-09-24 10:27:28 -0700908 stream.readInt(&mProgram->getShaderAttributes()[i].type);
909 stream.readString(&mProgram->getShaderAttributes()[i].name);
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400910 stream.readInt(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000911 }
912
Al Patrick3f2daa82013-08-07 12:58:57 -0700913 initAttributesByLayout();
914
Geoff Lang76b10c92014-09-05 16:28:14 -0400915 const unsigned int psSamplerCount = stream.readInt<unsigned int>();
916 for (unsigned int i = 0; i < psSamplerCount; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000917 {
Geoff Lang76b10c92014-09-05 16:28:14 -0400918 Sampler sampler;
919 stream.readBool(&sampler.active);
920 stream.readInt(&sampler.logicalTextureUnit);
921 stream.readInt(&sampler.textureType);
922 mSamplersPS.push_back(sampler);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000923 }
Geoff Lang76b10c92014-09-05 16:28:14 -0400924 const unsigned int vsSamplerCount = stream.readInt<unsigned int>();
925 for (unsigned int i = 0; i < vsSamplerCount; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000926 {
Geoff Lang76b10c92014-09-05 16:28:14 -0400927 Sampler sampler;
928 stream.readBool(&sampler.active);
929 stream.readInt(&sampler.logicalTextureUnit);
930 stream.readInt(&sampler.textureType);
931 mSamplersVS.push_back(sampler);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000932 }
933
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400934 stream.readInt(&mUsedVertexSamplerRange);
935 stream.readInt(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000936
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400937 const unsigned int uniformCount = stream.readInt<unsigned int>();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +0000938 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000939 {
940 infoLog.append("Invalid program binary.");
Geoff Langb543aff2014-09-30 14:52:54 -0400941 return LinkResult(false, Error(GL_NO_ERROR));
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000942 }
943
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400944 mUniforms.resize(uniformCount);
945 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000946 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400947 GLenum type = stream.readInt<GLenum>();
948 GLenum precision = stream.readInt<GLenum>();
949 std::string name = stream.readString();
950 unsigned int arraySize = stream.readInt<unsigned int>();
951 int blockIndex = stream.readInt<int>();
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000952
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400953 int offset = stream.readInt<int>();
954 int arrayStride = stream.readInt<int>();
955 int matrixStride = stream.readInt<int>();
956 bool isRowMajorMatrix = stream.readBool();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000957
Jamie Madillf2575982014-06-25 16:04:54 -0400958 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000959
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400960 LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
961
962 stream.readInt(&uniform->psRegisterIndex);
963 stream.readInt(&uniform->vsRegisterIndex);
964 stream.readInt(&uniform->registerCount);
965 stream.readInt(&uniform->registerElement);
966
967 mUniforms[uniformIndex] = uniform;
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000968 }
969
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400970 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +0000971 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000972 {
973 infoLog.append("Invalid program binary.");
Geoff Langb543aff2014-09-30 14:52:54 -0400974 return LinkResult(false, Error(GL_NO_ERROR));
apatrick@chromium.org90080e32012-07-09 22:15:33 +0000975 }
976
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400977 mUniformBlocks.resize(uniformBlockCount);
978 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000979 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400980 std::string name = stream.readString();
981 unsigned int elementIndex = stream.readInt<unsigned int>();
982 unsigned int dataSize = stream.readInt<unsigned int>();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000983
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400984 UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000985
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400986 stream.readInt(&uniformBlock->psRegisterIndex);
987 stream.readInt(&uniformBlock->vsRegisterIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000988
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400989 unsigned int numMembers = stream.readInt<unsigned int>();
990 uniformBlock->memberUniformIndexes.resize(numMembers);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000991 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
992 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400993 stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000994 }
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400995
996 mUniformBlocks[uniformBlockIndex] = uniformBlock;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000997 }
998
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400999 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001000 if (stream.error())
1001 {
1002 infoLog.append("Invalid program binary.");
Geoff Langb543aff2014-09-30 14:52:54 -04001003 return LinkResult(false, Error(GL_NO_ERROR));
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001004 }
1005
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001006 mUniformIndex.resize(uniformIndexCount);
1007 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001008 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001009 stream.readString(&mUniformIndex[uniformIndexIndex].name);
1010 stream.readInt(&mUniformIndex[uniformIndexIndex].element);
1011 stream.readInt(&mUniformIndex[uniformIndexIndex].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001012 }
1013
Geoff Langb543aff2014-09-30 14:52:54 -04001014 LinkResult result = mProgram->load(infoLog, &stream);
1015 if (result.error.isError() || !result.linkSuccess)
Brandon Jones22502d52014-08-29 16:58:36 -07001016 {
Geoff Langb543aff2014-09-30 14:52:54 -04001017 return result;
Brandon Jones22502d52014-08-29 16:58:36 -07001018 }
1019
Brandon Jonesc9610c52014-08-25 17:02:59 -07001020 mProgram->initializeUniformStorage(mUniforms);
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001021
Geoff Langb543aff2014-09-30 14:52:54 -04001022 return LinkResult(true, Error(GL_NO_ERROR));
Jamie Madill9c4b24a2014-06-12 13:41:17 -04001023#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001024}
1025
Geoff Langb543aff2014-09-30 14:52:54 -04001026Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001027{
Geoff Lang900013c2014-07-07 11:32:19 -04001028 if (binaryFormat)
1029 {
Brandon Jones22502d52014-08-29 16:58:36 -07001030 *binaryFormat = mProgram->getBinaryFormat();
Geoff Lang900013c2014-07-07 11:32:19 -04001031 }
1032
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001033 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001034
Brandon Jones22502d52014-08-29 16:58:36 -07001035 stream.writeInt(mProgram->getBinaryFormat());
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001036 stream.writeInt(ANGLE_MAJOR_VERSION);
1037 stream.writeInt(ANGLE_MINOR_VERSION);
Ehsan Akhgariaa7e1662014-07-05 21:13:11 -04001038 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001039 stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001040
1041 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1042 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001043 stream.writeInt(mLinkedAttribute[i].type);
1044 stream.writeString(mLinkedAttribute[i].name);
Brandon Joneseb994362014-09-24 10:27:28 -07001045 stream.writeInt(mProgram->getShaderAttributes()[i].type);
1046 stream.writeString(mProgram->getShaderAttributes()[i].name);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001047 stream.writeInt(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001048 }
1049
Geoff Lang76b10c92014-09-05 16:28:14 -04001050 stream.writeInt(mSamplersPS.size());
1051 for (unsigned int i = 0; i < mSamplersPS.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001052 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001053 stream.writeInt(mSamplersPS[i].active);
1054 stream.writeInt(mSamplersPS[i].logicalTextureUnit);
1055 stream.writeInt(mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001056 }
1057
Geoff Lang76b10c92014-09-05 16:28:14 -04001058 stream.writeInt(mSamplersVS.size());
1059 for (unsigned int i = 0; i < mSamplersVS.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001060 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001061 stream.writeInt(mSamplersVS[i].active);
1062 stream.writeInt(mSamplersVS[i].logicalTextureUnit);
1063 stream.writeInt(mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001064 }
1065
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001066 stream.writeInt(mUsedVertexSamplerRange);
1067 stream.writeInt(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001068
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001069 stream.writeInt(mUniforms.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001070 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001071 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001072 const LinkedUniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001073
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001074 stream.writeInt(uniform.type);
1075 stream.writeInt(uniform.precision);
1076 stream.writeString(uniform.name);
1077 stream.writeInt(uniform.arraySize);
1078 stream.writeInt(uniform.blockIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001079
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001080 stream.writeInt(uniform.blockInfo.offset);
1081 stream.writeInt(uniform.blockInfo.arrayStride);
1082 stream.writeInt(uniform.blockInfo.matrixStride);
1083 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001084
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001085 stream.writeInt(uniform.psRegisterIndex);
1086 stream.writeInt(uniform.vsRegisterIndex);
1087 stream.writeInt(uniform.registerCount);
1088 stream.writeInt(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001089 }
1090
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001091 stream.writeInt(mUniformBlocks.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001092 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001093 {
1094 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1095
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001096 stream.writeString(uniformBlock.name);
1097 stream.writeInt(uniformBlock.elementIndex);
1098 stream.writeInt(uniformBlock.dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001099
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001100 stream.writeInt(uniformBlock.memberUniformIndexes.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001101 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1102 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001103 stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001104 }
1105
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001106 stream.writeInt(uniformBlock.psRegisterIndex);
1107 stream.writeInt(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001108 }
1109
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001110 stream.writeInt(mUniformIndex.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001111 for (size_t i = 0; i < mUniformIndex.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001112 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001113 stream.writeString(mUniformIndex[i].name);
1114 stream.writeInt(mUniformIndex[i].element);
1115 stream.writeInt(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001116 }
1117
Geoff Langb543aff2014-09-30 14:52:54 -04001118 mProgram->save(&stream);
Brandon Jones22502d52014-08-29 16:58:36 -07001119
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001120 GLsizei streamLength = stream.length();
1121 const void *streamData = stream.data();
1122
Brandon Jones18bd4102014-09-22 14:21:44 -07001123 if (streamLength > bufSize)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001124 {
1125 if (length)
1126 {
1127 *length = 0;
1128 }
1129
Geoff Langb543aff2014-09-30 14:52:54 -04001130 // TODO: This should be moved to the validation layer but computing the size of the binary before saving
1131 // it causes the save to happen twice. It may be possible to write the binary to a separate buffer, validate
1132 // sizes and then copy it.
1133 return Error(GL_INVALID_OPERATION);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001134 }
1135
1136 if (binary)
1137 {
1138 char *ptr = (char*) binary;
1139
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001140 memcpy(ptr, streamData, streamLength);
1141 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001142
Brandon Jones18bd4102014-09-22 14:21:44 -07001143 ASSERT(ptr - streamLength == binary);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001144 }
1145
1146 if (length)
1147 {
Brandon Jones18bd4102014-09-22 14:21:44 -07001148 *length = streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001149 }
1150
Geoff Langb543aff2014-09-30 14:52:54 -04001151 return Error(GL_NO_ERROR);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001152}
1153
1154GLint ProgramBinary::getLength()
1155{
1156 GLint length;
Geoff Langb543aff2014-09-30 14:52:54 -04001157 Error error = save(NULL, NULL, INT_MAX, &length);
1158 if (error.isError())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001159 {
1160 return 0;
1161 }
Geoff Langb543aff2014-09-30 14:52:54 -04001162
1163 return length;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001164}
1165
Geoff Langb543aff2014-09-30 14:52:54 -04001166LinkResult ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
1167 const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001168{
1169 if (!fragmentShader || !fragmentShader->isCompiled())
1170 {
Geoff Langb543aff2014-09-30 14:52:54 -04001171 return LinkResult(false, Error(GL_NO_ERROR));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001172 }
Brandon Jones71620962014-08-20 14:04:59 -07001173 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001174
1175 if (!vertexShader || !vertexShader->isCompiled())
1176 {
Geoff Langb543aff2014-09-30 14:52:54 -04001177 return LinkResult(false, Error(GL_NO_ERROR));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001178 }
Brandon Jones71620962014-08-20 14:04:59 -07001179 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001180
Geoff Lang04fb89a2014-06-09 15:05:36 -04001181 reset();
1182
Geoff Lang76b10c92014-09-05 16:28:14 -04001183 mSamplersPS.resize(caps.maxTextureImageUnits);
1184 mSamplersVS.resize(caps.maxVertexTextureImageUnits);
1185
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001186 rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
1187 rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001188
Brandon Jones22502d52014-08-29 16:58:36 -07001189 int registers;
1190 std::vector<LinkedVarying> linkedVaryings;
Geoff Langb543aff2014-09-30 14:52:54 -04001191 LinkResult result = mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode,
1192 &registers, &linkedVaryings, &mOutputVariables, caps);
1193 if (result.error.isError() || !result.linkSuccess)
Jamie Madill5f562732014-02-14 16:41:24 -05001194 {
Geoff Langb543aff2014-09-30 14:52:54 -04001195 return result;
Jamie Madill5f562732014-02-14 16:41:24 -05001196 }
1197
Jamie Madilld15250e2014-09-03 09:40:44 -04001198 if (!linkAttributes(infoLog, attributeBindings, vertexShader))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001199 {
Geoff Langb543aff2014-09-30 14:52:54 -04001200 return LinkResult(false, Error(GL_NO_ERROR));
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001201 }
1202
Brandon Jones43a53e22014-08-28 16:23:22 -07001203 if (!linkUniforms(infoLog, *vertexShader, *fragmentShader, caps))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001204 {
Geoff Langb543aff2014-09-30 14:52:54 -04001205 return LinkResult(false, Error(GL_NO_ERROR));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001206 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001207
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001208 // special case for gl_DepthRange, the only built-in uniform (also a struct)
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001209 if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange())
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001210 {
Jamie Madille04a5b72014-07-18 10:33:12 -04001211 const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo();
1212
1213 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo));
1214 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo));
1215 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001216 }
1217
Brandon Jones43a53e22014-08-28 16:23:22 -07001218 if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001219 {
Geoff Langb543aff2014-09-30 14:52:54 -04001220 return LinkResult(false, Error(GL_NO_ERROR));
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001221 }
1222
Geoff Lang48dcae72014-02-05 16:28:24 -05001223 if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
Brandon Joneseb994362014-09-24 10:27:28 -07001224 transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), caps))
Geoff Lang48dcae72014-02-05 16:28:24 -05001225 {
Geoff Langb543aff2014-09-30 14:52:54 -04001226 return LinkResult(false, Error(GL_NO_ERROR));
Geoff Lang48dcae72014-02-05 16:28:24 -05001227 }
1228
Geoff Langb543aff2014-09-30 14:52:54 -04001229 // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
1230 // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
1231 result = mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers);
1232 if (result.error.isError() || !result.linkSuccess)
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001233 {
Geoff Langb543aff2014-09-30 14:52:54 -04001234 infoLog.append("Failed to create D3D shaders.");
1235 reset();
1236 return result;
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001237 }
1238
Geoff Langb543aff2014-09-30 14:52:54 -04001239 return LinkResult(true, Error(GL_NO_ERROR));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001240}
1241
1242// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madilld15250e2014-09-03 09:40:44 -04001243bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001244{
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001245 const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001246
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001247 unsigned int usedLocations = 0;
Jamie Madill54ad4f82014-09-03 09:40:46 -04001248 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001249
1250 // Link attributes that have a binding location
Jamie Madill54ad4f82014-09-03 09:40:46 -04001251 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001252 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001253 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1254
1255 ASSERT(attribute.staticUse);
1256
Jamie Madilleba4eff2013-06-20 11:55:51 -04001257 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001258
Brandon Joneseb994362014-09-24 10:27:28 -07001259 mProgram->getShaderAttributes()[attributeIndex] = attribute;
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001260
Jamie Madilleba4eff2013-06-20 11:55:51 -04001261 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001262 {
Jamie Madillf2575982014-06-25 16:04:54 -04001263 const int rows = VariableRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001264
1265 if (rows + location > MAX_VERTEX_ATTRIBS)
1266 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001267 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 +00001268
1269 return false;
1270 }
1271
Jamie Madilleba4eff2013-06-20 11:55:51 -04001272 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001273 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001274 const int rowLocation = location + row;
Jamie Madillf2575982014-06-25 16:04:54 -04001275 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001276
1277 // In GLSL 3.00, attribute aliasing produces a link error
1278 // In GLSL 1.00, attribute aliasing is allowed
Brandon Jones44151a92014-09-10 11:32:25 -07001279 if (mProgram->getShaderVersion() >= 300)
Jamie Madilleba4eff2013-06-20 11:55:51 -04001280 {
1281 if (!linkedAttribute.name.empty())
1282 {
1283 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1284 return false;
1285 }
1286 }
1287
1288 linkedAttribute = attribute;
1289 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001290 }
1291 }
1292 }
1293
1294 // Link attributes that don't have a binding location
Jamie Madill54ad4f82014-09-03 09:40:46 -04001295 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001296 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001297 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1298
1299 ASSERT(attribute.staticUse);
1300
Jamie Madilleba4eff2013-06-20 11:55:51 -04001301 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001302
Jamie Madilleba4eff2013-06-20 11:55:51 -04001303 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001304 {
Jamie Madillf2575982014-06-25 16:04:54 -04001305 int rows = VariableRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001306 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1307
1308 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1309 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001310 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001311
1312 return false; // Fail to link
1313 }
1314
Jamie Madilldefb6742013-06-20 11:55:51 -04001315 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001316 }
1317 }
1318
1319 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1320 {
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001321 int index = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillf2575982014-06-25 16:04:54 -04001322 int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001323
1324 for (int r = 0; r < rows; r++)
1325 {
1326 mSemanticIndex[attributeIndex++] = index++;
1327 }
1328 }
1329
Al Patrick3f2daa82013-08-07 12:58:57 -07001330 initAttributesByLayout();
1331
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001332 return true;
1333}
1334
Jamie Madillf2575982014-06-25 16:04:54 -04001335bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1336 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001337{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001338 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001339 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001340 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001341 return false;
1342 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001343 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001344 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001345 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001346 return false;
1347 }
Jamie Madill28167c62013-08-30 13:21:10 -04001348 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001349 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001350 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04001351 return false;
1352 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001353
Jamie Madill42bcf322014-08-25 16:20:46 -04001354 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001355 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001356 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001357 return false;
1358 }
Jamie Madill42bcf322014-08-25 16:20:46 -04001359 const unsigned int numMembers = vertexVariable.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001360 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1361 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001362 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1363 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001364
1365 if (vertexMember.name != fragmentMember.name)
1366 {
Jamie Madill28167c62013-08-30 13:21:10 -04001367 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
Jamie Madill42bcf322014-08-25 16:20:46 -04001368 memberIndex, variableName.c_str(),
1369 vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001370 return false;
1371 }
1372
Jamie Madill42bcf322014-08-25 16:20:46 -04001373 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1374 vertexMember.name + "'";
1375
1376 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001377 {
1378 return false;
1379 }
1380 }
1381
1382 return true;
1383}
1384
Jamie Madill42bcf322014-08-25 16:20:46 -04001385bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001386{
Jamie Madill28167c62013-08-30 13:21:10 -04001387 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001388 {
1389 return false;
1390 }
1391
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001392 return true;
1393}
1394
Jamie Madill42bcf322014-08-25 16:20:46 -04001395bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
Jamie Madill28167c62013-08-30 13:21:10 -04001396{
1397 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1398 {
1399 return false;
1400 }
1401
1402 if (vertexVarying.interpolation != fragmentVarying.interpolation)
1403 {
1404 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1405 return false;
1406 }
1407
Jamie Madill28167c62013-08-30 13:21:10 -04001408 return true;
1409}
1410
Jamie Madill42bcf322014-08-25 16:20:46 -04001411bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001412{
Jamie Madill28167c62013-08-30 13:21:10 -04001413 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001414 {
1415 return false;
1416 }
1417
Jamie Madilla6f267f2014-08-27 11:44:15 -04001418 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001419 {
1420 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1421 return false;
1422 }
1423
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001424 return true;
1425}
1426
Brandon Jones43a53e22014-08-28 16:23:22 -07001427bool ProgramBinary::linkUniforms(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001428{
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001429 const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader.getImplementation());
1430 const rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader.getImplementation());
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001431
Jamie Madilld15250e2014-09-03 09:40:44 -04001432 const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms();
1433 const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms();
Jamie Madillbf9cce22014-07-18 10:33:09 -04001434
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001435 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madillf2575982014-06-25 16:04:54 -04001436 typedef std::map<std::string, const sh::Uniform*> UniformMap;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001437 UniformMap linkedUniforms;
1438
1439 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
1440 {
Jamie Madillf2575982014-06-25 16:04:54 -04001441 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001442 linkedUniforms[vertexUniform.name] = &vertexUniform;
1443 }
1444
1445 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
1446 {
Jamie Madillf2575982014-06-25 16:04:54 -04001447 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001448 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
1449 if (entry != linkedUniforms.end())
1450 {
Jamie Madillf2575982014-06-25 16:04:54 -04001451 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04001452 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill42bcf322014-08-25 16:20:46 -04001453 if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001454 {
1455 return false;
1456 }
1457 }
1458 }
1459
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001460 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001461 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001462 const sh::Uniform &uniform = vertexUniforms[uniformIndex];
Jamie Madill54ad4f82014-09-03 09:40:46 -04001463
1464 if (uniform.staticUse)
1465 {
1466 defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShaderD3D->getUniformRegister(uniform.name));
1467 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001468 }
1469
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001470 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001471 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001472 const sh::Uniform &uniform = fragmentUniforms[uniformIndex];
Jamie Madill54ad4f82014-09-03 09:40:46 -04001473
1474 if (uniform.staticUse)
1475 {
1476 defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShaderD3D->getUniformRegister(uniform.name));
1477 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001478 }
1479
Brandon Jones43a53e22014-08-28 16:23:22 -07001480 if (!indexUniforms(infoLog, caps))
Jamie Madill66d43d22014-07-11 17:02:03 -04001481 {
1482 return false;
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001483 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001484
Brandon Jonesc9610c52014-08-25 17:02:59 -07001485 mProgram->initializeUniformStorage(mUniforms);
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001486
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001487 return true;
1488}
1489
Jamie Madillbf9cce22014-07-18 10:33:09 -04001490void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001491{
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001492 ShShaderOutput outputType = rx::ShaderD3D::getCompilerOutputType(shader);
Jamie Madille04a5b72014-07-18 10:33:12 -04001493 sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
Jamie Madillbf9cce22014-07-18 10:33:09 -04001494 encoder.skipRegisters(uniformRegister);
1495
1496 defineUniform(shader, uniform, uniform.name, &encoder);
Jamie Madill5b130dc2014-07-11 17:02:05 -04001497}
1498
Jamie Madill42bcf322014-08-25 16:20:46 -04001499void ProgramBinary::defineUniform(GLenum shader, const sh::ShaderVariable &uniform,
Jamie Madillbf9cce22014-07-18 10:33:09 -04001500 const std::string &fullName, sh::HLSLBlockEncoder *encoder)
Jamie Madill5b130dc2014-07-11 17:02:05 -04001501{
1502 if (uniform.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001503 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001504 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001505 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001506 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001507
Jamie Madillbf9cce22014-07-18 10:33:09 -04001508 encoder->enterAggregateType();
Jamie Madillc600c8c2014-05-16 11:22:21 -04001509
Jamie Madill5b130dc2014-07-11 17:02:05 -04001510 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001511 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001512 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
Jamie Madillbf9cce22014-07-18 10:33:09 -04001513 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
1514
1515 defineUniform(shader, field, fieldFullName, encoder);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001516 }
Jamie Madillbf9cce22014-07-18 10:33:09 -04001517
1518 encoder->exitAggregateType();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001519 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001520 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001521 else // Not a struct
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001522 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001523 // Arrays are treated as aggregate types
1524 if (uniform.isArray())
1525 {
1526 encoder->enterAggregateType();
1527 }
1528
Jamie Madill5b130dc2014-07-11 17:02:05 -04001529 LinkedUniform *linkedUniform = getUniformByName(fullName);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001530
Jamie Madill66d43d22014-07-11 17:02:03 -04001531 if (!linkedUniform)
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001532 {
Jamie Madill5b130dc2014-07-11 17:02:05 -04001533 linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
Jamie Madill66d43d22014-07-11 17:02:03 -04001534 -1, sh::BlockMemberInfo::getDefaultBlockInfo());
1535 ASSERT(linkedUniform);
Jamie Madillbf9cce22014-07-18 10:33:09 -04001536 linkedUniform->registerElement = encoder->getCurrentElement();
Jamie Madill66d43d22014-07-11 17:02:03 -04001537 mUniforms.push_back(linkedUniform);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001538 }
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001539
Jamie Madillbf9cce22014-07-18 10:33:09 -04001540 ASSERT(linkedUniform->registerElement == encoder->getCurrentElement());
1541
Jamie Madill66d43d22014-07-11 17:02:03 -04001542 if (shader == GL_FRAGMENT_SHADER)
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001543 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001544 linkedUniform->psRegisterIndex = encoder->getCurrentRegister();
Jamie Madill66d43d22014-07-11 17:02:03 -04001545 }
1546 else if (shader == GL_VERTEX_SHADER)
1547 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001548 linkedUniform->vsRegisterIndex = encoder->getCurrentRegister();
Jamie Madill66d43d22014-07-11 17:02:03 -04001549 }
1550 else UNREACHABLE();
Jamie Madillbf9cce22014-07-18 10:33:09 -04001551
1552 // Advance the uniform offset, to track registers allocation for structs
1553 encoder->encodeType(uniform.type, uniform.arraySize, false);
1554
1555 // Arrays are treated as aggregate types
1556 if (uniform.isArray())
1557 {
1558 encoder->exitAggregateType();
1559 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001560 }
1561}
1562
Brandon Jones43a53e22014-08-28 16:23:22 -07001563bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog, const Caps &caps)
Jamie Madill66d43d22014-07-11 17:02:03 -04001564{
1565 ASSERT(IsSampler(uniform.type));
1566 ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
1567
1568 if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
1569 {
1570 if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
Geoff Lang76b10c92014-09-05 16:28:14 -04001571 &mUsedVertexSamplerRange))
Jamie Madill66d43d22014-07-11 17:02:03 -04001572 {
1573 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).",
Geoff Lang76b10c92014-09-05 16:28:14 -04001574 mSamplersVS.size());
Jamie Madill66d43d22014-07-11 17:02:03 -04001575 return false;
1576 }
1577
Brandon Jones18bd4102014-09-22 14:21:44 -07001578 unsigned int maxVertexVectors = mProgram->getReservedUniformVectors(GL_VERTEX_SHADER) + caps.maxVertexUniformVectors;
Jamie Madill66d43d22014-07-11 17:02:03 -04001579 if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
1580 {
1581 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)",
Geoff Lang301d1612014-07-09 10:34:37 -04001582 caps.maxVertexUniformVectors);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001583 return false;
1584 }
1585 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001586
1587 if (uniform.psRegisterIndex != GL_INVALID_INDEX)
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001588 {
Jamie Madill66d43d22014-07-11 17:02:03 -04001589 if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
Geoff Lang76b10c92014-09-05 16:28:14 -04001590 &mUsedPixelSamplerRange))
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001591 {
Jamie Madill66d43d22014-07-11 17:02:03 -04001592 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).",
Geoff Lang76b10c92014-09-05 16:28:14 -04001593 mSamplersPS.size());
Jamie Madill66d43d22014-07-11 17:02:03 -04001594 return false;
1595 }
1596
Brandon Jones18bd4102014-09-22 14:21:44 -07001597 unsigned int maxFragmentVectors = mProgram->getReservedUniformVectors(GL_FRAGMENT_SHADER) + caps.maxFragmentUniformVectors;
Jamie Madill66d43d22014-07-11 17:02:03 -04001598 if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
1599 {
1600 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)",
Geoff Lang301d1612014-07-09 10:34:37 -04001601 caps.maxFragmentUniformVectors);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001602 return false;
1603 }
1604 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001605
1606 return true;
1607}
1608
Brandon Jones43a53e22014-08-28 16:23:22 -07001609bool ProgramBinary::indexUniforms(InfoLog &infoLog, const Caps &caps)
Jamie Madill66d43d22014-07-11 17:02:03 -04001610{
1611 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
1612 {
1613 const LinkedUniform &uniform = *mUniforms[uniformIndex];
1614
1615 if (IsSampler(uniform.type))
1616 {
Brandon Jones43a53e22014-08-28 16:23:22 -07001617 if (!indexSamplerUniform(uniform, infoLog, caps))
Jamie Madill66d43d22014-07-11 17:02:03 -04001618 {
1619 return false;
1620 }
1621 }
1622
1623 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++)
1624 {
1625 mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex));
1626 }
1627 }
1628
1629 return true;
1630}
1631
1632bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex,
1633 GLenum samplerType,
1634 unsigned int samplerCount,
Geoff Lang76b10c92014-09-05 16:28:14 -04001635 std::vector<Sampler> &outSamplers,
1636 GLuint *outUsedRange)
Jamie Madill66d43d22014-07-11 17:02:03 -04001637{
1638 unsigned int samplerIndex = startSamplerIndex;
1639
1640 do
1641 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001642 if (samplerIndex < outSamplers.size())
Jamie Madill66d43d22014-07-11 17:02:03 -04001643 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001644 Sampler& sampler = outSamplers[samplerIndex];
1645 sampler.active = true;
1646 sampler.textureType = GetTextureType(samplerType);
1647 sampler.logicalTextureUnit = 0;
1648 *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
Jamie Madill66d43d22014-07-11 17:02:03 -04001649 }
1650 else
1651 {
1652 return false;
1653 }
1654
1655 samplerIndex++;
1656 } while (samplerIndex < startSamplerIndex + samplerCount);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001657
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001658 return true;
1659}
1660
Jamie Madillf2575982014-06-25 16:04:54 -04001661bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001662{
1663 const char* blockName = vertexInterfaceBlock.name.c_str();
1664
1665 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001666 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001667 {
1668 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
1669 return false;
1670 }
1671
1672 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
1673 {
1674 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
1675 return false;
1676 }
1677
Jamie Madill9060a4e2013-08-12 16:22:57 -07001678 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
1679 {
1680 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
1681 return false;
1682 }
1683
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001684 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001685 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
1686 {
Jamie Madillf2575982014-06-25 16:04:54 -04001687 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
1688 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001689
1690 if (vertexMember.name != fragmentMember.name)
1691 {
Jamie Madill28167c62013-08-30 13:21:10 -04001692 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 +00001693 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
1694 return false;
1695 }
1696
Jamie Madill42bcf322014-08-25 16:20:46 -04001697 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
1698 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001699 {
1700 return false;
1701 }
1702 }
1703
1704 return true;
1705}
1706
Brandon Jones43a53e22014-08-28 16:23:22 -07001707bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001708{
Jamie Madilld15250e2014-09-03 09:40:44 -04001709 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
1710 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madilld4116ff2014-07-11 17:02:01 -04001711
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001712 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jamie Madillf2575982014-06-25 16:04:54 -04001713 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001714 UniformBlockMap linkedUniformBlocks;
1715
1716 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1717 {
Jamie Madillf2575982014-06-25 16:04:54 -04001718 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001719 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
1720 }
1721
1722 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1723 {
Jamie Madillf2575982014-06-25 16:04:54 -04001724 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001725 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
1726 if (entry != linkedUniformBlocks.end())
1727 {
Jamie Madillf2575982014-06-25 16:04:54 -04001728 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001729 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
1730 {
1731 return false;
1732 }
1733 }
1734 }
1735
1736 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
1737 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001738 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
1739
Jamie Madill04668672014-09-03 09:40:49 -04001740 // Note: shared and std140 layouts are always considered active
1741 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001742 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001743 if (!defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
1744 {
1745 return false;
1746 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001747 }
1748 }
1749
1750 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
1751 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001752 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
1753
Jamie Madill04668672014-09-03 09:40:49 -04001754 // Note: shared and std140 layouts are always considered active
1755 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001756 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001757 if (!defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
1758 {
1759 return false;
1760 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001761 }
1762 }
1763
1764 return true;
1765}
1766
Geoff Lang48dcae72014-02-05 16:28:24 -05001767bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
1768 const std::vector<std::string> &transformFeedbackVaryingNames,
1769 GLenum transformFeedbackBufferMode,
Brandon Jones43a53e22014-08-28 16:23:22 -07001770 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
1771 const Caps &caps) const
Geoff Lang48dcae72014-02-05 16:28:24 -05001772{
1773 size_t totalComponents = 0;
Geoff Lang05881a02014-07-10 14:05:30 -04001774
Geoff Lang48dcae72014-02-05 16:28:24 -05001775 // Gather the linked varyings that are used for transform feedback, they should all exist.
1776 outTransformFeedbackLinkedVaryings->clear();
1777 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
1778 {
1779 bool found = false;
1780 for (size_t j = 0; j < linkedVaryings.size(); j++)
1781 {
1782 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
1783 {
1784 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
1785 {
1786 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
1787 {
1788 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
1789 return false;
1790 }
1791 }
1792
1793 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
1794 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang05881a02014-07-10 14:05:30 -04001795 componentCount > caps.maxTransformFeedbackSeparateComponents)
Geoff Lang48dcae72014-02-05 16:28:24 -05001796 {
1797 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
Geoff Lang05881a02014-07-10 14:05:30 -04001798 linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
Geoff Lang48dcae72014-02-05 16:28:24 -05001799 return false;
1800 }
1801
1802 totalComponents += componentCount;
1803
1804 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
1805 found = true;
1806 break;
1807 }
1808 }
1809
1810 // All transform feedback varyings are expected to exist since packVaryings checks for them.
1811 ASSERT(found);
1812 }
1813
Geoff Lang05881a02014-07-10 14:05:30 -04001814 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang48dcae72014-02-05 16:28:24 -05001815 {
1816 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
Geoff Lang05881a02014-07-10 14:05:30 -04001817 totalComponents, caps.maxTransformFeedbackInterleavedComponents);
Geoff Lang48dcae72014-02-05 16:28:24 -05001818 return false;
1819 }
1820
1821 return true;
1822}
1823
Jamie Madill42bcf322014-08-25 16:20:46 -04001824template <typename VarT>
1825void ProgramBinary::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
Jamie Madilla6f267f2014-08-27 11:44:15 -04001826 sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
1827 bool inRowMajorLayout)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001828{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001829 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001830 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001831 const VarT &field = fields[uniformIndex];
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001832 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001833
Jamie Madille04a5b72014-07-18 10:33:12 -04001834 if (field.isStruct())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001835 {
Jamie Madilla6f267f2014-08-27 11:44:15 -04001836 bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
1837
Jamie Madille04a5b72014-07-18 10:33:12 -04001838 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00001839 {
Jamie Madille04a5b72014-07-18 10:33:12 -04001840 encoder->enterAggregateType();
1841
1842 const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
Jamie Madilla6f267f2014-08-27 11:44:15 -04001843 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout);
Jamie Madille04a5b72014-07-18 10:33:12 -04001844
1845 encoder->exitAggregateType();
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00001846 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001847 }
1848 else
1849 {
Jamie Madilla6f267f2014-08-27 11:44:15 -04001850 bool isRowMajorMatrix = (IsMatrixType(field.type) && inRowMajorLayout);
1851
1852 sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
Jamie Madille04a5b72014-07-18 10:33:12 -04001853
Jamie Madill834e8b72014-04-11 13:33:58 -04001854 LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
Jamie Madille04a5b72014-07-18 10:33:12 -04001855 blockIndex, memberInfo);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001856
1857 // add to uniform list, but not index, since uniform block uniforms have no location
1858 blockUniformIndexes->push_back(mUniforms.size());
1859 mUniforms.push_back(newUniform);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00001860 }
1861 }
1862}
1863
Brandon Jones43a53e22014-08-28 16:23:22 -07001864bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001865{
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001866 const rx::ShaderD3D* shaderD3D = rx::ShaderD3D::makeShaderD3D(shader.getImplementation());
1867
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001868 // create uniform block entries if they do not exist
1869 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
1870 {
1871 std::vector<unsigned int> blockUniformIndexes;
1872 const unsigned int blockIndex = mUniformBlocks.size();
1873
1874 // define member uniforms
Jamie Madille04a5b72014-07-18 10:33:12 -04001875 sh::BlockLayoutEncoder *encoder = NULL;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001876
Jamie Madille04a5b72014-07-18 10:33:12 -04001877 if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
1878 {
1879 encoder = new sh::Std140BlockEncoder;
1880 }
1881 else
1882 {
1883 encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
1884 }
1885 ASSERT(encoder);
1886
Jamie Madilla6f267f2014-08-27 11:44:15 -04001887 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout);
Jamie Madille04a5b72014-07-18 10:33:12 -04001888
1889 size_t dataSize = encoder->getBlockSize();
Jamie Madillfc43d272014-07-11 17:02:02 -04001890
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001891 // create all the uniform blocks
1892 if (interfaceBlock.arraySize > 0)
1893 {
1894 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
1895 {
Jamie Madillfc43d272014-07-11 17:02:02 -04001896 UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001897 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
1898 mUniformBlocks.push_back(newUniformBlock);
1899 }
1900 }
1901 else
1902 {
Jamie Madillfc43d272014-07-11 17:02:02 -04001903 UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001904 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
1905 mUniformBlocks.push_back(newUniformBlock);
1906 }
1907 }
1908
Jamie Madill04668672014-09-03 09:40:49 -04001909 if (interfaceBlock.staticUse)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001910 {
Jamie Madill04668672014-09-03 09:40:49 -04001911 // Assign registers to the uniform blocks
1912 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
1913 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
1914 ASSERT(blockIndex != GL_INVALID_INDEX);
1915 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001916
Jamie Madill04668672014-09-03 09:40:49 -04001917 unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name);
1918
1919 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001920 {
Jamie Madill04668672014-09-03 09:40:49 -04001921 UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
1922 ASSERT(uniformBlock->name == interfaceBlock.name);
1923
Brandon Jones18bd4102014-09-22 14:21:44 -07001924 if (!mProgram->assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(),
1925 interfaceBlockRegister + uniformBlockElement, caps))
Jamie Madill04668672014-09-03 09:40:49 -04001926 {
1927 return false;
1928 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001929 }
1930 }
1931
1932 return true;
1933}
1934
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001935bool ProgramBinary::isValidated() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001936{
1937 return mValidated;
1938}
1939
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00001940void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001941{
1942 // Skip over inactive attributes
1943 unsigned int activeAttribute = 0;
1944 unsigned int attribute;
1945 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
1946 {
1947 if (mLinkedAttribute[attribute].name.empty())
1948 {
1949 continue;
1950 }
1951
1952 if (activeAttribute == index)
1953 {
1954 break;
1955 }
1956
1957 activeAttribute++;
1958 }
1959
1960 if (bufsize > 0)
1961 {
1962 const char *string = mLinkedAttribute[attribute].name.c_str();
1963
1964 strncpy(name, string, bufsize);
1965 name[bufsize - 1] = '\0';
1966
1967 if (length)
1968 {
1969 *length = strlen(name);
1970 }
1971 }
1972
1973 *size = 1; // Always a single 'type' instance
1974
1975 *type = mLinkedAttribute[attribute].type;
1976}
1977
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00001978GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001979{
1980 int count = 0;
1981
1982 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1983 {
1984 if (!mLinkedAttribute[attributeIndex].name.empty())
1985 {
1986 count++;
1987 }
1988 }
1989
1990 return count;
1991}
1992
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00001993GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001994{
1995 int maxLength = 0;
1996
1997 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
1998 {
1999 if (!mLinkedAttribute[attributeIndex].name.empty())
2000 {
2001 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2002 }
2003 }
2004
2005 return maxLength;
2006}
2007
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002008void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002009{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002010 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002011
2012 if (bufsize > 0)
2013 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002014 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002015
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002016 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002017 {
2018 string += "[0]";
2019 }
2020
2021 strncpy(name, string.c_str(), bufsize);
2022 name[bufsize - 1] = '\0';
2023
2024 if (length)
2025 {
2026 *length = strlen(name);
2027 }
2028 }
2029
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002030 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002031
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002032 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002033}
2034
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002035GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002036{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002037 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002038}
2039
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002040GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002041{
2042 int maxLength = 0;
2043
2044 unsigned int numUniforms = mUniforms.size();
2045 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2046 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002047 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002048 {
2049 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2050 if (mUniforms[uniformIndex]->isArray())
2051 {
2052 length += 3; // Counting in "[0]".
2053 }
2054 maxLength = std::max(length, maxLength);
2055 }
2056 }
2057
2058 return maxLength;
2059}
2060
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002061GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2062{
Jamie Madill834e8b72014-04-11 13:33:58 -04002063 const gl::LinkedUniform& uniform = *mUniforms[index];
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002064
2065 switch (pname)
2066 {
2067 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2068 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002069 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 +00002070 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002071
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002072 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2073 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2074 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2075 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002076
2077 default:
2078 UNREACHABLE();
2079 break;
2080 }
2081 return 0;
2082}
2083
Jamie Madill36398922014-05-20 14:51:53 -04002084bool ProgramBinary::isValidUniformLocation(GLint location) const
2085{
2086 ASSERT(rx::IsIntegerCastSafe<GLint>(mUniformIndex.size()));
2087 return (location >= 0 && location < static_cast<GLint>(mUniformIndex.size()));
2088}
2089
2090LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const
2091{
2092 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformIndex.size());
2093 return mUniforms[mUniformIndex[location].index];
2094}
2095
Jamie Madill66d43d22014-07-11 17:02:03 -04002096LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const
2097{
2098 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2099 {
2100 if (mUniforms[uniformIndex]->name == name)
2101 {
2102 return mUniforms[uniformIndex];
2103 }
2104 }
2105
2106 return NULL;
2107}
2108
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002109void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2110{
2111 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2112
2113 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2114
2115 if (bufSize > 0)
2116 {
2117 std::string string = uniformBlock.name;
2118
2119 if (uniformBlock.isArrayElement())
2120 {
Jamie Madill5f562732014-02-14 16:41:24 -05002121 string += ArrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002122 }
2123
2124 strncpy(uniformBlockName, string.c_str(), bufSize);
2125 uniformBlockName[bufSize - 1] = '\0';
2126
2127 if (length)
2128 {
2129 *length = strlen(uniformBlockName);
2130 }
2131 }
2132}
2133
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002134void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2135{
2136 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2137
2138 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2139
2140 switch (pname)
2141 {
2142 case GL_UNIFORM_BLOCK_DATA_SIZE:
2143 *params = static_cast<GLint>(uniformBlock.dataSize);
2144 break;
2145 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002146 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002147 break;
2148 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2149 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2150 break;
2151 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2152 {
2153 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2154 {
2155 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2156 }
2157 }
2158 break;
2159 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2160 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2161 break;
2162 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2163 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2164 break;
2165 default: UNREACHABLE();
2166 }
2167}
2168
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002169GLuint ProgramBinary::getActiveUniformBlockCount() const
2170{
2171 return mUniformBlocks.size();
2172}
2173
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002174GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2175{
2176 unsigned int maxLength = 0;
2177
2178 unsigned int numUniformBlocks = mUniformBlocks.size();
2179 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2180 {
2181 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2182 if (!uniformBlock.name.empty())
2183 {
2184 const unsigned int length = uniformBlock.name.length() + 1;
2185
2186 // Counting in "[0]".
2187 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2188
2189 maxLength = std::max(length + arrayLength, maxLength);
2190 }
2191 }
2192
2193 return maxLength;
2194}
2195
Brandon Jones43a53e22014-08-28 16:23:22 -07002196void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002197{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002198 applyUniforms();
Brandon Jones43a53e22014-08-28 16:23:22 -07002199 if (!validateSamplers(&infoLog, caps))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002200 {
2201 mValidated = false;
2202 }
2203 else
2204 {
2205 mValidated = true;
2206 }
2207}
2208
Brandon Jones43a53e22014-08-28 16:23:22 -07002209bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002210{
2211 // if any two active samplers in a program are of different types, but refer to the same
2212 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2213 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madilld4cfa572014-07-08 10:00:32 -04002214 updateSamplerMapping();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002215
Geoff Lang76b10c92014-09-05 16:28:14 -04002216 std::vector<GLenum> textureUnitTypes(caps.maxCombinedTextureImageUnits, GL_NONE);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002217
2218 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2219 {
2220 if (mSamplersPS[i].active)
2221 {
2222 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002223
Geoff Lang76b10c92014-09-05 16:28:14 -04002224 if (unit >= textureUnitTypes.size())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002225 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002226 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002227 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002228 infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002229 }
2230
2231 return false;
2232 }
2233
Geoff Lang76b10c92014-09-05 16:28:14 -04002234 if (textureUnitTypes[unit] != GL_NONE)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002235 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002236 if (mSamplersPS[i].textureType != textureUnitTypes[unit])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002237 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002238 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002239 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002240 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002241 }
2242
2243 return false;
2244 }
2245 }
2246 else
2247 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002248 textureUnitTypes[unit] = mSamplersPS[i].textureType;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002249 }
2250 }
2251 }
2252
2253 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2254 {
2255 if (mSamplersVS[i].active)
2256 {
2257 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002258
Geoff Lang76b10c92014-09-05 16:28:14 -04002259 if (unit >= textureUnitTypes.size())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002260 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002261 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002262 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002263 infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002264 }
2265
2266 return false;
2267 }
2268
Geoff Lang76b10c92014-09-05 16:28:14 -04002269 if (textureUnitTypes[unit] != GL_NONE)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002270 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002271 if (mSamplersVS[i].textureType != textureUnitTypes[unit])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002272 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002273 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002274 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002275 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002276 }
2277
2278 return false;
2279 }
2280 }
2281 else
2282 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002283 textureUnitTypes[unit] = mSamplersVS[i].textureType;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002284 }
2285 }
2286 }
2287
2288 return true;
2289}
2290
Geoff Lang76b10c92014-09-05 16:28:14 -04002291ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002292{
2293}
2294
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002295struct AttributeSorter
2296{
2297 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2298 : originalIndices(semanticIndices)
2299 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002300 }
2301
2302 bool operator()(int a, int b)
2303 {
Jamie Madill03181ab2013-12-18 12:56:06 -05002304 if (originalIndices[a] == -1) return false;
2305 if (originalIndices[b] == -1) return true;
2306 return (originalIndices[a] < originalIndices[b]);
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002307 }
2308
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002309 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2310};
2311
Al Patrick3f2daa82013-08-07 12:58:57 -07002312void ProgramBinary::initAttributesByLayout()
2313{
2314 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2315 {
2316 mAttributesByLayout[i] = i;
2317 }
2318
2319 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
2320}
2321
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002322void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2323{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002324 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2325
2326 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2327 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002328 oldTranslatedAttributes[i] = attributes[i];
2329 }
2330
2331 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2332 {
Al Patrick3f2daa82013-08-07 12:58:57 -07002333 int oldIndex = mAttributesByLayout[i];
2334 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002335 attributes[i] = oldTranslatedAttributes[oldIndex];
2336 }
2337}
2338
Geoff Lang04fb89a2014-06-09 15:05:36 -04002339void ProgramBinary::reset()
2340{
Geoff Lang76b10c92014-09-05 16:28:14 -04002341 mSamplersPS.clear();
2342 mSamplersVS.clear();
2343
Geoff Lang04fb89a2014-06-09 15:05:36 -04002344 mUsedVertexSamplerRange = 0;
2345 mUsedPixelSamplerRange = 0;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002346 mDirtySamplerMapping = true;
Geoff Lang04fb89a2014-06-09 15:05:36 -04002347
2348 SafeDeleteContainer(mUniforms);
2349 SafeDeleteContainer(mUniformBlocks);
2350 mUniformIndex.clear();
2351 mOutputVariables.clear();
Brandon Jonesc9610c52014-08-25 17:02:59 -07002352
2353 mProgram->reset();
Geoff Lang04fb89a2014-06-09 15:05:36 -04002354
2355 mValidated = false;
2356}
2357
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002358}