blob: 91c33bf9a4176e5a9ad90055653e1a07975bc708 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000026
daniel@transgaming.com88853c52012-12-20 20:56:40 +000027#undef near
28#undef far
29
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030namespace gl
31{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032std::string str(int i)
33{
34 char buffer[20];
35 snprintf(buffer, sizeof(buffer), "%d", i);
36 return buffer;
37}
38
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000039namespace
40{
41
42unsigned int parseAndStripArrayIndex(std::string* name)
43{
44 unsigned int subscript = GL_INVALID_INDEX;
45
46 // Strip any trailing array operator and retrieve the subscript
47 size_t open = name->find_last_of('[');
48 size_t close = name->find_last_of(']');
49 if (open != std::string::npos && close == name->length() - 1)
50 {
51 subscript = atoi(name->substr(open + 1).c_str());
52 name->erase(open);
53 }
54
55 return subscript;
56}
57
58}
59
daniel@transgaming.comdb019952012-12-20 21:13:32 +000060UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
61 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000062{
63}
64
daniel@transgaming.come87ca002012-07-24 18:30:43 +000065unsigned int ProgramBinary::mCurrentSerial = 1;
66
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000067ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000068{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000069 mPixelExecutable = NULL;
70 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000071 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000072
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000073 mValidated = false;
74
75 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
76 {
77 mSemanticIndex[index] = -1;
78 }
79
80 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
81 {
82 mSamplersPS[index].active = false;
83 }
84
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000085 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000086 {
87 mSamplersVS[index].active = false;
88 }
89
90 mUsedVertexSamplerRange = 0;
91 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000092 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000093}
94
95ProgramBinary::~ProgramBinary()
96{
daniel@transgaming.com95892412012-11-28 20:59:09 +000097 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000098 mPixelExecutable = NULL;
99
daniel@transgaming.com95892412012-11-28 20:59:09 +0000100 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000101 mVertexExecutable = NULL;
102
103 delete mGeometryExecutable;
104 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000105
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106 while (!mUniforms.empty())
107 {
108 delete mUniforms.back();
109 mUniforms.pop_back();
110 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000111
112 while (!mUniformBlocks.empty())
113 {
114 delete mUniformBlocks.back();
115 mUniformBlocks.pop_back();
116 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000117}
118
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000119unsigned int ProgramBinary::getSerial() const
120{
121 return mSerial;
122}
123
124unsigned int ProgramBinary::issueSerial()
125{
126 return mCurrentSerial++;
127}
128
daniel@transgaming.com95892412012-11-28 20:59:09 +0000129rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000130{
131 return mPixelExecutable;
132}
133
daniel@transgaming.com95892412012-11-28 20:59:09 +0000134rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135{
136 return mVertexExecutable;
137}
138
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000139rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
140{
141 return mGeometryExecutable;
142}
143
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000144GLuint ProgramBinary::getAttributeLocation(const char *name)
145{
146 if (name)
147 {
148 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
149 {
150 if (mLinkedAttribute[index].name == std::string(name))
151 {
152 return index;
153 }
154 }
155 }
156
157 return -1;
158}
159
160int ProgramBinary::getSemanticIndex(int attributeIndex)
161{
162 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
163
164 return mSemanticIndex[attributeIndex];
165}
166
167// Returns one more than the highest sampler index used.
168GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
169{
170 switch (type)
171 {
172 case SAMPLER_PIXEL:
173 return mUsedPixelSamplerRange;
174 case SAMPLER_VERTEX:
175 return mUsedVertexSamplerRange;
176 default:
177 UNREACHABLE();
178 return 0;
179 }
180}
181
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000182bool ProgramBinary::usesPointSize() const
183{
184 return mUsesPointSize;
185}
186
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000187bool ProgramBinary::usesPointSpriteEmulation() const
188{
189 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
190}
191
192bool ProgramBinary::usesGeometryShader() const
193{
194 return usesPointSpriteEmulation();
195}
196
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000197// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
198// index (0-15 for the pixel shader and 0-3 for the vertex shader).
199GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
200{
201 GLint logicalTextureUnit = -1;
202
203 switch (type)
204 {
205 case SAMPLER_PIXEL:
206 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
207
208 if (mSamplersPS[samplerIndex].active)
209 {
210 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
211 }
212 break;
213 case SAMPLER_VERTEX:
214 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
215
216 if (mSamplersVS[samplerIndex].active)
217 {
218 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
219 }
220 break;
221 default: UNREACHABLE();
222 }
223
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000224 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000225 {
226 return logicalTextureUnit;
227 }
228
229 return -1;
230}
231
232// Returns the texture type for a given Direct3D 9 sampler type and
233// index (0-15 for the pixel shader and 0-3 for the vertex shader).
234TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
235{
236 switch (type)
237 {
238 case SAMPLER_PIXEL:
239 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
240 ASSERT(mSamplersPS[samplerIndex].active);
241 return mSamplersPS[samplerIndex].textureType;
242 case SAMPLER_VERTEX:
243 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
244 ASSERT(mSamplersVS[samplerIndex].active);
245 return mSamplersVS[samplerIndex].textureType;
246 default: UNREACHABLE();
247 }
248
249 return TEXTURE_2D;
250}
251
252GLint ProgramBinary::getUniformLocation(std::string name)
253{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000254 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000255
256 unsigned int numUniforms = mUniformIndex.size();
257 for (unsigned int location = 0; location < numUniforms; location++)
258 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000259 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000260 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000261 const int index = mUniformIndex[location].index;
262 const bool isArray = mUniforms[index]->isArray();
263
264 if ((isArray && mUniformIndex[location].element == subscript) ||
265 (subscript == GL_INVALID_INDEX))
266 {
267 return location;
268 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000269 }
270 }
271
272 return -1;
273}
274
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000275GLuint ProgramBinary::getUniformIndex(std::string name)
276{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000277 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000278
279 // The app is not allowed to specify array indices other than 0 for arrays of basic types
280 if (subscript != 0 && subscript != GL_INVALID_INDEX)
281 {
282 return GL_INVALID_INDEX;
283 }
284
285 unsigned int numUniforms = mUniforms.size();
286 for (unsigned int index = 0; index < numUniforms; index++)
287 {
288 if (mUniforms[index]->name == name)
289 {
290 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
291 {
292 return index;
293 }
294 }
295 }
296
297 return GL_INVALID_INDEX;
298}
299
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000300GLuint ProgramBinary::getUniformBlockIndex(std::string name)
301{
302 unsigned int subscript = parseAndStripArrayIndex(&name);
303
304 unsigned int numUniformBlocks = mUniformBlocks.size();
305 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
306 {
307 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
308 if (uniformBlock.name == name)
309 {
310 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
311 if (subscript == uniformBlock.elementIndex || arrayElementZero)
312 {
313 return blockIndex;
314 }
315 }
316 }
317
318 return GL_INVALID_INDEX;
319}
320
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000321UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
322{
323 ASSERT(blockIndex < mUniformBlocks.size());
324 return mUniformBlocks[blockIndex];
325}
326
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000327template <typename T>
328bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000329{
330 if (location < 0 || location >= (int)mUniformIndex.size())
331 {
332 return false;
333 }
334
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000335 const int components = UniformComponentCount(targetUniformType);
336 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
337
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000338 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
339 targetUniform->dirty = true;
340
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000341 int elementCount = targetUniform->elementCount();
342
343 if (elementCount == 1 && count > 1)
344 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
345
346 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
347
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000348 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000349 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000350 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000351
352 for (int i = 0; i < count; i++)
353 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000354 for (int c = 0; c < components; c++)
355 {
356 target[c] = v[c];
357 }
358 for (int c = components; c < 4; c++)
359 {
360 target[c] = 0;
361 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000362 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000363 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000364 }
365 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000366 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000367 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000368 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000369
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000370 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000371 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000372 for (int c = 0; c < components; c++)
373 {
374 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
375 }
376 for (int c = components; c < 4; c++)
377 {
378 boolParams[c] = GL_FALSE;
379 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000380 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000381 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000382 }
383 }
384 else
385 {
386 return false;
387 }
388
389 return true;
390}
391
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000392bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
393{
394 return setUniform(location, count, v, GL_FLOAT);
395}
396
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000397bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
398{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000399 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000400}
401
402bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
403{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000404 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000405}
406
407bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
408{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000409 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000410}
411
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000412template<typename T>
413void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000414{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000415 int copyWidth = std::min(targetHeight, srcWidth);
416 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000417
418 for (int x = 0; x < copyWidth; x++)
419 {
420 for (int y = 0; y < copyHeight; y++)
421 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000422 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000423 }
424 }
425 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000426 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000427 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000428 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000429 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000430 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000431 }
432 }
433 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000434 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000435 {
436 for (int x = 0; x < targetWidth; x++)
437 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000438 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000439 }
440 }
441}
442
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000443template<typename T>
444void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
445{
446 int copyWidth = std::min(targetWidth, srcWidth);
447 int copyHeight = std::min(targetHeight, srcHeight);
448
449 for (int y = 0; y < copyHeight; y++)
450 {
451 for (int x = 0; x < copyWidth; x++)
452 {
453 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
454 }
455 }
456 // clear unfilled right side
457 for (int y = 0; y < copyHeight; y++)
458 {
459 for (int x = copyWidth; x < targetWidth; x++)
460 {
461 target[y * targetWidth + x] = static_cast<T>(0);
462 }
463 }
464 // clear unfilled bottom.
465 for (int y = copyHeight; y < targetHeight; y++)
466 {
467 for (int x = 0; x < targetWidth; x++)
468 {
469 target[y * targetWidth + x] = static_cast<T>(0);
470 }
471 }
472}
473
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000474template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000475bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000476{
477 if (location < 0 || location >= (int)mUniformIndex.size())
478 {
479 return false;
480 }
481
482 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
483 targetUniform->dirty = true;
484
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000485 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000486 {
487 return false;
488 }
489
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000490 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000491
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000492 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000493 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
494
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000495 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000496 const unsigned int targetMatrixStride = (4 * rows);
497 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000498
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000499 for (int i = 0; i < count; i++)
500 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000501 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
502 if (transpose == GL_FALSE)
503 {
504 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
505 }
506 else
507 {
508 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
509 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000510 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000511 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000512 }
513
514 return true;
515}
516
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000517bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000518{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000519 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000520}
521
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000522bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000523{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000524 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000525}
526
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000527bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000528{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000529 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000530}
531
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000532bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000533{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000534 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000535}
536
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000537bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000538{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000539 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000540}
541
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000542bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000543{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000544 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000545}
546
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000547bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000548{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000549 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000550}
551
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000552bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000553{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000554 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000555}
556
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000557bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000558{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000559 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000560}
561
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000562bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
563{
564 if (location < 0 || location >= (int)mUniformIndex.size())
565 {
566 return false;
567 }
568
569 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
570 targetUniform->dirty = true;
571
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000572 int elementCount = targetUniform->elementCount();
573
574 if (elementCount == 1 && count > 1)
575 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
576
577 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
578
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000579 if (targetUniform->type == GL_INT ||
580 targetUniform->type == GL_SAMPLER_2D ||
581 targetUniform->type == GL_SAMPLER_CUBE)
582 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000583 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000584
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000585 for (int i = 0; i < count; i++)
586 {
587 target[0] = v[0];
588 target[1] = 0;
589 target[2] = 0;
590 target[3] = 0;
591 target += 4;
592 v += 1;
593 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000594 }
595 else if (targetUniform->type == GL_BOOL)
596 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000597 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000598
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000599 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000600 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000601 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
602 boolParams[1] = GL_FALSE;
603 boolParams[2] = GL_FALSE;
604 boolParams[3] = GL_FALSE;
605 boolParams += 4;
606 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000607 }
608 }
609 else
610 {
611 return false;
612 }
613
614 return true;
615}
616
617bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
618{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000619 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000620}
621
622bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
623{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000624 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000625}
626
627bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
628{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000629 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000630}
631
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000632bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
633{
634 return setUniform(location, count, v, GL_UNSIGNED_INT);
635}
636
637bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
638{
639 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
640}
641
642bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
643{
644 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
645}
646
647bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
648{
649 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
650}
651
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000652template <typename T>
653bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000654{
655 if (location < 0 || location >= (int)mUniformIndex.size())
656 {
657 return false;
658 }
659
660 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
661
662 // sized queries -- ensure the provided buffer is large enough
663 if (bufSize)
664 {
665 int requiredBytes = UniformExternalSize(targetUniform->type);
666 if (*bufSize < requiredBytes)
667 {
668 return false;
669 }
670 }
671
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000672 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000673 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000674 const int rows = VariableRowCount(targetUniform->type);
675 const int cols = VariableColumnCount(targetUniform->type);
676 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
677 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000678 else if (uniformType == UniformComponentType(targetUniform->type))
679 {
680 unsigned int size = UniformComponentCount(targetUniform->type);
681 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
682 size * sizeof(T));
683 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000684 else
685 {
686 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000687 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000688 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000689 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000690 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000691 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000692
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000693 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000694 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000695 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000696 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000697 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000698 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000699
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000700 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000701 {
702 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
703
704 for (unsigned int i = 0; i < size; i++)
705 {
706 params[i] = static_cast<T>(floatParams[i]);
707 }
708 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000709 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000710
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000711 case GL_INT:
712 {
713 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
714
715 for (unsigned int i = 0; i < size; i++)
716 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000717 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000718 }
719 }
720 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000721
722 case GL_UNSIGNED_INT:
723 {
724 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000725
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000726 for (unsigned int i = 0; i < size; i++)
727 {
728 params[i] = static_cast<T>(uintParams[i]);
729 }
730 }
731 break;
732
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000733 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000734 }
735 }
736
737 return true;
738}
739
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000740bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
741{
742 return getUniformv(location, bufSize, params, GL_FLOAT);
743}
744
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000745bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
746{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000747 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000748}
749
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000750bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
751{
752 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
753}
754
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000755void ProgramBinary::dirtyAllUniforms()
756{
757 unsigned int numUniforms = mUniforms.size();
758 for (unsigned int index = 0; index < numUniforms; index++)
759 {
760 mUniforms[index]->dirty = true;
761 }
762}
763
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000764// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000765void ProgramBinary::applyUniforms()
766{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000767 // Retrieve sampler uniform values
768 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
769 {
770 Uniform *targetUniform = *ub;
771
772 if (targetUniform->dirty)
773 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000774 if (targetUniform->type == GL_SAMPLER_2D ||
775 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000776 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000777 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000778 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000779
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000780 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000781 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000782 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000783
784 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000785 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000786 unsigned int samplerIndex = firstIndex + i;
787
788 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000789 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000790 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000791 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000792 }
793 }
794 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000795
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000796 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000797 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000798 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000799
800 for (int i = 0; i < count; i++)
801 {
802 unsigned int samplerIndex = firstIndex + i;
803
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000804 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000805 {
806 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000807 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000808 }
809 }
810 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000811 }
812 }
813 }
814
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000815 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000816}
817
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000818bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
819{
820 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
821 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
822
823 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
824 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
825
826 ASSERT(boundBuffers.size() == mUniformBlocks.size());
827
828 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
829 {
830 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
831 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
832
833 ASSERT(uniformBlock && uniformBuffer);
834
835 if (uniformBuffer->size() < uniformBlock->dataSize)
836 {
837 // undefined behaviour
838 return false;
839 }
840
841 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
842
843 if (uniformBlock->isReferencedByVertexShader())
844 {
845 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
846 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
847 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
848 vertexUniformBuffers[registerIndex] = uniformBuffer;
849 }
850
851 if (uniformBlock->isReferencedByFragmentShader())
852 {
853 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
854 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
855 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
856 fragmentUniformBuffers[registerIndex] = uniformBuffer;
857 }
858 }
859
860 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
861}
862
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000863// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
864// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000865int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000866{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000867 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000868
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000869 fragmentShader->resetVaryingsRegisterAssignment();
870
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000871 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
872 {
873 int n = VariableRowCount(varying->type) * varying->size;
874 int m = VariableColumnCount(varying->type);
875 bool success = false;
876
877 if (m == 2 || m == 3 || m == 4)
878 {
879 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
880 {
881 bool available = true;
882
883 for (int y = 0; y < n && available; y++)
884 {
885 for (int x = 0; x < m && available; x++)
886 {
887 if (packing[r + y][x])
888 {
889 available = false;
890 }
891 }
892 }
893
894 if (available)
895 {
896 varying->reg = r;
897 varying->col = 0;
898
899 for (int y = 0; y < n; y++)
900 {
901 for (int x = 0; x < m; x++)
902 {
903 packing[r + y][x] = &*varying;
904 }
905 }
906
907 success = true;
908 }
909 }
910
911 if (!success && m == 2)
912 {
913 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
914 {
915 bool available = true;
916
917 for (int y = 0; y < n && available; y++)
918 {
919 for (int x = 2; x < 4 && available; x++)
920 {
921 if (packing[r + y][x])
922 {
923 available = false;
924 }
925 }
926 }
927
928 if (available)
929 {
930 varying->reg = r;
931 varying->col = 2;
932
933 for (int y = 0; y < n; y++)
934 {
935 for (int x = 2; x < 4; x++)
936 {
937 packing[r + y][x] = &*varying;
938 }
939 }
940
941 success = true;
942 }
943 }
944 }
945 }
946 else if (m == 1)
947 {
948 int space[4] = {0};
949
950 for (int y = 0; y < maxVaryingVectors; y++)
951 {
952 for (int x = 0; x < 4; x++)
953 {
954 space[x] += packing[y][x] ? 0 : 1;
955 }
956 }
957
958 int column = 0;
959
960 for (int x = 0; x < 4; x++)
961 {
962 if (space[x] >= n && space[x] < space[column])
963 {
964 column = x;
965 }
966 }
967
968 if (space[column] >= n)
969 {
970 for (int r = 0; r < maxVaryingVectors; r++)
971 {
972 if (!packing[r][column])
973 {
974 varying->reg = r;
975
976 for (int y = r; y < r + n; y++)
977 {
978 packing[y][column] = &*varying;
979 }
980
981 break;
982 }
983 }
984
985 varying->col = column;
986
987 success = true;
988 }
989 }
990 else UNREACHABLE();
991
992 if (!success)
993 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000994 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000995
996 return -1;
997 }
998 }
999
1000 // Return the number of used registers
1001 int registers = 0;
1002
1003 for (int r = 0; r < maxVaryingVectors; r++)
1004 {
1005 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1006 {
1007 registers++;
1008 }
1009 }
1010
1011 return registers;
1012}
1013
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001014bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1015 std::string& pixelHLSL, std::string& vertexHLSL,
1016 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001017{
1018 if (pixelHLSL.empty() || vertexHLSL.empty())
1019 {
1020 return false;
1021 }
1022
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001023 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1024 bool usesFragColor = fragmentShader->mUsesFragColor;
1025 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001026 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001027 {
1028 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1029 return false;
1030 }
1031
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001032 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001033 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001034 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001035
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001036 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1037
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001038 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1039 // - with a 3.0 context, the output color is copied to channel 0
1040 // - with a 2.0 context, the output color is broadcast to all channels
1041 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1042 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1043
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001044 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001045 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001046 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001047
1048 return false;
1049 }
1050
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001051 vertexShader->resetVaryingsRegisterAssignment();
1052
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001053 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1054 {
1055 bool matched = false;
1056
1057 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1058 {
1059 if (output->name == input->name)
1060 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001061 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001062 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001063 infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001064
1065 return false;
1066 }
1067
1068 output->reg = input->reg;
1069 output->col = input->col;
1070
1071 matched = true;
1072 break;
1073 }
1074 }
1075
1076 if (!matched)
1077 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001078 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001079
1080 return false;
1081 }
1082 }
1083
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001084 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001085 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001086 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001087 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1088
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001089 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1090
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001091 // special varyings that use reserved registers
1092 int reservedRegisterIndex = registers;
1093 std::string fragCoordSemantic;
1094 std::string pointCoordSemantic;
1095
1096 if (fragmentShader->mUsesFragCoord)
1097 {
1098 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1099 }
1100
1101 if (fragmentShader->mUsesPointCoord)
1102 {
1103 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1104 // In DX11 we compute this in the GS.
1105 if (shaderModel == 3)
1106 {
1107 pointCoordSemantic = "TEXCOORD0";
1108 }
1109 else if (shaderModel >= 4)
1110 {
1111 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1112 }
1113 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001114
1115 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001116 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001117
1118 int semanticIndex = 0;
1119 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1120 {
1121 switch (attribute->type)
1122 {
1123 case GL_FLOAT: vertexHLSL += " float "; break;
1124 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1125 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1126 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1127 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1128 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1129 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1130 default: UNREACHABLE();
1131 }
1132
1133 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1134
1135 semanticIndex += VariableRowCount(attribute->type);
1136 }
1137
1138 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001139 "\n"
1140 "struct VS_OUTPUT\n"
1141 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001142
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001143 if (shaderModel < 4)
1144 {
1145 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1146 }
1147
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001148 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001149
1150 if (fragmentShader->mUsesFragCoord)
1151 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001152 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001153 }
1154
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001155 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001156 {
1157 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1158 }
1159
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001160 if (shaderModel >= 4)
1161 {
1162 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1163 }
1164
1165 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001166 "\n"
1167 "VS_OUTPUT main(VS_INPUT input)\n"
1168 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001169
1170 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1171 {
1172 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1173
1174 if (VariableRowCount(attribute->type) > 1) // Matrix
1175 {
1176 vertexHLSL += "transpose";
1177 }
1178
1179 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1180 }
1181
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001182 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1183 {
1184 vertexHLSL += "\n"
1185 " dx_initConstantBuffers();\n";
1186 }
1187
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001188 if (shaderModel >= 4)
1189 {
1190 vertexHLSL += "\n"
1191 " gl_main();\n"
1192 "\n"
1193 " VS_OUTPUT output;\n"
1194 " output.gl_Position.x = gl_Position.x;\n"
1195 " output.gl_Position.y = -gl_Position.y;\n"
1196 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1197 " output.gl_Position.w = gl_Position.w;\n";
1198 }
1199 else
1200 {
1201 vertexHLSL += "\n"
1202 " gl_main();\n"
1203 "\n"
1204 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001205 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1206 " output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001207 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1208 " output.gl_Position.w = gl_Position.w;\n";
1209 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001210
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001211 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001212 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001213 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001214 }
1215
1216 if (fragmentShader->mUsesFragCoord)
1217 {
1218 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1219 }
1220
1221 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1222 {
1223 if (varying->reg >= 0)
1224 {
1225 for (int i = 0; i < varying->size; i++)
1226 {
1227 int rows = VariableRowCount(varying->type);
1228
1229 for (int j = 0; j < rows; j++)
1230 {
1231 int r = varying->reg + i * rows + j;
1232 vertexHLSL += " output.v" + str(r);
1233
1234 bool sharedRegister = false; // Register used by multiple varyings
1235
1236 for (int x = 0; x < 4; x++)
1237 {
1238 if (packing[r][x] && packing[r][x] != packing[r][0])
1239 {
1240 sharedRegister = true;
1241 break;
1242 }
1243 }
1244
1245 if(sharedRegister)
1246 {
1247 vertexHLSL += ".";
1248
1249 for (int x = 0; x < 4; x++)
1250 {
1251 if (packing[r][x] == &*varying)
1252 {
1253 switch(x)
1254 {
1255 case 0: vertexHLSL += "x"; break;
1256 case 1: vertexHLSL += "y"; break;
1257 case 2: vertexHLSL += "z"; break;
1258 case 3: vertexHLSL += "w"; break;
1259 }
1260 }
1261 }
1262 }
1263
1264 vertexHLSL += " = " + varying->name;
1265
1266 if (varying->array)
1267 {
1268 vertexHLSL += "[" + str(i) + "]";
1269 }
1270
1271 if (rows > 1)
1272 {
1273 vertexHLSL += "[" + str(j) + "]";
1274 }
1275
1276 vertexHLSL += ";\n";
1277 }
1278 }
1279 }
1280 }
1281
1282 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001283 " return output;\n"
1284 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001285
1286 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001287 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001288
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001289 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001290
1291 if (fragmentShader->mUsesFragCoord)
1292 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001293 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001294 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001295
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001296 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1297 {
1298 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1299 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001300
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001301 // Must consume the PSIZE element if the geometry shader is not active
1302 // We won't know if we use a GS until we draw
1303 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1304 {
1305 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1306 }
1307
1308 if (fragmentShader->mUsesFragCoord)
1309 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001310 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001311 {
1312 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1313 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001314 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001315 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001316 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1317 }
1318 }
1319
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001320 pixelHLSL += "};\n"
1321 "\n"
1322 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001323 "{\n";
1324
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001325 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001326 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001327 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001328 }
1329
1330 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001331 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001332
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001333 if (fragmentShader->mUsesFrontFacing)
1334 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001335 if (shaderModel >= 4)
1336 {
1337 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1338 "{\n";
1339 }
1340 else
1341 {
1342 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1343 "{\n";
1344 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001345 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001346 else
1347 {
1348 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1349 "{\n";
1350 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001351
1352 if (fragmentShader->mUsesFragCoord)
1353 {
1354 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1355
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001356 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001357 {
1358 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1359 " gl_FragCoord.y = input.dx_VPos.y;\n";
1360 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001361 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001362 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001363 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001364 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001365 }
1366 else
1367 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001368 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1369 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1370 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001371 }
1372
daniel@transgaming.com12985182012-12-20 20:56:31 +00001373 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001374 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001375 }
1376
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001377 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001378 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001379 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1380 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001381 }
1382
1383 if (fragmentShader->mUsesFrontFacing)
1384 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001385 if (shaderModel <= 3)
1386 {
1387 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1388 }
1389 else
1390 {
1391 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1392 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001393 }
1394
1395 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1396 {
1397 if (varying->reg >= 0)
1398 {
1399 for (int i = 0; i < varying->size; i++)
1400 {
1401 int rows = VariableRowCount(varying->type);
1402 for (int j = 0; j < rows; j++)
1403 {
1404 std::string n = str(varying->reg + i * rows + j);
1405 pixelHLSL += " " + varying->name;
1406
1407 if (varying->array)
1408 {
1409 pixelHLSL += "[" + str(i) + "]";
1410 }
1411
1412 if (rows > 1)
1413 {
1414 pixelHLSL += "[" + str(j) + "]";
1415 }
1416
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001417 switch (VariableColumnCount(varying->type))
1418 {
1419 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1420 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1421 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1422 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1423 default: UNREACHABLE();
1424 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001425 }
1426 }
1427 }
1428 else UNREACHABLE();
1429 }
1430
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001431 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1432 {
1433 pixelHLSL += "\n"
1434 " dx_initConstantBuffers();\n";
1435 }
1436
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001437 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001438 " gl_main();\n"
1439 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001440 " PS_OUTPUT output;\n";
1441
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001442 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001443 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001444 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001445
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001446 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001447 }
1448
1449 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001450 " return output;\n"
1451 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001452
1453 return true;
1454}
1455
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001456std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1457{
1458 std::string varyingHLSL;
1459
1460 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1461 {
1462 if (varying->reg >= 0)
1463 {
1464 for (int i = 0; i < varying->size; i++)
1465 {
1466 int rows = VariableRowCount(varying->type);
1467 for (int j = 0; j < rows; j++)
1468 {
1469 switch (varying->interpolation)
1470 {
1471 case Smooth: varyingHLSL += " "; break;
1472 case Flat: varyingHLSL += " nointerpolation "; break;
1473 case Centroid: varyingHLSL += " centroid "; break;
1474 default: UNREACHABLE();
1475 }
1476
1477 std::string n = str(varying->reg + i * rows + j);
1478 varyingHLSL += "float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
1479 }
1480 }
1481 }
1482 else UNREACHABLE();
1483 }
1484
1485 return varyingHLSL;
1486}
1487
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001488bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1489{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001490 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001491
1492 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001493 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001494 if (format != GL_PROGRAM_BINARY_ANGLE)
1495 {
1496 infoLog.append("Invalid program binary format.");
1497 return false;
1498 }
1499
1500 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001501 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001502 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001503 {
1504 infoLog.append("Invalid program binary version.");
1505 return false;
1506 }
1507
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001508 int compileFlags = 0;
1509 stream.read(&compileFlags);
1510 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1511 {
1512 infoLog.append("Mismatched compilation flags.");
1513 return false;
1514 }
1515
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001516 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1517 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001518 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001519 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001520 stream.read(&name);
1521 mLinkedAttribute[i].name = name;
1522 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001523 }
1524
1525 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1526 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001527 stream.read(&mSamplersPS[i].active);
1528 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001529
1530 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001531 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001532 mSamplersPS[i].textureType = (TextureType) textureType;
1533 }
1534
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001535 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001536 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001537 stream.read(&mSamplersVS[i].active);
1538 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001539
1540 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001541 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001542 mSamplersVS[i].textureType = (TextureType) textureType;
1543 }
1544
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001545 stream.read(&mUsedVertexSamplerRange);
1546 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001547 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001548
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001549 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001550 stream.read(&size);
1551 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001552 {
1553 infoLog.append("Invalid program binary.");
1554 return false;
1555 }
1556
1557 mUniforms.resize(size);
1558 for (unsigned int i = 0; i < size; ++i)
1559 {
1560 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001561 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001562 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001563 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001564 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001565
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001566 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001567 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001568 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001569 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001570 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001571
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001572 int offset;
1573 int arrayStride;
1574 int matrixStride;
1575 bool isRowMajorMatrix;
1576
1577 stream.read(&offset);
1578 stream.read(&arrayStride);
1579 stream.read(&matrixStride);
1580 stream.read(&isRowMajorMatrix);
1581
1582 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1583
1584 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001585
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001586 stream.read(&mUniforms[i]->psRegisterIndex);
1587 stream.read(&mUniforms[i]->vsRegisterIndex);
1588 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001589 }
1590
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001591 stream.read(&size);
1592 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001593 {
1594 infoLog.append("Invalid program binary.");
1595 return false;
1596 }
1597
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001598 mUniformBlocks.resize(size);
1599 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1600 {
1601 std::string name;
1602 unsigned int elementIndex;
1603 unsigned int dataSize;
1604
1605 stream.read(&name);
1606 stream.read(&elementIndex);
1607 stream.read(&dataSize);
1608
1609 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1610
1611 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1612 stream.read(&uniformBlock.psRegisterIndex);
1613 stream.read(&uniformBlock.vsRegisterIndex);
1614
1615 size_t numMembers;
1616 stream.read(&numMembers);
1617 uniformBlock.memberUniformIndexes.resize(numMembers);
1618 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1619 {
1620 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1621 }
1622 }
1623
1624 stream.read(&size);
1625 if (stream.error())
1626 {
1627 infoLog.append("Invalid program binary.");
1628 return false;
1629 }
1630
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631 mUniformIndex.resize(size);
1632 for (unsigned int i = 0; i < size; ++i)
1633 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001634 stream.read(&mUniformIndex[i].name);
1635 stream.read(&mUniformIndex[i].element);
1636 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001637 }
1638
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001639 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001640 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641
1642 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001643 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001644
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001645 unsigned int geometryShaderSize;
1646 stream.read(&geometryShaderSize);
1647
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001648 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001649
daniel@transgaming.com36038542012-11-28 20:59:26 +00001650 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651 ptr += sizeof(GUID);
1652
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001653 GUID identifier = mRenderer->getAdapterIdentifier();
1654 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655 {
1656 infoLog.append("Invalid program binary.");
1657 return false;
1658 }
1659
1660 const char *pixelShaderFunction = ptr;
1661 ptr += pixelShaderSize;
1662
1663 const char *vertexShaderFunction = ptr;
1664 ptr += vertexShaderSize;
1665
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001666 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1667 ptr += geometryShaderSize;
1668
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001669 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001670 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001671 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001672 {
1673 infoLog.append("Could not create pixel shader.");
1674 return false;
1675 }
1676
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001677 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001678 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001679 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001680 {
1681 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001682 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001683 mPixelExecutable = NULL;
1684 return false;
1685 }
1686
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001687 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1688 {
1689 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1690 geometryShaderSize, rx::SHADER_GEOMETRY);
1691 if (!mGeometryExecutable)
1692 {
1693 infoLog.append("Could not create geometry shader.");
1694 delete mPixelExecutable;
1695 mPixelExecutable = NULL;
1696 delete mVertexExecutable;
1697 mVertexExecutable = NULL;
1698 return false;
1699 }
1700 }
1701 else
1702 {
1703 mGeometryExecutable = NULL;
1704 }
1705
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001706 return true;
1707}
1708
1709bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1710{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001711 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001713 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001714 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001715 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001716
1717 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1718 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001719 stream.write(mLinkedAttribute[i].type);
1720 stream.write(mLinkedAttribute[i].name);
1721 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001722 }
1723
1724 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1725 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001726 stream.write(mSamplersPS[i].active);
1727 stream.write(mSamplersPS[i].logicalTextureUnit);
1728 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 }
1730
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001731 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001732 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001733 stream.write(mSamplersVS[i].active);
1734 stream.write(mSamplersVS[i].logicalTextureUnit);
1735 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001736 }
1737
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001738 stream.write(mUsedVertexSamplerRange);
1739 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001740 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001741
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001742 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001743 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001744 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001745 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001746
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001747 stream.write(uniform.type);
1748 stream.write(uniform.precision);
1749 stream.write(uniform.name);
1750 stream.write(uniform.arraySize);
1751 stream.write(uniform.blockIndex);
1752
1753 stream.write(uniform.blockInfo.offset);
1754 stream.write(uniform.blockInfo.arrayStride);
1755 stream.write(uniform.blockInfo.matrixStride);
1756 stream.write(uniform.blockInfo.isRowMajorMatrix);
1757
1758 stream.write(uniform.psRegisterIndex);
1759 stream.write(uniform.vsRegisterIndex);
1760 stream.write(uniform.registerCount);
1761 }
1762
1763 stream.write(mUniformBlocks.size());
1764 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1765 {
1766 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1767
1768 stream.write(uniformBlock.name);
1769 stream.write(uniformBlock.elementIndex);
1770 stream.write(uniformBlock.dataSize);
1771
1772 stream.write(uniformBlock.memberUniformIndexes.size());
1773 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1774 {
1775 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1776 }
1777
1778 stream.write(uniformBlock.psRegisterIndex);
1779 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001780 }
1781
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001782 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001783 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1784 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001785 stream.write(mUniformIndex[i].name);
1786 stream.write(mUniformIndex[i].element);
1787 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788 }
1789
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001790 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001791 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001792
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001793 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001794 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001795
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001796 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1797 stream.write(geometryShaderSize);
1798
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001799 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001800
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001801 GLsizei streamLength = stream.length();
1802 const void *streamData = stream.data();
1803
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001804 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805 if (totalLength > bufSize)
1806 {
1807 if (length)
1808 {
1809 *length = 0;
1810 }
1811
1812 return false;
1813 }
1814
1815 if (binary)
1816 {
1817 char *ptr = (char*) binary;
1818
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001819 memcpy(ptr, streamData, streamLength);
1820 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001821
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001822 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001823 ptr += sizeof(GUID);
1824
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001825 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001826 ptr += pixelShaderSize;
1827
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001828 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 ptr += vertexShaderSize;
1830
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001831 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1832 {
1833 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1834 ptr += geometryShaderSize;
1835 }
1836
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001837 ASSERT(ptr - totalLength == binary);
1838 }
1839
1840 if (length)
1841 {
1842 *length = totalLength;
1843 }
1844
1845 return true;
1846}
1847
1848GLint ProgramBinary::getLength()
1849{
1850 GLint length;
1851 if (save(NULL, INT_MAX, &length))
1852 {
1853 return length;
1854 }
1855 else
1856 {
1857 return 0;
1858 }
1859}
1860
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001861bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001862{
1863 if (!fragmentShader || !fragmentShader->isCompiled())
1864 {
1865 return false;
1866 }
1867
1868 if (!vertexShader || !vertexShader->isCompiled())
1869 {
1870 return false;
1871 }
1872
1873 std::string pixelHLSL = fragmentShader->getHLSL();
1874 std::string vertexHLSL = vertexShader->getHLSL();
1875
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001876 // Map the varyings to the register file
1877 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1878 int registers = packVaryings(infoLog, packing, fragmentShader);
1879
1880 if (registers < 0)
1881 {
1882 return false;
1883 }
1884
1885 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001886 {
1887 return false;
1888 }
1889
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001890 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001891 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1892 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001893
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001894 if (usesGeometryShader())
1895 {
1896 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1897 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1898 }
1899
1900 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001901 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001902 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001903 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001904
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001905 delete mVertexExecutable;
1906 mVertexExecutable = NULL;
1907 delete mPixelExecutable;
1908 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001909 delete mGeometryExecutable;
1910 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001911 }
1912
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001913 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1914 {
1915 success = false;
1916 }
1917
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001918 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001919 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001920 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001921 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001922
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001923 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1924 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1925 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001926 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1927 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1928 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001929 }
1930
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001931 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1932 {
1933 success = false;
1934 }
1935
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001936 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001937}
1938
1939// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001940bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001941{
1942 unsigned int usedLocations = 0;
1943
1944 // Link attributes that have a binding location
1945 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1946 {
1947 int location = attributeBindings.getAttributeBinding(attribute->name);
1948
1949 if (location != -1) // Set by glBindAttribLocation
1950 {
1951 if (!mLinkedAttribute[location].name.empty())
1952 {
1953 // Multiple active attributes bound to the same location; not an error
1954 }
1955
1956 mLinkedAttribute[location] = *attribute;
1957
1958 int rows = VariableRowCount(attribute->type);
1959
1960 if (rows + location > MAX_VERTEX_ATTRIBS)
1961 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001962 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 +00001963
1964 return false;
1965 }
1966
1967 for (int i = 0; i < rows; i++)
1968 {
1969 usedLocations |= 1 << (location + i);
1970 }
1971 }
1972 }
1973
1974 // Link attributes that don't have a binding location
1975 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1976 {
1977 int location = attributeBindings.getAttributeBinding(attribute->name);
1978
1979 if (location == -1) // Not set by glBindAttribLocation
1980 {
1981 int rows = VariableRowCount(attribute->type);
1982 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1983
1984 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1985 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001986 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001987
1988 return false; // Fail to link
1989 }
1990
1991 mLinkedAttribute[availableIndex] = *attribute;
1992 }
1993 }
1994
1995 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1996 {
1997 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1998 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1999
2000 for (int r = 0; r < rows; r++)
2001 {
2002 mSemanticIndex[attributeIndex++] = index++;
2003 }
2004 }
2005
2006 return true;
2007}
2008
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002009bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2010{
2011 if (vertexUniform.type != fragmentUniform.type)
2012 {
2013 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2014 return false;
2015 }
2016 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2017 {
2018 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2019 return false;
2020 }
2021 else if (vertexUniform.precision != fragmentUniform.precision)
2022 {
2023 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2024 return false;
2025 }
2026 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2027 {
2028 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2029 }
2030
2031 const unsigned int numMembers = vertexUniform.fields.size();
2032 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2033 {
2034 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2035 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2036
2037 if (vertexMember.name != fragmentMember.name)
2038 {
2039 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2040 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2041 return false;
2042 }
2043
2044 const std::string memberName = uniformName + "." + vertexUniform.name;
2045 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2046 {
2047 return false;
2048 }
2049 }
2050
2051 return true;
2052}
2053
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002054bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002055{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002056 // Check that uniforms defined in the vertex and fragment shaders are identical
2057 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2058 UniformMap linkedUniforms;
2059
2060 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2061 {
2062 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2063 linkedUniforms[vertexUniform.name] = &vertexUniform;
2064 }
2065
2066 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2067 {
2068 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2069 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2070 if (entry != linkedUniforms.end())
2071 {
2072 const sh::Uniform &vertexUniform = *entry->second;
2073 const std::string &uniformName = "uniform " + vertexUniform.name;
2074 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2075 {
2076 return false;
2077 }
2078 }
2079 }
2080
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002081 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002083 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002084 {
2085 return false;
2086 }
2087 }
2088
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002089 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002090 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002091 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002092 {
2093 return false;
2094 }
2095 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002096
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002097 return true;
2098}
2099
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002100int totalRegisterCount(const sh::Uniform &uniform)
2101{
2102 int registerCount = 0;
2103
2104 if (!uniform.fields.empty())
2105 {
2106 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2107 {
2108 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2109 }
2110 }
2111 else
2112 {
2113 registerCount = 1;
2114 }
2115
2116 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2117}
2118
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002119bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002120{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002121 if (!constant.fields.empty())
2122 {
2123 if (constant.arraySize > 0)
2124 {
2125 unsigned int elementRegisterIndex = constant.registerIndex;
2126
2127 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2128 {
2129 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2130 {
2131 const sh::Uniform &field = constant.fields[fieldIndex];
2132 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2133 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2134 if (!defineUniform(shader, fieldUniform, infoLog))
2135 {
2136 return false;
2137 }
2138 elementRegisterIndex += totalRegisterCount(field);
2139 }
2140 }
2141 }
2142 else
2143 {
2144 unsigned int fieldRegisterIndex = constant.registerIndex;
2145
2146 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2147 {
2148 const sh::Uniform &field = constant.fields[fieldIndex];
2149 const std::string &uniformName = constant.name + "." + field.name;
2150
2151 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2152 fieldUniform.fields = field.fields;
2153
2154 if (!defineUniform(shader, fieldUniform, infoLog))
2155 {
2156 return false;
2157 }
2158 fieldRegisterIndex += totalRegisterCount(field);
2159 }
2160 }
2161
2162 return true;
2163 }
2164
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002165 if (constant.type == GL_SAMPLER_2D ||
2166 constant.type == GL_SAMPLER_CUBE)
2167 {
2168 unsigned int samplerIndex = constant.registerIndex;
2169
2170 do
2171 {
2172 if (shader == GL_VERTEX_SHADER)
2173 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002174 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002175 {
2176 mSamplersVS[samplerIndex].active = true;
2177 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2178 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2179 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2180 }
2181 else
2182 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002183 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002184 return false;
2185 }
2186 }
2187 else if (shader == GL_FRAGMENT_SHADER)
2188 {
2189 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2190 {
2191 mSamplersPS[samplerIndex].active = true;
2192 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2193 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2194 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2195 }
2196 else
2197 {
2198 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2199 return false;
2200 }
2201 }
2202 else UNREACHABLE();
2203
2204 samplerIndex++;
2205 }
2206 while (samplerIndex < constant.registerIndex + constant.arraySize);
2207 }
2208
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002209 Uniform *uniform = NULL;
2210 GLint location = getUniformLocation(constant.name);
2211
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002212 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002213 {
2214 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002215 }
2216 else
2217 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002218 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002219 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002220
2221 if (!uniform)
2222 {
2223 return false;
2224 }
2225
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002226 if (shader == GL_FRAGMENT_SHADER)
2227 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002228 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002229 }
2230 else if (shader == GL_VERTEX_SHADER)
2231 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002232 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002233 }
2234 else UNREACHABLE();
2235
2236 if (location >= 0)
2237 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002238 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002239 }
2240
2241 mUniforms.push_back(uniform);
2242 unsigned int uniformIndex = mUniforms.size() - 1;
2243
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002244 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002245 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002246 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002247 }
2248
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002249 if (shader == GL_VERTEX_SHADER)
2250 {
2251 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2252 {
2253 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2254 return false;
2255 }
2256 }
2257 else if (shader == GL_FRAGMENT_SHADER)
2258 {
2259 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2260 {
2261 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2262 return false;
2263 }
2264 }
2265 else UNREACHABLE();
2266
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002267 return true;
2268}
2269
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002270bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2271{
2272 const char* blockName = vertexInterfaceBlock.name.c_str();
2273
2274 // validate blocks for the same member types
2275 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2276 {
2277 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2278 return false;
2279 }
2280
2281 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2282 {
2283 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2284 return false;
2285 }
2286
2287 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2288 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2289 {
2290 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2291 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2292
2293 if (vertexMember.name != fragmentMember.name)
2294 {
2295 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2296 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2297 return false;
2298 }
2299
2300 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2301 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2302 {
2303 return false;
2304 }
2305 }
2306
2307 return true;
2308}
2309
2310bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2311{
2312 // Check that interface blocks defined in the vertex and fragment shaders are identical
2313 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2314 UniformBlockMap linkedUniformBlocks;
2315
2316 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2317 {
2318 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2319 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2320 }
2321
2322 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2323 {
2324 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2325 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2326 if (entry != linkedUniformBlocks.end())
2327 {
2328 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2329 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2330 {
2331 return false;
2332 }
2333 }
2334 }
2335
2336 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2337 {
2338 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2339 {
2340 return false;
2341 }
2342 }
2343
2344 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2345 {
2346 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2347 {
2348 return false;
2349 }
2350 }
2351
2352 return true;
2353}
2354
2355bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2356{
2357 // create uniform block entries if they do not exist
2358 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2359 {
2360 std::vector<unsigned int> blockUniformIndexes;
2361 const unsigned int blockIndex = mUniformBlocks.size();
2362
2363 // define member uniforms
2364 for (unsigned int activeUniformIndex = 0; activeUniformIndex < interfaceBlock.activeUniforms.size(); activeUniformIndex++)
2365 {
2366 const sh::Uniform &constant = interfaceBlock.activeUniforms[activeUniformIndex];
2367 Uniform *uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize,
2368 blockIndex, interfaceBlock.blockInfo[activeUniformIndex]);
2369
2370 // add to uniform list, but not index, since uniform block uniforms have no location
2371 blockUniformIndexes.push_back(mUniforms.size());
2372 mUniforms.push_back(uniform);
2373 }
2374
2375 // create all the uniform blocks
2376 if (interfaceBlock.arraySize > 0)
2377 {
2378 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2379 {
2380 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2381 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2382 mUniformBlocks.push_back(newUniformBlock);
2383 }
2384 }
2385 else
2386 {
2387 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2388 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2389 mUniformBlocks.push_back(newUniformBlock);
2390 }
2391 }
2392
2393 // Assign registers to the uniform blocks
2394 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2395 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2396 ASSERT(blockIndex != GL_INVALID_INDEX);
2397 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2398
2399 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2400 {
2401 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2402 ASSERT(uniformBlock->name == interfaceBlock.name);
2403
2404 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2405 {
2406 return false;
2407 }
2408 }
2409
2410 return true;
2411}
2412
2413bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2414{
2415 if (shader == GL_VERTEX_SHADER)
2416 {
2417 uniformBlock->vsRegisterIndex = registerIndex;
2418 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2419
2420 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2421 {
2422 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2423 return false;
2424 }
2425 }
2426 else if (shader == GL_FRAGMENT_SHADER)
2427 {
2428 uniformBlock->psRegisterIndex = registerIndex;
2429 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2430
2431 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2432 {
2433 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2434 return false;
2435 }
2436 }
2437 else UNREACHABLE();
2438
2439 return true;
2440}
2441
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002442std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2443{
2444 // for now we only handle point sprite emulation
2445 ASSERT(usesPointSpriteEmulation());
2446 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2447}
2448
2449std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2450{
2451 ASSERT(registers >= 0);
2452 ASSERT(vertexShader->mUsesPointSize);
2453 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2454
2455 std::string geomHLSL;
2456
2457 std::string varyingSemantic = "TEXCOORD";
2458
2459 std::string fragCoordSemantic;
2460 std::string pointCoordSemantic;
2461
2462 int reservedRegisterIndex = registers;
2463
2464 if (fragmentShader->mUsesFragCoord)
2465 {
2466 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2467 }
2468
2469 if (fragmentShader->mUsesPointCoord)
2470 {
2471 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2472 }
2473
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002474 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2475 "\n"
2476 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002477 "{\n";
2478
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002479 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002480
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002481 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002482
2483 if (fragmentShader->mUsesFragCoord)
2484 {
2485 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2486 }
2487
2488 geomHLSL += " float gl_PointSize : PSIZE;\n"
2489 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002490 "};\n"
2491 "\n"
2492 "struct GS_OUTPUT\n"
2493 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002494
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002495 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002496
2497 if (fragmentShader->mUsesFragCoord)
2498 {
2499 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2500 }
2501
2502 if (fragmentShader->mUsesPointCoord)
2503 {
2504 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2505 }
2506
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002507 geomHLSL += " float gl_PointSize : PSIZE;\n"
2508 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002509 "};\n"
2510 "\n"
2511 "static float2 pointSpriteCorners[] = \n"
2512 "{\n"
2513 " float2( 0.5f, -0.5f),\n"
2514 " float2( 0.5f, 0.5f),\n"
2515 " float2(-0.5f, -0.5f),\n"
2516 " float2(-0.5f, 0.5f)\n"
2517 "};\n"
2518 "\n"
2519 "static float2 pointSpriteTexcoords[] = \n"
2520 "{\n"
2521 " float2(1.0f, 1.0f),\n"
2522 " float2(1.0f, 0.0f),\n"
2523 " float2(0.0f, 1.0f),\n"
2524 " float2(0.0f, 0.0f)\n"
2525 "};\n"
2526 "\n"
2527 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2528 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2529 "\n"
2530 "[maxvertexcount(4)]\n"
2531 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2532 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002533 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2534 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002535
2536 for (int r = 0; r < registers; r++)
2537 {
2538 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2539 }
2540
2541 if (fragmentShader->mUsesFragCoord)
2542 {
2543 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2544 }
2545
2546 geomHLSL += " \n"
2547 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2548 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002549 " float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002550
2551 for (int corner = 0; corner < 4; corner++)
2552 {
2553 geomHLSL += " \n"
2554 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2555
2556 if (fragmentShader->mUsesPointCoord)
2557 {
2558 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2559 }
2560
2561 geomHLSL += " outStream.Append(output);\n";
2562 }
2563
2564 geomHLSL += " \n"
2565 " outStream.RestartStrip();\n"
2566 "}\n";
2567
2568 return geomHLSL;
2569}
2570
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002571// This method needs to match OutputHLSL::decorate
2572std::string ProgramBinary::decorateAttribute(const std::string &name)
2573{
2574 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2575 {
2576 return "_" + name;
2577 }
2578
2579 return name;
2580}
2581
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002582bool ProgramBinary::isValidated() const
2583{
2584 return mValidated;
2585}
2586
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002587void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002588{
2589 // Skip over inactive attributes
2590 unsigned int activeAttribute = 0;
2591 unsigned int attribute;
2592 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2593 {
2594 if (mLinkedAttribute[attribute].name.empty())
2595 {
2596 continue;
2597 }
2598
2599 if (activeAttribute == index)
2600 {
2601 break;
2602 }
2603
2604 activeAttribute++;
2605 }
2606
2607 if (bufsize > 0)
2608 {
2609 const char *string = mLinkedAttribute[attribute].name.c_str();
2610
2611 strncpy(name, string, bufsize);
2612 name[bufsize - 1] = '\0';
2613
2614 if (length)
2615 {
2616 *length = strlen(name);
2617 }
2618 }
2619
2620 *size = 1; // Always a single 'type' instance
2621
2622 *type = mLinkedAttribute[attribute].type;
2623}
2624
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002625GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002626{
2627 int count = 0;
2628
2629 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2630 {
2631 if (!mLinkedAttribute[attributeIndex].name.empty())
2632 {
2633 count++;
2634 }
2635 }
2636
2637 return count;
2638}
2639
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002640GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002641{
2642 int maxLength = 0;
2643
2644 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2645 {
2646 if (!mLinkedAttribute[attributeIndex].name.empty())
2647 {
2648 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2649 }
2650 }
2651
2652 return maxLength;
2653}
2654
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002655void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002656{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002657 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002658
2659 if (bufsize > 0)
2660 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002661 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002662
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002663 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002664 {
2665 string += "[0]";
2666 }
2667
2668 strncpy(name, string.c_str(), bufsize);
2669 name[bufsize - 1] = '\0';
2670
2671 if (length)
2672 {
2673 *length = strlen(name);
2674 }
2675 }
2676
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002677 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002678
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002679 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002680}
2681
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002682GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002683{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002684 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002685}
2686
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002687GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002688{
2689 int maxLength = 0;
2690
2691 unsigned int numUniforms = mUniforms.size();
2692 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2693 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002694 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002695 {
2696 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2697 if (mUniforms[uniformIndex]->isArray())
2698 {
2699 length += 3; // Counting in "[0]".
2700 }
2701 maxLength = std::max(length, maxLength);
2702 }
2703 }
2704
2705 return maxLength;
2706}
2707
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002708GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2709{
2710 const gl::Uniform& uniform = *mUniforms[index];
2711
2712 switch (pname)
2713 {
2714 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2715 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
2716 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002717 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002718
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002719 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2720 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2721 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2722 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002723
2724 default:
2725 UNREACHABLE();
2726 break;
2727 }
2728 return 0;
2729}
2730
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002731void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2732{
2733 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2734
2735 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2736
2737 if (bufSize > 0)
2738 {
2739 std::string string = uniformBlock.name;
2740
2741 if (uniformBlock.isArrayElement())
2742 {
2743 string += "[" + str(uniformBlock.elementIndex) + "]";
2744 }
2745
2746 strncpy(uniformBlockName, string.c_str(), bufSize);
2747 uniformBlockName[bufSize - 1] = '\0';
2748
2749 if (length)
2750 {
2751 *length = strlen(uniformBlockName);
2752 }
2753 }
2754}
2755
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002756void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2757{
2758 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2759
2760 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2761
2762 switch (pname)
2763 {
2764 case GL_UNIFORM_BLOCK_DATA_SIZE:
2765 *params = static_cast<GLint>(uniformBlock.dataSize);
2766 break;
2767 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2768 *params = static_cast<GLint>(uniformBlock.name.size() + 1);
2769 break;
2770 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2771 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2772 break;
2773 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2774 {
2775 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2776 {
2777 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2778 }
2779 }
2780 break;
2781 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2782 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2783 break;
2784 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2785 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2786 break;
2787 default: UNREACHABLE();
2788 }
2789}
2790
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002791GLuint ProgramBinary::getActiveUniformBlockCount() const
2792{
2793 return mUniformBlocks.size();
2794}
2795
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002796GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2797{
2798 unsigned int maxLength = 0;
2799
2800 unsigned int numUniformBlocks = mUniformBlocks.size();
2801 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2802 {
2803 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2804 if (!uniformBlock.name.empty())
2805 {
2806 const unsigned int length = uniformBlock.name.length() + 1;
2807
2808 // Counting in "[0]".
2809 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2810
2811 maxLength = std::max(length + arrayLength, maxLength);
2812 }
2813 }
2814
2815 return maxLength;
2816}
2817
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002818void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002819{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002820 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002821 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002822 {
2823 mValidated = false;
2824 }
2825 else
2826 {
2827 mValidated = true;
2828 }
2829}
2830
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002831bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002832{
2833 // if any two active samplers in a program are of different types, but refer to the same
2834 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2835 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2836
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002837 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002838 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002839
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002840 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002841 {
2842 textureUnitType[i] = TEXTURE_UNKNOWN;
2843 }
2844
2845 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2846 {
2847 if (mSamplersPS[i].active)
2848 {
2849 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2850
2851 if (unit >= maxCombinedTextureImageUnits)
2852 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002853 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002854 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002855 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002856 }
2857
2858 return false;
2859 }
2860
2861 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2862 {
2863 if (mSamplersPS[i].textureType != textureUnitType[unit])
2864 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002865 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002866 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002867 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002868 }
2869
2870 return false;
2871 }
2872 }
2873 else
2874 {
2875 textureUnitType[unit] = mSamplersPS[i].textureType;
2876 }
2877 }
2878 }
2879
2880 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2881 {
2882 if (mSamplersVS[i].active)
2883 {
2884 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2885
2886 if (unit >= maxCombinedTextureImageUnits)
2887 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002888 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002889 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002890 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002891 }
2892
2893 return false;
2894 }
2895
2896 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2897 {
2898 if (mSamplersVS[i].textureType != textureUnitType[unit])
2899 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002900 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002901 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002902 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002903 }
2904
2905 return false;
2906 }
2907 }
2908 else
2909 {
2910 textureUnitType[unit] = mSamplersVS[i].textureType;
2911 }
2912 }
2913 }
2914
2915 return true;
2916}
2917
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002918ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2919{
2920}
2921
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002922struct AttributeSorter
2923{
2924 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2925 : originalIndices(semanticIndices)
2926 {
2927 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2928 {
2929 indices[i] = i;
2930 }
2931
2932 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2933 }
2934
2935 bool operator()(int a, int b)
2936 {
2937 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2938 }
2939
2940 int indices[MAX_VERTEX_ATTRIBS];
2941 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2942};
2943
2944void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2945{
2946 AttributeSorter sorter(mSemanticIndex);
2947
2948 int oldIndices[MAX_VERTEX_ATTRIBS];
2949 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2950
2951 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2952 {
2953 oldIndices[i] = mSemanticIndex[i];
2954 oldTranslatedAttributes[i] = attributes[i];
2955 }
2956
2957 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2958 {
2959 int oldIndex = sorter.indices[i];
2960 sortedSemanticIndices[i] = oldIndices[oldIndex];
2961 attributes[i] = oldTranslatedAttributes[oldIndex];
2962 }
2963}
2964
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002965}