blob: 65d4d156e5dbd01da103a2d4c5429c531eb9521b [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"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000026#include "libGLESv2/renderer/Renderer.h"
Brandon Jonesf05cdee2014-08-27 15:24:07 -070027#include "libGLESv2/renderer/d3d/ShaderD3D.h"
Brandon Jonesc7a41042014-06-23 12:03:25 -070028#include "libGLESv2/renderer/d3d/VertexDataManager.h"
Nicolas Capense6050882013-07-08 10:43:10 -040029#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000030#include "libGLESv2/Buffer.h"
Jamie Madillc600c8c2014-05-16 11:22:21 -040031#include "common/blocklayout.h"
Jamie Madillc2141fb2013-08-30 13:21:08 -040032
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000033namespace gl
34{
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000035
Jamie Madill1b2a8f92014-05-14 13:09:39 -040036namespace
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000037{
38
Geoff Lang76b10c92014-09-05 16:28:14 -040039GLenum GetTextureType(GLenum samplerType)
Jamie Madill66d43d22014-07-11 17:02:03 -040040{
41 switch (samplerType)
42 {
43 case GL_SAMPLER_2D:
44 case GL_INT_SAMPLER_2D:
45 case GL_UNSIGNED_INT_SAMPLER_2D:
46 case GL_SAMPLER_2D_SHADOW:
Geoff Lang76b10c92014-09-05 16:28:14 -040047 return GL_TEXTURE_2D;
Jamie Madill66d43d22014-07-11 17:02:03 -040048 case GL_SAMPLER_3D:
49 case GL_INT_SAMPLER_3D:
50 case GL_UNSIGNED_INT_SAMPLER_3D:
Geoff Lang76b10c92014-09-05 16:28:14 -040051 return GL_TEXTURE_3D;
Jamie Madill66d43d22014-07-11 17:02:03 -040052 case GL_SAMPLER_CUBE:
53 case GL_SAMPLER_CUBE_SHADOW:
Geoff Lang76b10c92014-09-05 16:28:14 -040054 return GL_TEXTURE_CUBE_MAP;
Jamie Madill66d43d22014-07-11 17:02:03 -040055 case GL_INT_SAMPLER_CUBE:
56 case GL_UNSIGNED_INT_SAMPLER_CUBE:
Geoff Lang76b10c92014-09-05 16:28:14 -040057 return GL_TEXTURE_CUBE_MAP;
Jamie Madill66d43d22014-07-11 17:02:03 -040058 case GL_SAMPLER_2D_ARRAY:
59 case GL_INT_SAMPLER_2D_ARRAY:
60 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
61 case GL_SAMPLER_2D_ARRAY_SHADOW:
Geoff Lang76b10c92014-09-05 16:28:14 -040062 return GL_TEXTURE_2D_ARRAY;
Jamie Madill66d43d22014-07-11 17:02:03 -040063 default: UNREACHABLE();
64 }
65
Geoff Lang76b10c92014-09-05 16:28:14 -040066 return GL_TEXTURE_2D;
Jamie Madill66d43d22014-07-11 17:02:03 -040067}
68
Jamie Madill8ff21ae2014-02-04 16:04:05 -050069unsigned int ParseAndStripArrayIndex(std::string* name)
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000070{
71 unsigned int subscript = GL_INVALID_INDEX;
72
73 // Strip any trailing array operator and retrieve the subscript
74 size_t open = name->find_last_of('[');
75 size_t close = name->find_last_of(']');
76 if (open != std::string::npos && close == name->length() - 1)
77 {
78 subscript = atoi(name->substr(open + 1).c_str());
79 name->erase(open);
80 }
81
82 return subscript;
83}
84
Jamie Madill3f2e61d2014-09-05 10:38:05 -040085void GetDefaultInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
Jamie Madillc5a83002014-02-14 16:41:25 -050086{
Jamie Madill3b7e2052014-03-17 09:47:43 -040087 size_t layoutIndex = 0;
Jamie Madillc5a83002014-02-14 16:41:25 -050088 for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
89 {
Jamie Madill3b7e2052014-03-17 09:47:43 -040090 ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS);
91
Jamie Madillf2575982014-06-25 16:04:54 -040092 const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -050093
94 if (shaderAttr.type != GL_NONE)
95 {
Jamie Madillac0a2672014-04-11 13:33:56 -040096 GLenum transposedType = TransposeMatrixType(shaderAttr.type);
97
98 for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++)
Jamie Madill3b7e2052014-03-17 09:47:43 -040099 {
100 VertexFormat *defaultFormat = &inputLayout[layoutIndex];
101
Jamie Madillf2575982014-06-25 16:04:54 -0400102 defaultFormat->mType = VariableComponentType(transposedType);
Jamie Madill3b7e2052014-03-17 09:47:43 -0400103 defaultFormat->mNormalized = false;
104 defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
Jamie Madillac0a2672014-04-11 13:33:56 -0400105 defaultFormat->mComponents = VariableColumnCount(transposedType);
Jamie Madill3b7e2052014-03-17 09:47:43 -0400106 }
Jamie Madillc5a83002014-02-14 16:41:25 -0500107 }
108 }
109}
110
Jamie Madillf6be8d72014-09-05 10:38:07 -0400111std::vector<GLenum> GetDefaultOutputLayoutFromShader(const std::vector<rx::PixelShaderOutputVariable> &shaderOutputVars)
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400112{
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400113 std::vector<GLenum> defaultPixelOutput(1);
Jamie Madill3f2e61d2014-09-05 10:38:05 -0400114
115 ASSERT(!shaderOutputVars.empty());
116 defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex;
117
118 return defaultPixelOutput;
119}
120
Jamie Madilla6f267f2014-08-27 11:44:15 -0400121bool IsRowMajorLayout(const sh::InterfaceBlockField &var)
122{
123 return var.isRowMajorLayout;
124}
125
126bool IsRowMajorLayout(const sh::ShaderVariable &var)
127{
128 return false;
129}
130
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000131}
132
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400133VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000134 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135{
136}
137
Geoff Lang04fb89a2014-06-09 15:05:36 -0400138ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[],
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400139 const GLenum signature[],
Jamie Madillc5a83002014-02-14 16:41:25 -0500140 rx::ShaderExecutable *shaderExecutable)
141 : mShaderExecutable(shaderExecutable)
142{
143 for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
144 {
145 mInputs[attributeIndex] = inputLayout[attributeIndex];
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400146 mSignature[attributeIndex] = signature[attributeIndex];
Jamie Madillc5a83002014-02-14 16:41:25 -0500147 }
148}
149
Jamie Madill8b4f8f82014-03-26 14:01:58 -0400150ProgramBinary::VertexExecutable::~VertexExecutable()
151{
Geoff Lang04fb89a2014-06-09 15:05:36 -0400152 SafeDelete(mShaderExecutable);
Jamie Madill8b4f8f82014-03-26 14:01:58 -0400153}
154
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400155bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const
Jamie Madillc5a83002014-02-14 16:41:25 -0500156{
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400157 for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
Jamie Madillc5a83002014-02-14 16:41:25 -0500158 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400159 if (mSignature[attributeIndex] != signature[attributeIndex])
Jamie Madillc5a83002014-02-14 16:41:25 -0500160 {
161 return false;
162 }
163 }
164
165 return true;
166}
167
Geoff Lang04fb89a2014-06-09 15:05:36 -0400168ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable)
169 : mOutputSignature(outputSignature),
170 mShaderExecutable(shaderExecutable)
171{
172}
173
174ProgramBinary::PixelExecutable::~PixelExecutable()
175{
176 SafeDelete(mShaderExecutable);
177}
178
Geoff Lang48dcae72014-02-05 16:28:24 -0500179LinkedVarying::LinkedVarying()
180{
181}
182
183LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
184 unsigned int semanticIndex, unsigned int semanticIndexCount)
185 : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
186{
187}
188
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000189unsigned int ProgramBinary::mCurrentSerial = 1;
190
Brandon Jonesc9610c52014-08-25 17:02:59 -0700191ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500192 : RefCountObject(0),
Brandon Jonesc9610c52014-08-25 17:02:59 -0700193 mProgram(impl),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500194 mGeometryExecutable(NULL),
195 mUsedVertexSamplerRange(0),
196 mUsedPixelSamplerRange(0),
Jamie Madilld4cfa572014-07-08 10:00:32 -0400197 mDirtySamplerMapping(true),
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500198 mValidated(false),
199 mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000200{
Brandon Jonesc9610c52014-08-25 17:02:59 -0700201 ASSERT(impl);
202
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000203 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
204 {
205 mSemanticIndex[index] = -1;
206 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000207}
208
209ProgramBinary::~ProgramBinary()
210{
Geoff Lang04fb89a2014-06-09 15:05:36 -0400211 reset();
Brandon Jonesc9610c52014-08-25 17:02:59 -0700212 SafeDelete(mProgram);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000213}
214
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000215unsigned int ProgramBinary::getSerial() const
216{
217 return mSerial;
218}
219
220unsigned int ProgramBinary::issueSerial()
221{
222 return mCurrentSerial++;
223}
224
Geoff Lang04fb89a2014-06-09 15:05:36 -0400225rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000226{
Jamie Madillaef95de2014-09-05 10:12:41 -0400227 std::vector<GLenum> outputs;
228
229 const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender();
230
231 for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
Geoff Lang04fb89a2014-06-09 15:05:36 -0400232 {
Jamie Madillaef95de2014-09-05 10:12:41 -0400233 const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
234
235 if (colorbuffer)
Geoff Lang04fb89a2014-06-09 15:05:36 -0400236 {
Jamie Madillaef95de2014-09-05 10:12:41 -0400237 outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding());
Geoff Lang04fb89a2014-06-09 15:05:36 -0400238 }
239 else
240 {
Jamie Madillaef95de2014-09-05 10:12:41 -0400241 outputs.push_back(GL_NONE);
Geoff Lang04fb89a2014-06-09 15:05:36 -0400242 }
243 }
244
245 return getPixelExecutableForOutputLayout(outputs);
246}
247
248rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
249{
250 for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
251 {
252 if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
253 {
254 return mPixelExecutables[executableIndex]->shaderExecutable();
255 }
256 }
257
Geoff Lang04fb89a2014-06-09 15:05:36 -0400258 InfoLog tempInfoLog;
Brandon Jones22502d52014-08-29 16:58:36 -0700259 rx::ShaderExecutable *pixelExecutable = mProgram->getPixelExecutableForOutputLayout(tempInfoLog, outputSignature,
260 mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Geoff Lang04fb89a2014-06-09 15:05:36 -0400261
262 if (!pixelExecutable)
263 {
264 std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
265 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
266 ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
267 }
268 else
269 {
270 mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
271 }
272
273 return pixelExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000274}
275
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400276rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000277{
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400278 GLenum signature[MAX_VERTEX_ATTRIBS];
Brandon Jones44151a92014-09-10 11:32:25 -0700279 mProgram->getInputLayoutSignature(inputLayout, signature);
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400280
Jamie Madillc5a83002014-02-14 16:41:25 -0500281 for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
282 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -0400283 if (mVertexExecutables[executableIndex]->matchesSignature(signature))
Jamie Madillc5a83002014-02-14 16:41:25 -0500284 {
285 return mVertexExecutables[executableIndex]->shaderExecutable();
286 }
287 }
288
Jamie Madillc5a83002014-02-14 16:41:25 -0500289 InfoLog tempInfoLog;
Brandon Jones22502d52014-08-29 16:58:36 -0700290 rx::ShaderExecutable *vertexExecutable = mProgram->getVertexExecutableForInputLayout(tempInfoLog, inputLayout, mShaderAttributes,
291 mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -0500292
293 if (!vertexExecutable)
294 {
295 std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
296 tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
297 ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
298 }
299 else
300 {
Geoff Lang04fb89a2014-06-09 15:05:36 -0400301 mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
Jamie Madillc5a83002014-02-14 16:41:25 -0500302 }
303
304 return vertexExecutable;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000305}
306
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500307rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000308{
309 return mGeometryExecutable;
310}
311
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000312GLuint ProgramBinary::getAttributeLocation(const char *name)
313{
314 if (name)
315 {
316 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
317 {
318 if (mLinkedAttribute[index].name == std::string(name))
319 {
320 return index;
321 }
322 }
323 }
324
325 return -1;
326}
327
328int ProgramBinary::getSemanticIndex(int attributeIndex)
329{
330 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400331
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000332 return mSemanticIndex[attributeIndex];
333}
334
335// Returns one more than the highest sampler index used.
336GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
337{
338 switch (type)
339 {
340 case SAMPLER_PIXEL:
341 return mUsedPixelSamplerRange;
342 case SAMPLER_VERTEX:
343 return mUsedVertexSamplerRange;
344 default:
345 UNREACHABLE();
346 return 0;
347 }
348}
349
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000350bool ProgramBinary::usesPointSize() const
351{
Brandon Jones44151a92014-09-10 11:32:25 -0700352 return mProgram->usesPointSize();
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000353}
354
Brandon Jones43a53e22014-08-28 16:23:22 -0700355GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000356{
357 GLint logicalTextureUnit = -1;
358
359 switch (type)
360 {
361 case SAMPLER_PIXEL:
Geoff Lang76b10c92014-09-05 16:28:14 -0400362 ASSERT(samplerIndex < caps.maxTextureImageUnits);
363 if (samplerIndex < mSamplersPS.size() && mSamplersPS[samplerIndex].active)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000364 {
365 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
366 }
367 break;
368 case SAMPLER_VERTEX:
Geoff Lang76b10c92014-09-05 16:28:14 -0400369 ASSERT(samplerIndex < caps.maxVertexTextureImageUnits);
370 if (samplerIndex < mSamplersVS.size() && mSamplersVS[samplerIndex].active)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000371 {
372 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
373 }
374 break;
375 default: UNREACHABLE();
376 }
377
Brandon Jones43a53e22014-08-28 16:23:22 -0700378 if (logicalTextureUnit >= 0 && logicalTextureUnit < static_cast<GLint>(caps.maxCombinedTextureImageUnits))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000379 {
380 return logicalTextureUnit;
381 }
382
383 return -1;
384}
385
386// Returns the texture type for a given Direct3D 9 sampler type and
387// index (0-15 for the pixel shader and 0-3 for the vertex shader).
Geoff Lang76b10c92014-09-05 16:28:14 -0400388GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000389{
390 switch (type)
391 {
392 case SAMPLER_PIXEL:
Geoff Lang76b10c92014-09-05 16:28:14 -0400393 ASSERT(samplerIndex < mSamplersPS.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000394 ASSERT(mSamplersPS[samplerIndex].active);
395 return mSamplersPS[samplerIndex].textureType;
396 case SAMPLER_VERTEX:
Geoff Lang76b10c92014-09-05 16:28:14 -0400397 ASSERT(samplerIndex < mSamplersVS.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000398 ASSERT(mSamplersVS[samplerIndex].active);
399 return mSamplersVS[samplerIndex].textureType;
400 default: UNREACHABLE();
401 }
402
Geoff Lang76b10c92014-09-05 16:28:14 -0400403 return GL_TEXTURE_2D;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000404}
405
406GLint ProgramBinary::getUniformLocation(std::string name)
407{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500408 unsigned int subscript = ParseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000409
410 unsigned int numUniforms = mUniformIndex.size();
411 for (unsigned int location = 0; location < numUniforms; location++)
412 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000413 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000414 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000415 const int index = mUniformIndex[location].index;
416 const bool isArray = mUniforms[index]->isArray();
417
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400418 if ((isArray && mUniformIndex[location].element == subscript) ||
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000419 (subscript == GL_INVALID_INDEX))
420 {
421 return location;
422 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000423 }
424 }
425
426 return -1;
427}
428
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000429GLuint ProgramBinary::getUniformIndex(std::string name)
430{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500431 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000432
433 // The app is not allowed to specify array indices other than 0 for arrays of basic types
434 if (subscript != 0 && subscript != GL_INVALID_INDEX)
435 {
436 return GL_INVALID_INDEX;
437 }
438
439 unsigned int numUniforms = mUniforms.size();
440 for (unsigned int index = 0; index < numUniforms; index++)
441 {
442 if (mUniforms[index]->name == name)
443 {
444 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
445 {
446 return index;
447 }
448 }
449 }
450
451 return GL_INVALID_INDEX;
452}
453
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000454GLuint ProgramBinary::getUniformBlockIndex(std::string name)
455{
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500456 unsigned int subscript = ParseAndStripArrayIndex(&name);
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000457
458 unsigned int numUniformBlocks = mUniformBlocks.size();
459 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
460 {
461 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
462 if (uniformBlock.name == name)
463 {
464 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
465 if (subscript == uniformBlock.elementIndex || arrayElementZero)
466 {
467 return blockIndex;
468 }
469 }
470 }
471
472 return GL_INVALID_INDEX;
473}
474
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000475UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
476{
477 ASSERT(blockIndex < mUniformBlocks.size());
478 return mUniformBlocks[blockIndex];
479}
480
Jamie Madilld1e78c92013-06-20 11:55:50 -0400481GLint ProgramBinary::getFragDataLocation(const char *name) const
482{
483 std::string baseName(name);
484 unsigned int arrayIndex;
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500485 arrayIndex = ParseAndStripArrayIndex(&baseName);
Jamie Madilld1e78c92013-06-20 11:55:50 -0400486
487 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
488 {
489 const VariableLocation &outputVariable = locationIt->second;
490
491 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
492 {
493 return static_cast<GLint>(locationIt->first);
494 }
495 }
496
497 return -1;
498}
499
Geoff Lang48dcae72014-02-05 16:28:24 -0500500size_t ProgramBinary::getTransformFeedbackVaryingCount() const
501{
502 return mTransformFeedbackLinkedVaryings.size();
503}
504
505const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
506{
507 return mTransformFeedbackLinkedVaryings[idx];
508}
509
510GLenum ProgramBinary::getTransformFeedbackBufferMode() const
511{
512 return mTransformFeedbackBufferMode;
513}
514
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000515template <typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400516static inline void SetIfDirty(T *dest, const T& source, bool *dirtyFlag)
517{
518 ASSERT(dest != NULL);
519 ASSERT(dirtyFlag != NULL);
520
521 *dirtyFlag = *dirtyFlag || (memcmp(dest, &source, sizeof(T)) != 0);
522 *dest = source;
523}
524
525template <typename T>
Jamie Madill36398922014-05-20 14:51:53 -0400526void ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000527{
Jamie Madillf2575982014-06-25 16:04:54 -0400528 const int components = VariableComponentCount(targetUniformType);
529 const GLenum targetBoolType = VariableBoolVectorType(targetUniformType);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000530
Jamie Madill36398922014-05-20 14:51:53 -0400531 LinkedUniform *targetUniform = getUniformByLocation(location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000532
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000533 int elementCount = targetUniform->elementCount();
534
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000535 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
536
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000537 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000538 {
Geoff Langbe4fdb32014-09-16 14:11:40 -0400539 T *target = reinterpret_cast<T*>(targetUniform->data) + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000540
541 for (int i = 0; i < count; i++)
542 {
Geoff Lang61f54182014-09-16 14:10:02 -0400543 T *dest = target + (i * 4);
544 const T *source = v + (i * components);
545
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000546 for (int c = 0; c < components; c++)
547 {
Geoff Lang61f54182014-09-16 14:10:02 -0400548 SetIfDirty(dest + c, source[c], &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000549 }
550 for (int c = components; c < 4; c++)
551 {
Geoff Lang61f54182014-09-16 14:10:02 -0400552 SetIfDirty(dest + c, T(0), &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000553 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000554 }
555 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000556 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000557 {
Geoff Langbe4fdb32014-09-16 14:11:40 -0400558 GLint *boolParams = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000559
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000560 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000561 {
Geoff Lang61f54182014-09-16 14:10:02 -0400562 GLint *dest = boolParams + (i * 4);
563 const T *source = v + (i * components);
564
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000565 for (int c = 0; c < components; c++)
566 {
Geoff Lang61f54182014-09-16 14:10:02 -0400567 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 +0000568 }
569 for (int c = components; c < 4; c++)
570 {
Geoff Lang61f54182014-09-16 14:10:02 -0400571 SetIfDirty(dest + c, GL_FALSE, &targetUniform->dirty);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000572 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000573 }
574 }
Geoff Langbe4fdb32014-09-16 14:11:40 -0400575 else if (IsSampler(targetUniform->type))
576 {
577 ASSERT(targetUniformType == GL_INT);
578
579 GLint *target = reinterpret_cast<GLint*>(targetUniform->data) + mUniformIndex[location].element * 4;
580
581 bool wasDirty = targetUniform->dirty;
582
583 for (int i = 0; i < count; i++)
584 {
585 GLint *dest = target + (i * 4);
586 const GLint *source = reinterpret_cast<const GLint*>(v) + (i * components);
587
588 SetIfDirty(dest + 0, source[0], &targetUniform->dirty);
589 SetIfDirty(dest + 1, 0, &targetUniform->dirty);
590 SetIfDirty(dest + 2, 0, &targetUniform->dirty);
591 SetIfDirty(dest + 3, 0, &targetUniform->dirty);
592 }
593
594 if (!wasDirty && targetUniform->dirty)
595 {
596 mDirtySamplerMapping = true;
597 }
598 }
Jamie Madill36398922014-05-20 14:51:53 -0400599 else UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000600}
601
Jamie Madill36398922014-05-20 14:51:53 -0400602void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000603{
Jamie Madill36398922014-05-20 14:51:53 -0400604 setUniform(location, count, v, GL_FLOAT);
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000605}
606
Jamie Madill36398922014-05-20 14:51:53 -0400607void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000608{
Jamie Madill36398922014-05-20 14:51:53 -0400609 setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000610}
611
Jamie Madill36398922014-05-20 14:51:53 -0400612void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613{
Jamie Madill36398922014-05-20 14:51:53 -0400614 setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000615}
616
Jamie Madill36398922014-05-20 14:51:53 -0400617void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000618{
Jamie Madill36398922014-05-20 14:51:53 -0400619 setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000620}
621
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000622template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400623bool transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000624{
Geoff Langae1990c2014-05-12 16:57:14 -0400625 bool dirty = false;
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000626 int copyWidth = std::min(targetHeight, srcWidth);
627 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628
629 for (int x = 0; x < copyWidth; x++)
630 {
631 for (int y = 0; y < copyHeight; y++)
632 {
Geoff Langae1990c2014-05-12 16:57:14 -0400633 SetIfDirty(target + (x * targetWidth + y), static_cast<T>(value[y * srcWidth + x]), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000634 }
635 }
636 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000637 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000638 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000639 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000640 {
Geoff Langae1990c2014-05-12 16:57:14 -0400641 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000642 }
643 }
644 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000645 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000646 {
647 for (int x = 0; x < targetWidth; x++)
648 {
Geoff Langae1990c2014-05-12 16:57:14 -0400649 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000650 }
651 }
Geoff Langae1990c2014-05-12 16:57:14 -0400652
653 return dirty;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000654}
655
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000656template<typename T>
Geoff Langae1990c2014-05-12 16:57:14 -0400657bool 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 +0000658{
Geoff Langae1990c2014-05-12 16:57:14 -0400659 bool dirty = false;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000660 int copyWidth = std::min(targetWidth, srcWidth);
661 int copyHeight = std::min(targetHeight, srcHeight);
662
663 for (int y = 0; y < copyHeight; y++)
664 {
665 for (int x = 0; x < copyWidth; x++)
666 {
Geoff Langae1990c2014-05-12 16:57:14 -0400667 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(value[y * srcWidth + x]), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000668 }
669 }
670 // clear unfilled right side
671 for (int y = 0; y < copyHeight; y++)
672 {
673 for (int x = copyWidth; x < targetWidth; x++)
674 {
Geoff Langae1990c2014-05-12 16:57:14 -0400675 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000676 }
677 }
678 // clear unfilled bottom.
679 for (int y = copyHeight; y < targetHeight; y++)
680 {
681 for (int x = 0; x < targetWidth; x++)
682 {
Geoff Langae1990c2014-05-12 16:57:14 -0400683 SetIfDirty(target + (y * targetWidth + x), static_cast<T>(0), &dirty);
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000684 }
685 }
Geoff Langae1990c2014-05-12 16:57:14 -0400686
687 return dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000688}
689
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000690template <int cols, int rows>
Jamie Madill36398922014-05-20 14:51:53 -0400691void ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692{
Jamie Madill36398922014-05-20 14:51:53 -0400693 LinkedUniform *targetUniform = getUniformByLocation(location);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000694
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000695 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000696
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000697 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000698 const unsigned int targetMatrixStride = (4 * rows);
699 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000700
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000701 for (int i = 0; i < count; i++)
702 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000703 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
704 if (transpose == GL_FALSE)
705 {
Geoff Langae1990c2014-05-12 16:57:14 -0400706 targetUniform->dirty = transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000707 }
708 else
709 {
Geoff Langae1990c2014-05-12 16:57:14 -0400710 targetUniform->dirty = expandMatrix<GLfloat>(target, value, 4, rows, cols, rows) || targetUniform->dirty;
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000711 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000712 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000713 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000714 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000715}
716
Jamie Madill36398922014-05-20 14:51:53 -0400717void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000718{
Jamie Madill36398922014-05-20 14:51:53 -0400719 setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000720}
721
Jamie Madill36398922014-05-20 14:51:53 -0400722void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000723{
Jamie Madill36398922014-05-20 14:51:53 -0400724 setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000725}
726
Jamie Madill36398922014-05-20 14:51:53 -0400727void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000728{
Jamie Madill36398922014-05-20 14:51:53 -0400729 setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000730}
731
Jamie Madill36398922014-05-20 14:51:53 -0400732void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000733{
Jamie Madill36398922014-05-20 14:51:53 -0400734 setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000735}
736
Jamie Madill36398922014-05-20 14:51:53 -0400737void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000738{
Jamie Madill36398922014-05-20 14:51:53 -0400739 setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000740}
741
Jamie Madill36398922014-05-20 14:51:53 -0400742void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000743{
Jamie Madill36398922014-05-20 14:51:53 -0400744 setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000745}
746
Jamie Madill36398922014-05-20 14:51:53 -0400747void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000748{
Jamie Madill36398922014-05-20 14:51:53 -0400749 setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000750}
751
Jamie Madill36398922014-05-20 14:51:53 -0400752void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000753{
Jamie Madill36398922014-05-20 14:51:53 -0400754 setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000755}
756
Jamie Madill36398922014-05-20 14:51:53 -0400757void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000758{
Jamie Madill36398922014-05-20 14:51:53 -0400759 setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000760}
761
Jamie Madill36398922014-05-20 14:51:53 -0400762void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000763{
Geoff Langbe4fdb32014-09-16 14:11:40 -0400764 setUniform(location, count, v, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000765}
766
Jamie Madill36398922014-05-20 14:51:53 -0400767void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000768{
Jamie Madill36398922014-05-20 14:51:53 -0400769 setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000770}
771
Jamie Madill36398922014-05-20 14:51:53 -0400772void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000773{
Jamie Madill36398922014-05-20 14:51:53 -0400774 setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000775}
776
Jamie Madill36398922014-05-20 14:51:53 -0400777void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000778{
Jamie Madill36398922014-05-20 14:51:53 -0400779 setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000780}
781
Jamie Madill36398922014-05-20 14:51:53 -0400782void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000783{
Jamie Madill36398922014-05-20 14:51:53 -0400784 setUniform(location, count, v, GL_UNSIGNED_INT);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000785}
786
Jamie Madill36398922014-05-20 14:51:53 -0400787void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000788{
Jamie Madill36398922014-05-20 14:51:53 -0400789 setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000790}
791
Jamie Madill36398922014-05-20 14:51:53 -0400792void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000793{
Jamie Madill36398922014-05-20 14:51:53 -0400794 setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000795}
796
Jamie Madill36398922014-05-20 14:51:53 -0400797void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000798{
Jamie Madill36398922014-05-20 14:51:53 -0400799 setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000800}
801
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000802template <typename T>
Jamie Madill99a1e982014-08-25 15:47:54 -0400803void ProgramBinary::getUniformv(GLint location, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000804{
Jamie Madill834e8b72014-04-11 13:33:58 -0400805 LinkedUniform *targetUniform = mUniforms[mUniformIndex[location].index];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000806
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000807 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000808 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000809 const int rows = VariableRowCount(targetUniform->type);
810 const int cols = VariableColumnCount(targetUniform->type);
Jamie Madillf07558a2013-10-31 11:16:22 -0400811 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 +0000812 }
Jamie Madillf2575982014-06-25 16:04:54 -0400813 else if (uniformType == VariableComponentType(targetUniform->type))
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000814 {
Jamie Madillf2575982014-06-25 16:04:54 -0400815 unsigned int size = VariableComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000816 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
817 size * sizeof(T));
818 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000819 else
820 {
Jamie Madillf2575982014-06-25 16:04:54 -0400821 unsigned int size = VariableComponentCount(targetUniform->type);
822 switch (VariableComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000823 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000824 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000825 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000826 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000827
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000828 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000829 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000830 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000831 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000832 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000833 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000834
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000835 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000836 {
837 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
838
839 for (unsigned int i = 0; i < size; i++)
840 {
841 params[i] = static_cast<T>(floatParams[i]);
842 }
843 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000844 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000845
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000846 case GL_INT:
847 {
848 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
849
850 for (unsigned int i = 0; i < size; i++)
851 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000852 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000853 }
854 }
855 break;
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400856
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000857 case GL_UNSIGNED_INT:
858 {
859 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000860
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000861 for (unsigned int i = 0; i < size; i++)
862 {
863 params[i] = static_cast<T>(uintParams[i]);
864 }
865 }
866 break;
Jamie Madill1b2a8f92014-05-14 13:09:39 -0400867
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000868 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000869 }
870 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000871}
872
Jamie Madill99a1e982014-08-25 15:47:54 -0400873void ProgramBinary::getUniformfv(GLint location, GLfloat *params)
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000874{
Jamie Madill99a1e982014-08-25 15:47:54 -0400875 getUniformv(location, params, GL_FLOAT);
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000876}
877
Jamie Madill99a1e982014-08-25 15:47:54 -0400878void ProgramBinary::getUniformiv(GLint location, GLint *params)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000879{
Jamie Madill99a1e982014-08-25 15:47:54 -0400880 getUniformv(location, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000881}
882
Jamie Madill99a1e982014-08-25 15:47:54 -0400883void ProgramBinary::getUniformuiv(GLint location, GLuint *params)
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000884{
Jamie Madill99a1e982014-08-25 15:47:54 -0400885 getUniformv(location, params, GL_UNSIGNED_INT);
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000886}
887
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000888void ProgramBinary::dirtyAllUniforms()
889{
890 unsigned int numUniforms = mUniforms.size();
891 for (unsigned int index = 0; index < numUniforms; index++)
892 {
893 mUniforms[index]->dirty = true;
894 }
895}
896
Jamie Madilld4cfa572014-07-08 10:00:32 -0400897void ProgramBinary::updateSamplerMapping()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000898{
Jamie Madilld4cfa572014-07-08 10:00:32 -0400899 if (!mDirtySamplerMapping)
900 {
901 return;
902 }
903
904 mDirtySamplerMapping = false;
905
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000906 // Retrieve sampler uniform values
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500907 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000908 {
Jamie Madill834e8b72014-04-11 13:33:58 -0400909 LinkedUniform *targetUniform = mUniforms[uniformIndex];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000910
911 if (targetUniform->dirty)
912 {
Nicolas Capense6050882013-07-08 10:43:10 -0400913 if (IsSampler(targetUniform->type))
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000914 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000915 int count = targetUniform->elementCount();
Jamie Madilld4cfa572014-07-08 10:00:32 -0400916 GLint (*v)[4] = reinterpret_cast<GLint(*)[4]>(targetUniform->data);
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000917
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000918 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000919 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000920 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000921
922 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000923 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000924 unsigned int samplerIndex = firstIndex + i;
925
Geoff Lang76b10c92014-09-05 16:28:14 -0400926 if (samplerIndex < mSamplersPS.size())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000927 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000928 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000929 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000930 }
931 }
932 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000933
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000934 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000935 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000936 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000937
938 for (int i = 0; i < count; i++)
939 {
940 unsigned int samplerIndex = firstIndex + i;
941
Geoff Lang76b10c92014-09-05 16:28:14 -0400942 if (samplerIndex < mSamplersVS.size())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000943 {
944 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000945 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000946 }
947 }
948 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000949 }
950 }
951 }
Jamie Madilld4cfa572014-07-08 10:00:32 -0400952}
953
954// Applies all the uniforms set for this program object to the renderer
Geoff Langc77e8c32014-09-08 16:28:24 -0400955Error ProgramBinary::applyUniforms()
Jamie Madilld4cfa572014-07-08 10:00:32 -0400956{
957 updateSamplerMapping();
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000958
Geoff Langc77e8c32014-09-08 16:28:24 -0400959 Error error = mProgram->getRenderer()->applyUniforms(*this);
960 if (error.isError())
961 {
962 return error;
963 }
Jamie Madill8ff21ae2014-02-04 16:04:05 -0500964
965 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
966 {
967 mUniforms[uniformIndex]->dirty = false;
968 }
Geoff Langc77e8c32014-09-08 16:28:24 -0400969
970 return gl::Error(GL_NO_ERROR);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000971}
972
Geoff Langc77e8c32014-09-08 16:28:24 -0400973Error ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000974{
975 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
976 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
977
Brandon Jonesc9610c52014-08-25 17:02:59 -0700978 const unsigned int reservedBuffersInVS = mProgram->getRenderer()->getReservedVertexUniformBuffers();
979 const unsigned int reservedBuffersInFS = mProgram->getRenderer()->getReservedFragmentUniformBuffers();
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000980
981 ASSERT(boundBuffers.size() == mUniformBlocks.size());
982
983 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
984 {
Jamie Madillf2575982014-06-25 16:04:54 -0400985 UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000986 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
987
988 ASSERT(uniformBlock && uniformBuffer);
989
Brandon Jonesd38f9262014-06-18 16:26:45 -0700990 if (uniformBuffer->getSize() < uniformBlock->dataSize)
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000991 {
992 // undefined behaviour
Geoff Langc77e8c32014-09-08 16:28:24 -0400993 return gl::Error(GL_INVALID_OPERATION, "It is undefined behaviour to use a uniform buffer that is too small.");
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000994 }
995
Jamie Madill04668672014-09-03 09:40:49 -0400996 // Unnecessary to apply an unreferenced standard or shared UBO
997 if (!uniformBlock->isReferencedByVertexShader() && !uniformBlock->isReferencedByFragmentShader())
998 {
999 continue;
1000 }
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +00001001
1002 if (uniformBlock->isReferencedByVertexShader())
1003 {
1004 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
1005 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
Brandon Jones43a53e22014-08-28 16:23:22 -07001006 ASSERT(registerIndex < caps.maxVertexUniformBlocks);
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +00001007 vertexUniformBuffers[registerIndex] = uniformBuffer;
1008 }
1009
1010 if (uniformBlock->isReferencedByFragmentShader())
1011 {
1012 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
1013 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
Brandon Jones43a53e22014-08-28 16:23:22 -07001014 ASSERT(registerIndex < caps.maxFragmentUniformBlocks);
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +00001015 fragmentUniformBuffers[registerIndex] = uniformBuffer;
1016 }
1017 }
1018
Brandon Jonesc9610c52014-08-25 17:02:59 -07001019 return mProgram->getRenderer()->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +00001020}
1021
Brandon Jones71620962014-08-20 14:04:59 -07001022bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001023{
Jamie Madilld15250e2014-09-03 09:40:44 -04001024 std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
1025 std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
Jamie Madill5f562732014-02-14 16:41:24 -05001026
1027 for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001028 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001029 PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001030 bool matched = false;
1031
Jamie Madill54ad4f82014-09-03 09:40:46 -04001032 // Built-in varyings obey special rules
1033 if (input->isBuiltIn())
1034 {
1035 continue;
1036 }
1037
Jamie Madill5f562732014-02-14 16:41:24 -05001038 for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001039 {
Jamie Madillff0d2ba2014-05-14 13:49:10 -04001040 PackedVarying *output = &vertexVaryings[vertVaryingIndex];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001041 if (output->name == input->name)
1042 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001043 if (!linkValidateVaryings(infoLog, output->name, *input, *output))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001044 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001045 return false;
1046 }
1047
Jamie Madill139b9092013-08-30 13:21:06 -04001048 output->registerIndex = input->registerIndex;
Austin Kinrossaf875522014-08-25 21:06:07 -07001049 output->columnIndex = input->columnIndex;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001050
1051 matched = true;
1052 break;
1053 }
1054 }
1055
Jamie Madill54ad4f82014-09-03 09:40:46 -04001056 // We permit unmatched, unreferenced varyings
1057 if (!matched && input->staticUse)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001058 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001059 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001060 return false;
1061 }
1062 }
1063
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001064 return true;
1065}
1066
Geoff Lang900013c2014-07-07 11:32:19 -04001067bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001068{
Jamie Madill9c4b24a2014-06-12 13:41:17 -04001069#ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
1070 return false;
1071#else
Brandon Jones22502d52014-08-29 16:58:36 -07001072 ASSERT(binaryFormat == mProgram->getBinaryFormat());
Geoff Lang900013c2014-07-07 11:32:19 -04001073
Geoff Lang04fb89a2014-06-09 15:05:36 -04001074 reset();
1075
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001076 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001077
Brandon Jones22502d52014-08-29 16:58:36 -07001078 GLenum format = stream.readInt<GLenum>();
1079 if (format != mProgram->getBinaryFormat())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001080 {
1081 infoLog.append("Invalid program binary format.");
1082 return false;
1083 }
1084
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001085 int majorVersion = stream.readInt<int>();
1086 int minorVersion = stream.readInt<int>();
Jamie Madill0aa84f62014-02-13 13:17:23 -05001087 if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
Jamie Madill049108d2013-11-19 10:41:49 -05001088 {
1089 infoLog.append("Invalid program binary version.");
1090 return false;
1091 }
1092
Jamie Madill0aa84f62014-02-13 13:17:23 -05001093 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001094 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
Jamie Madill0aa84f62014-02-13 13:17:23 -05001095 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001096 {
1097 infoLog.append("Invalid program binary version.");
1098 return false;
1099 }
1100
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001101 int compileFlags = stream.readInt<int>();
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001102 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1103 {
1104 infoLog.append("Mismatched compilation flags.");
1105 return false;
1106 }
1107
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001108 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1109 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001110 stream.readInt(&mLinkedAttribute[i].type);
1111 stream.readString(&mLinkedAttribute[i].name);
1112 stream.readInt(&mShaderAttributes[i].type);
1113 stream.readString(&mShaderAttributes[i].name);
1114 stream.readInt(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001115 }
1116
Al Patrick3f2daa82013-08-07 12:58:57 -07001117 initAttributesByLayout();
1118
Geoff Lang76b10c92014-09-05 16:28:14 -04001119 const unsigned int psSamplerCount = stream.readInt<unsigned int>();
1120 for (unsigned int i = 0; i < psSamplerCount; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001121 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001122 Sampler sampler;
1123 stream.readBool(&sampler.active);
1124 stream.readInt(&sampler.logicalTextureUnit);
1125 stream.readInt(&sampler.textureType);
1126 mSamplersPS.push_back(sampler);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001127 }
Geoff Lang76b10c92014-09-05 16:28:14 -04001128 const unsigned int vsSamplerCount = stream.readInt<unsigned int>();
1129 for (unsigned int i = 0; i < vsSamplerCount; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001130 {
Geoff Lang76b10c92014-09-05 16:28:14 -04001131 Sampler sampler;
1132 stream.readBool(&sampler.active);
1133 stream.readInt(&sampler.logicalTextureUnit);
1134 stream.readInt(&sampler.textureType);
1135 mSamplersVS.push_back(sampler);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001136 }
1137
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001138 stream.readInt(&mUsedVertexSamplerRange);
1139 stream.readInt(&mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001140
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001141 const unsigned int uniformCount = stream.readInt<unsigned int>();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001142 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001143 {
1144 infoLog.append("Invalid program binary.");
1145 return false;
1146 }
1147
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001148 mUniforms.resize(uniformCount);
1149 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001150 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001151 GLenum type = stream.readInt<GLenum>();
1152 GLenum precision = stream.readInt<GLenum>();
1153 std::string name = stream.readString();
1154 unsigned int arraySize = stream.readInt<unsigned int>();
1155 int blockIndex = stream.readInt<int>();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001156
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001157 int offset = stream.readInt<int>();
1158 int arrayStride = stream.readInt<int>();
1159 int matrixStride = stream.readInt<int>();
1160 bool isRowMajorMatrix = stream.readBool();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001161
Jamie Madillf2575982014-06-25 16:04:54 -04001162 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001163
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001164 LinkedUniform *uniform = new LinkedUniform(type, precision, name, arraySize, blockIndex, blockInfo);
1165
1166 stream.readInt(&uniform->psRegisterIndex);
1167 stream.readInt(&uniform->vsRegisterIndex);
1168 stream.readInt(&uniform->registerCount);
1169 stream.readInt(&uniform->registerElement);
1170
1171 mUniforms[uniformIndex] = uniform;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001172 }
1173
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001174 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001175 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001176 {
1177 infoLog.append("Invalid program binary.");
1178 return false;
1179 }
1180
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001181 mUniformBlocks.resize(uniformBlockCount);
1182 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001183 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001184 std::string name = stream.readString();
1185 unsigned int elementIndex = stream.readInt<unsigned int>();
1186 unsigned int dataSize = stream.readInt<unsigned int>();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001187
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001188 UniformBlock *uniformBlock = new UniformBlock(name, elementIndex, dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001189
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001190 stream.readInt(&uniformBlock->psRegisterIndex);
1191 stream.readInt(&uniformBlock->vsRegisterIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001192
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001193 unsigned int numMembers = stream.readInt<unsigned int>();
1194 uniformBlock->memberUniformIndexes.resize(numMembers);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001195 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1196 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001197 stream.readInt(&uniformBlock->memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001198 }
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001199
1200 mUniformBlocks[uniformBlockIndex] = uniformBlock;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001201 }
1202
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001203 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001204 if (stream.error())
1205 {
1206 infoLog.append("Invalid program binary.");
1207 return false;
1208 }
1209
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001210 mUniformIndex.resize(uniformIndexCount);
1211 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001212 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001213 stream.readString(&mUniformIndex[uniformIndexIndex].name);
1214 stream.readInt(&mUniformIndex[uniformIndexIndex].element);
1215 stream.readInt(&mUniformIndex[uniformIndexIndex].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001216 }
1217
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001218 stream.readInt(&mTransformFeedbackBufferMode);
1219 const unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
1220 mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
1221 for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
Geoff Lang48dcae72014-02-05 16:28:24 -05001222 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001223 LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex];
Geoff Lang48dcae72014-02-05 16:28:24 -05001224
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001225 stream.readString(&varying.name);
1226 stream.readInt(&varying.type);
1227 stream.readInt(&varying.size);
1228 stream.readString(&varying.semanticName);
1229 stream.readInt(&varying.semanticIndex);
1230 stream.readInt(&varying.semanticIndexCount);
Geoff Lang48dcae72014-02-05 16:28:24 -05001231 }
1232
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001233 const unsigned int vertexShaderCount = stream.readInt<unsigned int>();
Jamie Madillc5a83002014-02-14 16:41:25 -05001234 for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
1235 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001236 VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
Jamie Madillc5a83002014-02-14 16:41:25 -05001237
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001238 for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++)
Jamie Madillc5a83002014-02-14 16:41:25 -05001239 {
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001240 VertexFormat *vertexInput = &inputLayout[inputIndex];
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001241 stream.readInt(&vertexInput->mType);
1242 stream.readInt(&vertexInput->mNormalized);
1243 stream.readInt(&vertexInput->mComponents);
1244 stream.readBool(&vertexInput->mPureInteger);
Jamie Madillc5a83002014-02-14 16:41:25 -05001245 }
1246
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001247 unsigned int vertexShaderSize = stream.readInt<unsigned int>();
Geoff Lang04fb89a2014-06-09 15:05:36 -04001248 const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
Brandon Jonesc9610c52014-08-25 17:02:59 -07001249 rx::ShaderExecutable *shaderExecutable = mProgram->getRenderer()->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
Geoff Lang48dcae72014-02-05 16:28:24 -05001250 vertexShaderSize, rx::SHADER_VERTEX,
1251 mTransformFeedbackLinkedVaryings,
1252 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
Jamie Madillc5a83002014-02-14 16:41:25 -05001253 if (!shaderExecutable)
1254 {
1255 infoLog.append("Could not create vertex shader.");
1256 return false;
1257 }
1258
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001259 // generated converted input layout
1260 GLenum signature[MAX_VERTEX_ATTRIBS];
Brandon Jones44151a92014-09-10 11:32:25 -07001261 mProgram->getInputLayoutSignature(inputLayout, signature);
Jamie Madill7a29e4a2014-05-02 10:41:48 -04001262
1263 // add new binary
Geoff Lang04fb89a2014-06-09 15:05:36 -04001264 mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
Jamie Madillc5a83002014-02-14 16:41:25 -05001265
1266 stream.skip(vertexShaderSize);
1267 }
1268
Geoff Lang04fb89a2014-06-09 15:05:36 -04001269 const size_t pixelShaderCount = stream.readInt<unsigned int>();
1270 for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
1271 {
1272 const size_t outputCount = stream.readInt<unsigned int>();
1273 std::vector<GLenum> outputs(outputCount);
1274 for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
1275 {
1276 stream.readInt(&outputs[outputIndex]);
1277 }
1278
1279 const size_t pixelShaderSize = stream.readInt<unsigned int>();
1280 const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
Brandon Jonesc9610c52014-08-25 17:02:59 -07001281 rx::Renderer *renderer = mProgram->getRenderer();
1282 rx::ShaderExecutable *shaderExecutable = renderer->loadExecutable(pixelShaderFunction, pixelShaderSize,
1283 rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings,
1284 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
1285
Geoff Lang04fb89a2014-06-09 15:05:36 -04001286 if (!shaderExecutable)
1287 {
1288 infoLog.append("Could not create pixel shader.");
1289 return false;
1290 }
1291
1292 // add new binary
1293 mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
1294
1295 stream.skip(pixelShaderSize);
1296 }
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001297
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001298 unsigned int geometryShaderSize = stream.readInt<unsigned int>();
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001299
Jamie Madillc5a83002014-02-14 16:41:25 -05001300 if (geometryShaderSize > 0)
1301 {
1302 const char *geometryShaderFunction = (const char*) binary + stream.offset();
Brandon Jonesc9610c52014-08-25 17:02:59 -07001303 rx::Renderer *renderer = mProgram->getRenderer();
1304 mGeometryExecutable = renderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1305 geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
1306 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
1307
Jamie Madillc5a83002014-02-14 16:41:25 -05001308 if (!mGeometryExecutable)
1309 {
1310 infoLog.append("Could not create geometry shader.");
Jamie Madillc5a83002014-02-14 16:41:25 -05001311 return false;
1312 }
1313 stream.skip(geometryShaderSize);
1314 }
1315
Brandon Jones22502d52014-08-29 16:58:36 -07001316 if (!mProgram->load(infoLog, &stream))
1317 {
1318 return false;
1319 }
1320
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001321 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001322
daniel@transgaming.com36038542012-11-28 20:59:26 +00001323 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001324 ptr += sizeof(GUID);
1325
Brandon Jonesc9610c52014-08-25 17:02:59 -07001326 GUID identifier = mProgram->getRenderer()->getAdapterIdentifier();
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001327 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001328 {
1329 infoLog.append("Invalid program binary.");
1330 return false;
1331 }
1332
Brandon Jonesc9610c52014-08-25 17:02:59 -07001333 mProgram->initializeUniformStorage(mUniforms);
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001334
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001335 return true;
Jamie Madill9c4b24a2014-06-12 13:41:17 -04001336#endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001337}
1338
Geoff Lang900013c2014-07-07 11:32:19 -04001339bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001340{
Geoff Lang900013c2014-07-07 11:32:19 -04001341 if (binaryFormat)
1342 {
Brandon Jones22502d52014-08-29 16:58:36 -07001343 *binaryFormat = mProgram->getBinaryFormat();
Geoff Lang900013c2014-07-07 11:32:19 -04001344 }
1345
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001346 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001347
Brandon Jones22502d52014-08-29 16:58:36 -07001348 stream.writeInt(mProgram->getBinaryFormat());
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001349 stream.writeInt(ANGLE_MAJOR_VERSION);
1350 stream.writeInt(ANGLE_MINOR_VERSION);
Ehsan Akhgariaa7e1662014-07-05 21:13:11 -04001351 stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001352 stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001353
1354 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1355 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001356 stream.writeInt(mLinkedAttribute[i].type);
1357 stream.writeString(mLinkedAttribute[i].name);
1358 stream.writeInt(mShaderAttributes[i].type);
1359 stream.writeString(mShaderAttributes[i].name);
1360 stream.writeInt(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001361 }
1362
Geoff Lang76b10c92014-09-05 16:28:14 -04001363 stream.writeInt(mSamplersPS.size());
1364 for (unsigned int i = 0; i < mSamplersPS.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001365 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001366 stream.writeInt(mSamplersPS[i].active);
1367 stream.writeInt(mSamplersPS[i].logicalTextureUnit);
1368 stream.writeInt(mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001369 }
1370
Geoff Lang76b10c92014-09-05 16:28:14 -04001371 stream.writeInt(mSamplersVS.size());
1372 for (unsigned int i = 0; i < mSamplersVS.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001373 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001374 stream.writeInt(mSamplersVS[i].active);
1375 stream.writeInt(mSamplersVS[i].logicalTextureUnit);
1376 stream.writeInt(mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001377 }
1378
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001379 stream.writeInt(mUsedVertexSamplerRange);
1380 stream.writeInt(mUsedPixelSamplerRange);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001381
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001382 stream.writeInt(mUniforms.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001383 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001384 {
Jamie Madill834e8b72014-04-11 13:33:58 -04001385 const LinkedUniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001386
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001387 stream.writeInt(uniform.type);
1388 stream.writeInt(uniform.precision);
1389 stream.writeString(uniform.name);
1390 stream.writeInt(uniform.arraySize);
1391 stream.writeInt(uniform.blockIndex);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001392
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001393 stream.writeInt(uniform.blockInfo.offset);
1394 stream.writeInt(uniform.blockInfo.arrayStride);
1395 stream.writeInt(uniform.blockInfo.matrixStride);
1396 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001397
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001398 stream.writeInt(uniform.psRegisterIndex);
1399 stream.writeInt(uniform.vsRegisterIndex);
1400 stream.writeInt(uniform.registerCount);
1401 stream.writeInt(uniform.registerElement);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001402 }
1403
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001404 stream.writeInt(mUniformBlocks.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001405 for (size_t uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001406 {
1407 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1408
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001409 stream.writeString(uniformBlock.name);
1410 stream.writeInt(uniformBlock.elementIndex);
1411 stream.writeInt(uniformBlock.dataSize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001412
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001413 stream.writeInt(uniformBlock.memberUniformIndexes.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001414 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1415 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001416 stream.writeInt(uniformBlock.memberUniformIndexes[blockMemberIndex]);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001417 }
1418
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001419 stream.writeInt(uniformBlock.psRegisterIndex);
1420 stream.writeInt(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001421 }
1422
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001423 stream.writeInt(mUniformIndex.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001424 for (size_t i = 0; i < mUniformIndex.size(); ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001425 {
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001426 stream.writeString(mUniformIndex[i].name);
1427 stream.writeInt(mUniformIndex[i].element);
1428 stream.writeInt(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001429 }
1430
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001431 stream.writeInt(mTransformFeedbackBufferMode);
1432 stream.writeInt(mTransformFeedbackLinkedVaryings.size());
Geoff Lang48dcae72014-02-05 16:28:24 -05001433 for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
1434 {
1435 const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
1436
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001437 stream.writeString(varying.name);
1438 stream.writeInt(varying.type);
1439 stream.writeInt(varying.size);
1440 stream.writeString(varying.semanticName);
1441 stream.writeInt(varying.semanticIndex);
1442 stream.writeInt(varying.semanticIndexCount);
Geoff Lang48dcae72014-02-05 16:28:24 -05001443 }
1444
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001445 stream.writeInt(mVertexExecutables.size());
Jamie Madillc5a83002014-02-14 16:41:25 -05001446 for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
1447 {
1448 VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
1449
1450 for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
1451 {
1452 const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001453 stream.writeInt(vertexInput.mType);
1454 stream.writeInt(vertexInput.mNormalized);
1455 stream.writeInt(vertexInput.mComponents);
1456 stream.writeInt(vertexInput.mPureInteger);
Jamie Madillc5a83002014-02-14 16:41:25 -05001457 }
1458
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001459 size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
1460 stream.writeInt(vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001461
Jamie Madillcafa2102014-07-23 16:43:22 -04001462 const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction();
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001463 stream.writeBytes(vertexBlob, vertexShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001464 }
1465
Geoff Lang04fb89a2014-06-09 15:05:36 -04001466 stream.writeInt(mPixelExecutables.size());
1467 for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
1468 {
1469 PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
1470
1471 const std::vector<GLenum> outputs = pixelExecutable->outputSignature();
1472 stream.writeInt(outputs.size());
1473 for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++)
1474 {
1475 stream.writeInt(outputs[outputIndex]);
1476 }
1477
1478 size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength();
1479 stream.writeInt(pixelShaderSize);
1480
Jamie Madillcafa2102014-07-23 16:43:22 -04001481 const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction();
Geoff Lang04fb89a2014-06-09 15:05:36 -04001482 stream.writeBytes(pixelBlob, pixelShaderSize);
1483 }
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001484
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001485 size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1486 stream.writeInt(geometryShaderSize);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001487
Jamie Madillc5a83002014-02-14 16:41:25 -05001488 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1489 {
Jamie Madillcafa2102014-07-23 16:43:22 -04001490 const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001491 stream.writeBytes(geometryBlob, geometryShaderSize);
Jamie Madillc5a83002014-02-14 16:41:25 -05001492 }
1493
Brandon Jones22502d52014-08-29 16:58:36 -07001494 if (!mProgram->save(&stream))
1495 {
1496 if (length)
1497 {
1498 *length = 0;
1499 }
1500
1501 return false;
1502 }
1503
Brandon Jonesc9610c52014-08-25 17:02:59 -07001504 GUID identifier = mProgram->getRenderer()->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001505
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001506 GLsizei streamLength = stream.length();
1507 const void *streamData = stream.data();
1508
Jamie Madillc5a83002014-02-14 16:41:25 -05001509 GLsizei totalLength = streamLength + sizeof(GUID);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001510 if (totalLength > bufSize)
1511 {
1512 if (length)
1513 {
1514 *length = 0;
1515 }
1516
1517 return false;
1518 }
1519
1520 if (binary)
1521 {
1522 char *ptr = (char*) binary;
1523
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001524 memcpy(ptr, streamData, streamLength);
1525 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001526
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001527 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001528 ptr += sizeof(GUID);
1529
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001530 ASSERT(ptr - totalLength == binary);
1531 }
1532
1533 if (length)
1534 {
1535 *length = totalLength;
1536 }
1537
1538 return true;
1539}
1540
1541GLint ProgramBinary::getLength()
1542{
1543 GLint length;
Geoff Lang900013c2014-07-07 11:32:19 -04001544 if (save(NULL, NULL, INT_MAX, &length))
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001545 {
1546 return length;
1547 }
1548 else
1549 {
1550 return 0;
1551 }
1552}
1553
Brandon Jones71620962014-08-20 14:04:59 -07001554bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
Brandon Jones43a53e22014-08-28 16:23:22 -07001555 const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001556{
1557 if (!fragmentShader || !fragmentShader->isCompiled())
1558 {
1559 return false;
1560 }
Brandon Jones71620962014-08-20 14:04:59 -07001561 ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001562
1563 if (!vertexShader || !vertexShader->isCompiled())
1564 {
1565 return false;
1566 }
Brandon Jones71620962014-08-20 14:04:59 -07001567 ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001568
Geoff Lang04fb89a2014-06-09 15:05:36 -04001569 reset();
1570
Geoff Lang76b10c92014-09-05 16:28:14 -04001571 mSamplersPS.resize(caps.maxTextureImageUnits);
1572 mSamplersVS.resize(caps.maxVertexTextureImageUnits);
1573
Geoff Lang48dcae72014-02-05 16:28:24 -05001574 mTransformFeedbackBufferMode = transformFeedbackBufferMode;
1575
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001576 rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
1577 rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001578
Brandon Jones22502d52014-08-29 16:58:36 -07001579 int registers;
1580 std::vector<LinkedVarying> linkedVaryings;
1581 if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, &registers, &linkedVaryings, &mOutputVariables))
Jamie Madill5f562732014-02-14 16:41:24 -05001582 {
1583 return false;
1584 }
1585
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001586 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001587
Jamie Madilld15250e2014-09-03 09:40:44 -04001588 if (!linkAttributes(infoLog, attributeBindings, vertexShader))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001589 {
1590 success = false;
1591 }
1592
Brandon Jones43a53e22014-08-28 16:23:22 -07001593 if (!linkUniforms(infoLog, *vertexShader, *fragmentShader, caps))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001594 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001595 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001596 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001597
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001598 // special case for gl_DepthRange, the only built-in uniform (also a struct)
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001599 if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange())
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001600 {
Jamie Madille04a5b72014-07-18 10:33:12 -04001601 const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo();
1602
1603 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo));
1604 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo));
1605 mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001606 }
1607
Brandon Jones43a53e22014-08-28 16:23:22 -07001608 if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001609 {
1610 success = false;
1611 }
1612
Geoff Lang48dcae72014-02-05 16:28:24 -05001613 if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
Brandon Jones43a53e22014-08-28 16:23:22 -07001614 transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings, caps))
Geoff Lang48dcae72014-02-05 16:28:24 -05001615 {
1616 success = false;
1617 }
1618
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001619 if (success)
1620 {
Jamie Madillc5a83002014-02-14 16:41:25 -05001621 VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
Jamie Madill3f2e61d2014-09-05 10:38:05 -04001622 GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout);
Jamie Madillc5a83002014-02-14 16:41:25 -05001623 rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
Geoff Lang04fb89a2014-06-09 15:05:36 -04001624
Brandon Jones22502d52014-08-29 16:58:36 -07001625 std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(mProgram->getPixelShaderKey());
Geoff Lang04fb89a2014-06-09 15:05:36 -04001626 rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001627
Brandon Jones44151a92014-09-10 11:32:25 -07001628 if (mProgram->usesGeometryShader())
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001629 {
Brandon Jones44151a92014-09-10 11:32:25 -07001630 mGeometryExecutable = mProgram->getGeometryExecutable(infoLog, fragmentShader, vertexShader,
1631 mTransformFeedbackLinkedVaryings,
1632 (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
1633 registers);
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001634 }
1635
Brandon Jones44151a92014-09-10 11:32:25 -07001636 if (!defaultVertexExecutable || !defaultPixelExecutable || (mProgram->usesGeometryShader() && !mGeometryExecutable))
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001637 {
1638 infoLog.append("Failed to create D3D shaders.");
1639 success = false;
Geoff Lang04fb89a2014-06-09 15:05:36 -04001640 reset();
Jamie Madilld1ac3c92013-06-25 10:40:30 -04001641 }
1642 }
1643
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001644 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001645}
1646
1647// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
Jamie Madilld15250e2014-09-03 09:40:44 -04001648bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001649{
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001650 const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001651
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001652 unsigned int usedLocations = 0;
Jamie Madill54ad4f82014-09-03 09:40:46 -04001653 const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001654
1655 // Link attributes that have a binding location
Jamie Madill54ad4f82014-09-03 09:40:46 -04001656 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001657 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001658 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1659
1660 ASSERT(attribute.staticUse);
1661
Jamie Madilleba4eff2013-06-20 11:55:51 -04001662 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001663
Jamie Madill2c7d84a2014-02-14 16:41:26 -05001664 mShaderAttributes[attributeIndex] = attribute;
1665
Jamie Madilleba4eff2013-06-20 11:55:51 -04001666 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001667 {
Jamie Madillf2575982014-06-25 16:04:54 -04001668 const int rows = VariableRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001669
1670 if (rows + location > MAX_VERTEX_ATTRIBS)
1671 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001672 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 +00001673
1674 return false;
1675 }
1676
Jamie Madilleba4eff2013-06-20 11:55:51 -04001677 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001678 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04001679 const int rowLocation = location + row;
Jamie Madillf2575982014-06-25 16:04:54 -04001680 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
Jamie Madilleba4eff2013-06-20 11:55:51 -04001681
1682 // In GLSL 3.00, attribute aliasing produces a link error
1683 // In GLSL 1.00, attribute aliasing is allowed
Brandon Jones44151a92014-09-10 11:32:25 -07001684 if (mProgram->getShaderVersion() >= 300)
Jamie Madilleba4eff2013-06-20 11:55:51 -04001685 {
1686 if (!linkedAttribute.name.empty())
1687 {
1688 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
1689 return false;
1690 }
1691 }
1692
1693 linkedAttribute = attribute;
1694 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001695 }
1696 }
1697 }
1698
1699 // Link attributes that don't have a binding location
Jamie Madill54ad4f82014-09-03 09:40:46 -04001700 for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001701 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04001702 const sh::Attribute &attribute = shaderAttributes[attributeIndex];
1703
1704 ASSERT(attribute.staticUse);
1705
Jamie Madilleba4eff2013-06-20 11:55:51 -04001706 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001707
Jamie Madilleba4eff2013-06-20 11:55:51 -04001708 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001709 {
Jamie Madillf2575982014-06-25 16:04:54 -04001710 int rows = VariableRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001711 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1712
1713 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1714 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001715 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001716
1717 return false; // Fail to link
1718 }
1719
Jamie Madilldefb6742013-06-20 11:55:51 -04001720 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001721 }
1722 }
1723
1724 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1725 {
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001726 int index = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillf2575982014-06-25 16:04:54 -04001727 int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001728
1729 for (int r = 0; r < rows; r++)
1730 {
1731 mSemanticIndex[attributeIndex++] = index++;
1732 }
1733 }
1734
Al Patrick3f2daa82013-08-07 12:58:57 -07001735 initAttributesByLayout();
1736
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001737 return true;
1738}
1739
Jamie Madillf2575982014-06-25 16:04:54 -04001740bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
1741 const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001742{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001743 if (vertexVariable.type != fragmentVariable.type)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001744 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001745 infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001746 return false;
1747 }
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001748 if (vertexVariable.arraySize != fragmentVariable.arraySize)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001749 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001750 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001751 return false;
1752 }
Jamie Madill28167c62013-08-30 13:21:10 -04001753 if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001754 {
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001755 infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill010fffa2013-06-20 11:55:53 -04001756 return false;
1757 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001758
Jamie Madill42bcf322014-08-25 16:20:46 -04001759 if (vertexVariable.fields.size() != fragmentVariable.fields.size())
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001760 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001761 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001762 return false;
1763 }
Jamie Madill42bcf322014-08-25 16:20:46 -04001764 const unsigned int numMembers = vertexVariable.fields.size();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001765 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1766 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001767 const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
1768 const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001769
1770 if (vertexMember.name != fragmentMember.name)
1771 {
Jamie Madill28167c62013-08-30 13:21:10 -04001772 infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
Jamie Madill42bcf322014-08-25 16:20:46 -04001773 memberIndex, variableName.c_str(),
1774 vertexMember.name.c_str(), fragmentMember.name.c_str());
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001775 return false;
1776 }
1777
Jamie Madill42bcf322014-08-25 16:20:46 -04001778 const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
1779 vertexMember.name + "'";
1780
1781 if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001782 {
1783 return false;
1784 }
1785 }
1786
1787 return true;
1788}
1789
Jamie Madill42bcf322014-08-25 16:20:46 -04001790bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001791{
Jamie Madill28167c62013-08-30 13:21:10 -04001792 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001793 {
1794 return false;
1795 }
1796
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001797 return true;
1798}
1799
Jamie Madill42bcf322014-08-25 16:20:46 -04001800bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
Jamie Madill28167c62013-08-30 13:21:10 -04001801{
1802 if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
1803 {
1804 return false;
1805 }
1806
1807 if (vertexVarying.interpolation != fragmentVarying.interpolation)
1808 {
1809 infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
1810 return false;
1811 }
1812
Jamie Madill28167c62013-08-30 13:21:10 -04001813 return true;
1814}
1815
Jamie Madill42bcf322014-08-25 16:20:46 -04001816bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001817{
Jamie Madill28167c62013-08-30 13:21:10 -04001818 if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001819 {
1820 return false;
1821 }
1822
Jamie Madilla6f267f2014-08-27 11:44:15 -04001823 if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001824 {
1825 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
1826 return false;
1827 }
1828
Jamie Madill9d2ffb12013-08-30 13:21:04 -04001829 return true;
1830}
1831
Brandon Jones43a53e22014-08-28 16:23:22 -07001832bool ProgramBinary::linkUniforms(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001833{
Jamie Madill2ad1dc42014-09-03 09:40:45 -04001834 const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader.getImplementation());
1835 const rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader.getImplementation());
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001836
Jamie Madilld15250e2014-09-03 09:40:44 -04001837 const std::vector<sh::Uniform> &vertexUniforms = vertexShader.getUniforms();
1838 const std::vector<sh::Uniform> &fragmentUniforms = fragmentShader.getUniforms();
Jamie Madillbf9cce22014-07-18 10:33:09 -04001839
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001840 // Check that uniforms defined in the vertex and fragment shaders are identical
Jamie Madillf2575982014-06-25 16:04:54 -04001841 typedef std::map<std::string, const sh::Uniform*> UniformMap;
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001842 UniformMap linkedUniforms;
1843
1844 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
1845 {
Jamie Madillf2575982014-06-25 16:04:54 -04001846 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001847 linkedUniforms[vertexUniform.name] = &vertexUniform;
1848 }
1849
1850 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
1851 {
Jamie Madillf2575982014-06-25 16:04:54 -04001852 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001853 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
1854 if (entry != linkedUniforms.end())
1855 {
Jamie Madillf2575982014-06-25 16:04:54 -04001856 const sh::Uniform &vertexUniform = *entry->second;
Jamie Madill28167c62013-08-30 13:21:10 -04001857 const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
Jamie Madill42bcf322014-08-25 16:20:46 -04001858 if (!linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001859 {
1860 return false;
1861 }
1862 }
1863 }
1864
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001865 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001866 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001867 const sh::Uniform &uniform = vertexUniforms[uniformIndex];
Jamie Madill54ad4f82014-09-03 09:40:46 -04001868
1869 if (uniform.staticUse)
1870 {
1871 defineUniformBase(GL_VERTEX_SHADER, uniform, vertexShaderD3D->getUniformRegister(uniform.name));
1872 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001873 }
1874
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001875 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001876 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001877 const sh::Uniform &uniform = fragmentUniforms[uniformIndex];
Jamie Madill54ad4f82014-09-03 09:40:46 -04001878
1879 if (uniform.staticUse)
1880 {
1881 defineUniformBase(GL_FRAGMENT_SHADER, uniform, fragmentShaderD3D->getUniformRegister(uniform.name));
1882 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001883 }
1884
Brandon Jones43a53e22014-08-28 16:23:22 -07001885 if (!indexUniforms(infoLog, caps))
Jamie Madill66d43d22014-07-11 17:02:03 -04001886 {
1887 return false;
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00001888 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001889
Brandon Jonesc9610c52014-08-25 17:02:59 -07001890 mProgram->initializeUniformStorage(mUniforms);
Jamie Madill8ff21ae2014-02-04 16:04:05 -05001891
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001892 return true;
1893}
1894
Jamie Madillbf9cce22014-07-18 10:33:09 -04001895void ProgramBinary::defineUniformBase(GLenum shader, const sh::Uniform &uniform, unsigned int uniformRegister)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001896{
Brandon Jonesf05cdee2014-08-27 15:24:07 -07001897 ShShaderOutput outputType = rx::ShaderD3D::getCompilerOutputType(shader);
Jamie Madille04a5b72014-07-18 10:33:12 -04001898 sh::HLSLBlockEncoder encoder(sh::HLSLBlockEncoder::GetStrategyFor(outputType));
Jamie Madillbf9cce22014-07-18 10:33:09 -04001899 encoder.skipRegisters(uniformRegister);
1900
1901 defineUniform(shader, uniform, uniform.name, &encoder);
Jamie Madill5b130dc2014-07-11 17:02:05 -04001902}
1903
Jamie Madill42bcf322014-08-25 16:20:46 -04001904void ProgramBinary::defineUniform(GLenum shader, const sh::ShaderVariable &uniform,
Jamie Madillbf9cce22014-07-18 10:33:09 -04001905 const std::string &fullName, sh::HLSLBlockEncoder *encoder)
Jamie Madill5b130dc2014-07-11 17:02:05 -04001906{
1907 if (uniform.isStruct())
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001908 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001909 for (unsigned int elementIndex = 0; elementIndex < uniform.elementCount(); elementIndex++)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001910 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001911 const std::string &elementString = (uniform.isArray() ? ArrayString(elementIndex) : "");
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001912
Jamie Madillbf9cce22014-07-18 10:33:09 -04001913 encoder->enterAggregateType();
Jamie Madillc600c8c2014-05-16 11:22:21 -04001914
Jamie Madill5b130dc2014-07-11 17:02:05 -04001915 for (size_t fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001916 {
Jamie Madill42bcf322014-08-25 16:20:46 -04001917 const sh::ShaderVariable &field = uniform.fields[fieldIndex];
Jamie Madillbf9cce22014-07-18 10:33:09 -04001918 const std::string &fieldFullName = (fullName + elementString + "." + field.name);
1919
1920 defineUniform(shader, field, fieldFullName, encoder);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001921 }
Jamie Madillbf9cce22014-07-18 10:33:09 -04001922
1923 encoder->exitAggregateType();
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001924 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001925 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001926 else // Not a struct
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001927 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001928 // Arrays are treated as aggregate types
1929 if (uniform.isArray())
1930 {
1931 encoder->enterAggregateType();
1932 }
1933
Jamie Madill5b130dc2014-07-11 17:02:05 -04001934 LinkedUniform *linkedUniform = getUniformByName(fullName);
Jamie Madill1b2a8f92014-05-14 13:09:39 -04001935
Jamie Madill66d43d22014-07-11 17:02:03 -04001936 if (!linkedUniform)
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001937 {
Jamie Madill5b130dc2014-07-11 17:02:05 -04001938 linkedUniform = new LinkedUniform(uniform.type, uniform.precision, fullName, uniform.arraySize,
Jamie Madill66d43d22014-07-11 17:02:03 -04001939 -1, sh::BlockMemberInfo::getDefaultBlockInfo());
1940 ASSERT(linkedUniform);
Jamie Madillbf9cce22014-07-18 10:33:09 -04001941 linkedUniform->registerElement = encoder->getCurrentElement();
Jamie Madill66d43d22014-07-11 17:02:03 -04001942 mUniforms.push_back(linkedUniform);
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001943 }
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00001944
Jamie Madillbf9cce22014-07-18 10:33:09 -04001945 ASSERT(linkedUniform->registerElement == encoder->getCurrentElement());
1946
Jamie Madill66d43d22014-07-11 17:02:03 -04001947 if (shader == GL_FRAGMENT_SHADER)
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001948 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001949 linkedUniform->psRegisterIndex = encoder->getCurrentRegister();
Jamie Madill66d43d22014-07-11 17:02:03 -04001950 }
1951 else if (shader == GL_VERTEX_SHADER)
1952 {
Jamie Madillbf9cce22014-07-18 10:33:09 -04001953 linkedUniform->vsRegisterIndex = encoder->getCurrentRegister();
Jamie Madill66d43d22014-07-11 17:02:03 -04001954 }
1955 else UNREACHABLE();
Jamie Madillbf9cce22014-07-18 10:33:09 -04001956
1957 // Advance the uniform offset, to track registers allocation for structs
1958 encoder->encodeType(uniform.type, uniform.arraySize, false);
1959
1960 // Arrays are treated as aggregate types
1961 if (uniform.isArray())
1962 {
1963 encoder->exitAggregateType();
1964 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001965 }
1966}
1967
Brandon Jones43a53e22014-08-28 16:23:22 -07001968bool ProgramBinary::indexSamplerUniform(const LinkedUniform &uniform, InfoLog &infoLog, const Caps &caps)
Jamie Madill66d43d22014-07-11 17:02:03 -04001969{
1970 ASSERT(IsSampler(uniform.type));
1971 ASSERT(uniform.vsRegisterIndex != GL_INVALID_INDEX || uniform.psRegisterIndex != GL_INVALID_INDEX);
1972
1973 if (uniform.vsRegisterIndex != GL_INVALID_INDEX)
1974 {
1975 if (!assignSamplers(uniform.vsRegisterIndex, uniform.type, uniform.arraySize, mSamplersVS,
Geoff Lang76b10c92014-09-05 16:28:14 -04001976 &mUsedVertexSamplerRange))
Jamie Madill66d43d22014-07-11 17:02:03 -04001977 {
1978 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).",
Geoff Lang76b10c92014-09-05 16:28:14 -04001979 mSamplersVS.size());
Jamie Madill66d43d22014-07-11 17:02:03 -04001980 return false;
1981 }
1982
Brandon Jonesc9610c52014-08-25 17:02:59 -07001983 unsigned int maxVertexVectors = mProgram->getRenderer()->getReservedVertexUniformVectors() + caps.maxVertexUniformVectors;
Jamie Madill66d43d22014-07-11 17:02:03 -04001984 if (uniform.vsRegisterIndex + uniform.registerCount > maxVertexVectors)
1985 {
1986 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)",
Geoff Lang301d1612014-07-09 10:34:37 -04001987 caps.maxVertexUniformVectors);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001988 return false;
1989 }
1990 }
Jamie Madill66d43d22014-07-11 17:02:03 -04001991
1992 if (uniform.psRegisterIndex != GL_INVALID_INDEX)
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001993 {
Jamie Madill66d43d22014-07-11 17:02:03 -04001994 if (!assignSamplers(uniform.psRegisterIndex, uniform.type, uniform.arraySize, mSamplersPS,
Geoff Lang76b10c92014-09-05 16:28:14 -04001995 &mUsedPixelSamplerRange))
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00001996 {
Jamie Madill66d43d22014-07-11 17:02:03 -04001997 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).",
Geoff Lang76b10c92014-09-05 16:28:14 -04001998 mSamplersPS.size());
Jamie Madill66d43d22014-07-11 17:02:03 -04001999 return false;
2000 }
2001
Brandon Jonesc9610c52014-08-25 17:02:59 -07002002 unsigned int maxFragmentVectors = mProgram->getRenderer()->getReservedFragmentUniformVectors() + caps.maxFragmentUniformVectors;
Jamie Madill66d43d22014-07-11 17:02:03 -04002003 if (uniform.psRegisterIndex + uniform.registerCount > maxFragmentVectors)
2004 {
2005 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)",
Geoff Lang301d1612014-07-09 10:34:37 -04002006 caps.maxFragmentUniformVectors);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002007 return false;
2008 }
2009 }
Jamie Madill66d43d22014-07-11 17:02:03 -04002010
2011 return true;
2012}
2013
Brandon Jones43a53e22014-08-28 16:23:22 -07002014bool ProgramBinary::indexUniforms(InfoLog &infoLog, const Caps &caps)
Jamie Madill66d43d22014-07-11 17:02:03 -04002015{
2016 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2017 {
2018 const LinkedUniform &uniform = *mUniforms[uniformIndex];
2019
2020 if (IsSampler(uniform.type))
2021 {
Brandon Jones43a53e22014-08-28 16:23:22 -07002022 if (!indexSamplerUniform(uniform, infoLog, caps))
Jamie Madill66d43d22014-07-11 17:02:03 -04002023 {
2024 return false;
2025 }
2026 }
2027
2028 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform.elementCount(); arrayElementIndex++)
2029 {
2030 mUniformIndex.push_back(VariableLocation(uniform.name, arrayElementIndex, uniformIndex));
2031 }
2032 }
2033
2034 return true;
2035}
2036
2037bool ProgramBinary::assignSamplers(unsigned int startSamplerIndex,
2038 GLenum samplerType,
2039 unsigned int samplerCount,
Geoff Lang76b10c92014-09-05 16:28:14 -04002040 std::vector<Sampler> &outSamplers,
2041 GLuint *outUsedRange)
Jamie Madill66d43d22014-07-11 17:02:03 -04002042{
2043 unsigned int samplerIndex = startSamplerIndex;
2044
2045 do
2046 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002047 if (samplerIndex < outSamplers.size())
Jamie Madill66d43d22014-07-11 17:02:03 -04002048 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002049 Sampler& sampler = outSamplers[samplerIndex];
2050 sampler.active = true;
2051 sampler.textureType = GetTextureType(samplerType);
2052 sampler.logicalTextureUnit = 0;
2053 *outUsedRange = std::max(samplerIndex + 1, *outUsedRange);
Jamie Madill66d43d22014-07-11 17:02:03 -04002054 }
2055 else
2056 {
2057 return false;
2058 }
2059
2060 samplerIndex++;
2061 } while (samplerIndex < startSamplerIndex + samplerCount);
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002062
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002063 return true;
2064}
2065
Jamie Madillf2575982014-06-25 16:04:54 -04002066bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002067{
2068 const char* blockName = vertexInterfaceBlock.name.c_str();
2069
2070 // validate blocks for the same member types
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002071 if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002072 {
2073 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2074 return false;
2075 }
2076
2077 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2078 {
2079 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2080 return false;
2081 }
2082
Jamie Madill9060a4e2013-08-12 16:22:57 -07002083 if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
2084 {
2085 infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
2086 return false;
2087 }
2088
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002089 const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002090 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2091 {
Jamie Madillf2575982014-06-25 16:04:54 -04002092 const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
2093 const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002094
2095 if (vertexMember.name != fragmentMember.name)
2096 {
Jamie Madill28167c62013-08-30 13:21:10 -04002097 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 +00002098 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2099 return false;
2100 }
2101
Jamie Madill42bcf322014-08-25 16:20:46 -04002102 std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
2103 if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002104 {
2105 return false;
2106 }
2107 }
2108
2109 return true;
2110}
2111
Brandon Jones43a53e22014-08-28 16:23:22 -07002112bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002113{
Jamie Madilld15250e2014-09-03 09:40:44 -04002114 const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
2115 const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
Jamie Madilld4116ff2014-07-11 17:02:01 -04002116
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002117 // Check that interface blocks defined in the vertex and fragment shaders are identical
Jamie Madillf2575982014-06-25 16:04:54 -04002118 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002119 UniformBlockMap linkedUniformBlocks;
2120
2121 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2122 {
Jamie Madillf2575982014-06-25 16:04:54 -04002123 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002124 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2125 }
2126
2127 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2128 {
Jamie Madillf2575982014-06-25 16:04:54 -04002129 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002130 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2131 if (entry != linkedUniformBlocks.end())
2132 {
Jamie Madillf2575982014-06-25 16:04:54 -04002133 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002134 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2135 {
2136 return false;
2137 }
2138 }
2139 }
2140
2141 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2142 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002143 const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
2144
Jamie Madill04668672014-09-03 09:40:49 -04002145 // Note: shared and std140 layouts are always considered active
2146 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002147 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002148 if (!defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
2149 {
2150 return false;
2151 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002152 }
2153 }
2154
2155 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2156 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002157 const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
2158
Jamie Madill04668672014-09-03 09:40:49 -04002159 // Note: shared and std140 layouts are always considered active
2160 if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002161 {
Jamie Madill54ad4f82014-09-03 09:40:46 -04002162 if (!defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
2163 {
2164 return false;
2165 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002166 }
2167 }
2168
2169 return true;
2170}
2171
Geoff Lang48dcae72014-02-05 16:28:24 -05002172bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
2173 const std::vector<std::string> &transformFeedbackVaryingNames,
2174 GLenum transformFeedbackBufferMode,
Brandon Jones43a53e22014-08-28 16:23:22 -07002175 std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
2176 const Caps &caps) const
Geoff Lang48dcae72014-02-05 16:28:24 -05002177{
2178 size_t totalComponents = 0;
Geoff Lang05881a02014-07-10 14:05:30 -04002179
Geoff Lang48dcae72014-02-05 16:28:24 -05002180 // Gather the linked varyings that are used for transform feedback, they should all exist.
2181 outTransformFeedbackLinkedVaryings->clear();
2182 for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
2183 {
2184 bool found = false;
2185 for (size_t j = 0; j < linkedVaryings.size(); j++)
2186 {
2187 if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
2188 {
2189 for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
2190 {
2191 if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
2192 {
2193 infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
2194 return false;
2195 }
2196 }
2197
2198 size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
2199 if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
Geoff Lang05881a02014-07-10 14:05:30 -04002200 componentCount > caps.maxTransformFeedbackSeparateComponents)
Geoff Lang48dcae72014-02-05 16:28:24 -05002201 {
2202 infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
Geoff Lang05881a02014-07-10 14:05:30 -04002203 linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
Geoff Lang48dcae72014-02-05 16:28:24 -05002204 return false;
2205 }
2206
2207 totalComponents += componentCount;
2208
2209 outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
2210 found = true;
2211 break;
2212 }
2213 }
2214
2215 // All transform feedback varyings are expected to exist since packVaryings checks for them.
2216 ASSERT(found);
2217 }
2218
Geoff Lang05881a02014-07-10 14:05:30 -04002219 if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
Geoff Lang48dcae72014-02-05 16:28:24 -05002220 {
2221 infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
Geoff Lang05881a02014-07-10 14:05:30 -04002222 totalComponents, caps.maxTransformFeedbackInterleavedComponents);
Geoff Lang48dcae72014-02-05 16:28:24 -05002223 return false;
2224 }
2225
2226 return true;
2227}
2228
Jamie Madill42bcf322014-08-25 16:20:46 -04002229template <typename VarT>
2230void ProgramBinary::defineUniformBlockMembers(const std::vector<VarT> &fields, const std::string &prefix, int blockIndex,
Jamie Madilla6f267f2014-08-27 11:44:15 -04002231 sh::BlockLayoutEncoder *encoder, std::vector<unsigned int> *blockUniformIndexes,
2232 bool inRowMajorLayout)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002233{
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002234 for (unsigned int uniformIndex = 0; uniformIndex < fields.size(); uniformIndex++)
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002235 {
Jamie Madill42bcf322014-08-25 16:20:46 -04002236 const VarT &field = fields[uniformIndex];
Jamie Madill9d2ffb12013-08-30 13:21:04 -04002237 const std::string &fieldName = (prefix.empty() ? field.name : prefix + "." + field.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002238
Jamie Madille04a5b72014-07-18 10:33:12 -04002239 if (field.isStruct())
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002240 {
Jamie Madilla6f267f2014-08-27 11:44:15 -04002241 bool rowMajorLayout = (inRowMajorLayout || IsRowMajorLayout(field));
2242
Jamie Madille04a5b72014-07-18 10:33:12 -04002243 for (unsigned int arrayElement = 0; arrayElement < field.elementCount(); arrayElement++)
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002244 {
Jamie Madille04a5b72014-07-18 10:33:12 -04002245 encoder->enterAggregateType();
2246
2247 const std::string uniformElementName = fieldName + (field.isArray() ? ArrayString(arrayElement) : "");
Jamie Madilla6f267f2014-08-27 11:44:15 -04002248 defineUniformBlockMembers(field.fields, uniformElementName, blockIndex, encoder, blockUniformIndexes, rowMajorLayout);
Jamie Madille04a5b72014-07-18 10:33:12 -04002249
2250 encoder->exitAggregateType();
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002251 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002252 }
2253 else
2254 {
Jamie Madilla6f267f2014-08-27 11:44:15 -04002255 bool isRowMajorMatrix = (IsMatrixType(field.type) && inRowMajorLayout);
2256
2257 sh::BlockMemberInfo memberInfo = encoder->encodeType(field.type, field.arraySize, isRowMajorMatrix);
Jamie Madille04a5b72014-07-18 10:33:12 -04002258
Jamie Madill834e8b72014-04-11 13:33:58 -04002259 LinkedUniform *newUniform = new LinkedUniform(field.type, field.precision, fieldName, field.arraySize,
Jamie Madille04a5b72014-07-18 10:33:12 -04002260 blockIndex, memberInfo);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002261
2262 // add to uniform list, but not index, since uniform block uniforms have no location
2263 blockUniformIndexes->push_back(mUniforms.size());
2264 mUniforms.push_back(newUniform);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002265 }
2266 }
2267}
2268
Brandon Jones43a53e22014-08-28 16:23:22 -07002269bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, const Shader &shader, const sh::InterfaceBlock &interfaceBlock, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002270{
Brandon Jonesf05cdee2014-08-27 15:24:07 -07002271 const rx::ShaderD3D* shaderD3D = rx::ShaderD3D::makeShaderD3D(shader.getImplementation());
2272
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002273 // create uniform block entries if they do not exist
2274 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2275 {
2276 std::vector<unsigned int> blockUniformIndexes;
2277 const unsigned int blockIndex = mUniformBlocks.size();
2278
2279 // define member uniforms
Jamie Madille04a5b72014-07-18 10:33:12 -04002280 sh::BlockLayoutEncoder *encoder = NULL;
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002281
Jamie Madille04a5b72014-07-18 10:33:12 -04002282 if (interfaceBlock.layout == sh::BLOCKLAYOUT_STANDARD)
2283 {
2284 encoder = new sh::Std140BlockEncoder;
2285 }
2286 else
2287 {
2288 encoder = new sh::HLSLBlockEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED);
2289 }
2290 ASSERT(encoder);
2291
Jamie Madilla6f267f2014-08-27 11:44:15 -04002292 defineUniformBlockMembers(interfaceBlock.fields, "", blockIndex, encoder, &blockUniformIndexes, interfaceBlock.isRowMajorLayout);
Jamie Madille04a5b72014-07-18 10:33:12 -04002293
2294 size_t dataSize = encoder->getBlockSize();
Jamie Madillfc43d272014-07-11 17:02:02 -04002295
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002296 // create all the uniform blocks
2297 if (interfaceBlock.arraySize > 0)
2298 {
2299 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2300 {
Jamie Madillfc43d272014-07-11 17:02:02 -04002301 UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, dataSize);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002302 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2303 mUniformBlocks.push_back(newUniformBlock);
2304 }
2305 }
2306 else
2307 {
Jamie Madillfc43d272014-07-11 17:02:02 -04002308 UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, dataSize);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002309 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2310 mUniformBlocks.push_back(newUniformBlock);
2311 }
2312 }
2313
Jamie Madill04668672014-09-03 09:40:49 -04002314 if (interfaceBlock.staticUse)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002315 {
Jamie Madill04668672014-09-03 09:40:49 -04002316 // Assign registers to the uniform blocks
2317 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2318 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2319 ASSERT(blockIndex != GL_INVALID_INDEX);
2320 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002321
Jamie Madill04668672014-09-03 09:40:49 -04002322 unsigned int interfaceBlockRegister = shaderD3D->getInterfaceBlockRegister(interfaceBlock.name);
2323
2324 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002325 {
Jamie Madill04668672014-09-03 09:40:49 -04002326 UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2327 ASSERT(uniformBlock->name == interfaceBlock.name);
2328
2329 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader.getType(),
2330 interfaceBlockRegister + uniformBlockElement, caps))
2331 {
2332 return false;
2333 }
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002334 }
2335 }
2336
2337 return true;
2338}
2339
Brandon Jones43a53e22014-08-28 16:23:22 -07002340bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002341{
2342 if (shader == GL_VERTEX_SHADER)
2343 {
2344 uniformBlock->vsRegisterIndex = registerIndex;
Brandon Jonesc9610c52014-08-25 17:02:59 -07002345 if (registerIndex - mProgram->getRenderer()->getReservedVertexUniformBuffers() >= caps.maxVertexUniformBlocks)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002346 {
Geoff Lang301d1612014-07-09 10:34:37 -04002347 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", caps.maxVertexUniformBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002348 return false;
2349 }
2350 }
2351 else if (shader == GL_FRAGMENT_SHADER)
2352 {
2353 uniformBlock->psRegisterIndex = registerIndex;
Brandon Jonesc9610c52014-08-25 17:02:59 -07002354 if (registerIndex - mProgram->getRenderer()->getReservedFragmentUniformBuffers() >= caps.maxFragmentUniformBlocks)
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002355 {
Geoff Lang301d1612014-07-09 10:34:37 -04002356 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", caps.maxFragmentUniformBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002357 return false;
2358 }
2359 }
2360 else UNREACHABLE();
2361
2362 return true;
2363}
2364
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002365bool ProgramBinary::isValidated() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002366{
2367 return mValidated;
2368}
2369
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002370void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002371{
2372 // Skip over inactive attributes
2373 unsigned int activeAttribute = 0;
2374 unsigned int attribute;
2375 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2376 {
2377 if (mLinkedAttribute[attribute].name.empty())
2378 {
2379 continue;
2380 }
2381
2382 if (activeAttribute == index)
2383 {
2384 break;
2385 }
2386
2387 activeAttribute++;
2388 }
2389
2390 if (bufsize > 0)
2391 {
2392 const char *string = mLinkedAttribute[attribute].name.c_str();
2393
2394 strncpy(name, string, bufsize);
2395 name[bufsize - 1] = '\0';
2396
2397 if (length)
2398 {
2399 *length = strlen(name);
2400 }
2401 }
2402
2403 *size = 1; // Always a single 'type' instance
2404
2405 *type = mLinkedAttribute[attribute].type;
2406}
2407
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002408GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002409{
2410 int count = 0;
2411
2412 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2413 {
2414 if (!mLinkedAttribute[attributeIndex].name.empty())
2415 {
2416 count++;
2417 }
2418 }
2419
2420 return count;
2421}
2422
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002423GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002424{
2425 int maxLength = 0;
2426
2427 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2428 {
2429 if (!mLinkedAttribute[attributeIndex].name.empty())
2430 {
2431 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2432 }
2433 }
2434
2435 return maxLength;
2436}
2437
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002438void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002439{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002440 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002441
2442 if (bufsize > 0)
2443 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002444 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002445
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002446 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002447 {
2448 string += "[0]";
2449 }
2450
2451 strncpy(name, string.c_str(), bufsize);
2452 name[bufsize - 1] = '\0';
2453
2454 if (length)
2455 {
2456 *length = strlen(name);
2457 }
2458 }
2459
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002460 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002461
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002462 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002463}
2464
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002465GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002466{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002467 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002468}
2469
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002470GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002471{
2472 int maxLength = 0;
2473
2474 unsigned int numUniforms = mUniforms.size();
2475 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2476 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002477 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002478 {
2479 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2480 if (mUniforms[uniformIndex]->isArray())
2481 {
2482 length += 3; // Counting in "[0]".
2483 }
2484 maxLength = std::max(length, maxLength);
2485 }
2486 }
2487
2488 return maxLength;
2489}
2490
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002491GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2492{
Jamie Madill834e8b72014-04-11 13:33:58 -04002493 const gl::LinkedUniform& uniform = *mUniforms[index];
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002494
2495 switch (pname)
2496 {
2497 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2498 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002499 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 +00002500 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002501
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002502 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2503 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2504 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2505 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002506
2507 default:
2508 UNREACHABLE();
2509 break;
2510 }
2511 return 0;
2512}
2513
Jamie Madill36398922014-05-20 14:51:53 -04002514bool ProgramBinary::isValidUniformLocation(GLint location) const
2515{
2516 ASSERT(rx::IsIntegerCastSafe<GLint>(mUniformIndex.size()));
2517 return (location >= 0 && location < static_cast<GLint>(mUniformIndex.size()));
2518}
2519
2520LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const
2521{
2522 ASSERT(location >= 0 && static_cast<size_t>(location) < mUniformIndex.size());
2523 return mUniforms[mUniformIndex[location].index];
2524}
2525
Jamie Madill66d43d22014-07-11 17:02:03 -04002526LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const
2527{
2528 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
2529 {
2530 if (mUniforms[uniformIndex]->name == name)
2531 {
2532 return mUniforms[uniformIndex];
2533 }
2534 }
2535
2536 return NULL;
2537}
2538
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002539void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2540{
2541 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2542
2543 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2544
2545 if (bufSize > 0)
2546 {
2547 std::string string = uniformBlock.name;
2548
2549 if (uniformBlock.isArrayElement())
2550 {
Jamie Madill5f562732014-02-14 16:41:24 -05002551 string += ArrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002552 }
2553
2554 strncpy(uniformBlockName, string.c_str(), bufSize);
2555 uniformBlockName[bufSize - 1] = '\0';
2556
2557 if (length)
2558 {
2559 *length = strlen(uniformBlockName);
2560 }
2561 }
2562}
2563
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002564void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2565{
2566 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2567
2568 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2569
2570 switch (pname)
2571 {
2572 case GL_UNIFORM_BLOCK_DATA_SIZE:
2573 *params = static_cast<GLint>(uniformBlock.dataSize);
2574 break;
2575 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002576 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002577 break;
2578 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2579 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2580 break;
2581 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2582 {
2583 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2584 {
2585 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2586 }
2587 }
2588 break;
2589 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2590 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2591 break;
2592 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2593 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2594 break;
2595 default: UNREACHABLE();
2596 }
2597}
2598
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002599GLuint ProgramBinary::getActiveUniformBlockCount() const
2600{
2601 return mUniformBlocks.size();
2602}
2603
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002604GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2605{
2606 unsigned int maxLength = 0;
2607
2608 unsigned int numUniformBlocks = mUniformBlocks.size();
2609 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2610 {
2611 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2612 if (!uniformBlock.name.empty())
2613 {
2614 const unsigned int length = uniformBlock.name.length() + 1;
2615
2616 // Counting in "[0]".
2617 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2618
2619 maxLength = std::max(length + arrayLength, maxLength);
2620 }
2621 }
2622
2623 return maxLength;
2624}
2625
Brandon Jones43a53e22014-08-28 16:23:22 -07002626void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002627{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002628 applyUniforms();
Brandon Jones43a53e22014-08-28 16:23:22 -07002629 if (!validateSamplers(&infoLog, caps))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002630 {
2631 mValidated = false;
2632 }
2633 else
2634 {
2635 mValidated = true;
2636 }
2637}
2638
Brandon Jones43a53e22014-08-28 16:23:22 -07002639bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002640{
2641 // if any two active samplers in a program are of different types, but refer to the same
2642 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2643 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
Jamie Madilld4cfa572014-07-08 10:00:32 -04002644 updateSamplerMapping();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002645
Geoff Lang76b10c92014-09-05 16:28:14 -04002646 std::vector<GLenum> textureUnitTypes(caps.maxCombinedTextureImageUnits, GL_NONE);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002647
2648 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2649 {
2650 if (mSamplersPS[i].active)
2651 {
2652 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002653
Geoff Lang76b10c92014-09-05 16:28:14 -04002654 if (unit >= textureUnitTypes.size())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002655 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002656 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002657 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002658 infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002659 }
2660
2661 return false;
2662 }
2663
Geoff Lang76b10c92014-09-05 16:28:14 -04002664 if (textureUnitTypes[unit] != GL_NONE)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002665 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002666 if (mSamplersPS[i].textureType != textureUnitTypes[unit])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002667 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002668 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002669 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002670 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002671 }
2672
2673 return false;
2674 }
2675 }
2676 else
2677 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002678 textureUnitTypes[unit] = mSamplersPS[i].textureType;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002679 }
2680 }
2681 }
2682
2683 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2684 {
2685 if (mSamplersVS[i].active)
2686 {
2687 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
Jamie Madill1b2a8f92014-05-14 13:09:39 -04002688
Geoff Lang76b10c92014-09-05 16:28:14 -04002689 if (unit >= textureUnitTypes.size())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002690 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002691 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002692 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002693 infoLog->append("Sampler uniform (%d) exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, textureUnitTypes.size());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002694 }
2695
2696 return false;
2697 }
2698
Geoff Lang76b10c92014-09-05 16:28:14 -04002699 if (textureUnitTypes[unit] != GL_NONE)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002700 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002701 if (mSamplersVS[i].textureType != textureUnitTypes[unit])
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002702 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002703 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002704 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002705 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002706 }
2707
2708 return false;
2709 }
2710 }
2711 else
2712 {
Geoff Lang76b10c92014-09-05 16:28:14 -04002713 textureUnitTypes[unit] = mSamplersVS[i].textureType;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002714 }
2715 }
2716 }
2717
2718 return true;
2719}
2720
Geoff Lang76b10c92014-09-05 16:28:14 -04002721ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(GL_TEXTURE_2D)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002722{
2723}
2724
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002725struct AttributeSorter
2726{
2727 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2728 : originalIndices(semanticIndices)
2729 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002730 }
2731
2732 bool operator()(int a, int b)
2733 {
Jamie Madill03181ab2013-12-18 12:56:06 -05002734 if (originalIndices[a] == -1) return false;
2735 if (originalIndices[b] == -1) return true;
2736 return (originalIndices[a] < originalIndices[b]);
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002737 }
2738
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002739 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2740};
2741
Al Patrick3f2daa82013-08-07 12:58:57 -07002742void ProgramBinary::initAttributesByLayout()
2743{
2744 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2745 {
2746 mAttributesByLayout[i] = i;
2747 }
2748
2749 std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
2750}
2751
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002752void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2753{
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002754 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2755
2756 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2757 {
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002758 oldTranslatedAttributes[i] = attributes[i];
2759 }
2760
2761 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2762 {
Al Patrick3f2daa82013-08-07 12:58:57 -07002763 int oldIndex = mAttributesByLayout[i];
2764 sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002765 attributes[i] = oldTranslatedAttributes[oldIndex];
2766 }
2767}
2768
Geoff Lang04fb89a2014-06-09 15:05:36 -04002769void ProgramBinary::reset()
2770{
Geoff Lang04fb89a2014-06-09 15:05:36 -04002771 SafeDeleteContainer(mVertexExecutables);
Geoff Lang04fb89a2014-06-09 15:05:36 -04002772 SafeDeleteContainer(mPixelExecutables);
Geoff Lang04fb89a2014-06-09 15:05:36 -04002773 SafeDelete(mGeometryExecutable);
2774
2775 mTransformFeedbackBufferMode = GL_NONE;
2776 mTransformFeedbackLinkedVaryings.clear();
2777
Geoff Lang76b10c92014-09-05 16:28:14 -04002778 mSamplersPS.clear();
2779 mSamplersVS.clear();
2780
Geoff Lang04fb89a2014-06-09 15:05:36 -04002781 mUsedVertexSamplerRange = 0;
2782 mUsedPixelSamplerRange = 0;
Jamie Madilld4cfa572014-07-08 10:00:32 -04002783 mDirtySamplerMapping = true;
Geoff Lang04fb89a2014-06-09 15:05:36 -04002784
2785 SafeDeleteContainer(mUniforms);
2786 SafeDeleteContainer(mUniformBlocks);
2787 mUniformIndex.clear();
2788 mOutputVariables.clear();
Brandon Jonesc9610c52014-08-25 17:02:59 -07002789
2790 mProgram->reset();
Geoff Lang04fb89a2014-06-09 15:05:36 -04002791
2792 mValidated = false;
2793}
2794
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002795}