blob: 584b4ac14b7497fe0c9711fcdff942f3e1711691 [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"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000017#include "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{
415 int copyWidth = std::min(targetWidth, srcWidth);
416 int copyHeight = std::min(targetHeight, srcHeight);
417
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);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000496 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4 * rows);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000497
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000498 for (int i = 0; i < count; i++)
499 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000500 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
501 if (transpose == GL_FALSE)
502 {
503 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
504 }
505 else
506 {
507 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
508 }
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000509 target += 4 * rows;
510 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000511 }
512
513 return true;
514}
515
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000516bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000517{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000518 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000519}
520
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000521bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000522{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000523 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000524}
525
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000526bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000527{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000528 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529}
530
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000531bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000532{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000533 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000534}
535
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000536bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000537{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000538 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000539}
540
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000541bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000542{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000543 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000544}
545
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000546bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000547{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000548 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000549}
550
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000551bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000552{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000553 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000554}
555
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000556bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000557{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000558 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000559}
560
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000561bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
562{
563 if (location < 0 || location >= (int)mUniformIndex.size())
564 {
565 return false;
566 }
567
568 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
569 targetUniform->dirty = true;
570
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000571 int elementCount = targetUniform->elementCount();
572
573 if (elementCount == 1 && count > 1)
574 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
575
576 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
577
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578 if (targetUniform->type == GL_INT ||
579 targetUniform->type == GL_SAMPLER_2D ||
580 targetUniform->type == GL_SAMPLER_CUBE)
581 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000582 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000583
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000584 for (int i = 0; i < count; i++)
585 {
586 target[0] = v[0];
587 target[1] = 0;
588 target[2] = 0;
589 target[3] = 0;
590 target += 4;
591 v += 1;
592 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000593 }
594 else if (targetUniform->type == GL_BOOL)
595 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000596 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000597
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000598 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000599 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000600 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
601 boolParams[1] = GL_FALSE;
602 boolParams[2] = GL_FALSE;
603 boolParams[3] = GL_FALSE;
604 boolParams += 4;
605 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000606 }
607 }
608 else
609 {
610 return false;
611 }
612
613 return true;
614}
615
616bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
617{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000618 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000619}
620
621bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
622{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000623 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000624}
625
626bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
627{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000628 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000629}
630
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000631bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
632{
633 return setUniform(location, count, v, GL_UNSIGNED_INT);
634}
635
636bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
637{
638 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
639}
640
641bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
642{
643 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
644}
645
646bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
647{
648 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
649}
650
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000651template <typename T>
652bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000653{
654 if (location < 0 || location >= (int)mUniformIndex.size())
655 {
656 return false;
657 }
658
659 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
660
661 // sized queries -- ensure the provided buffer is large enough
662 if (bufSize)
663 {
664 int requiredBytes = UniformExternalSize(targetUniform->type);
665 if (*bufSize < requiredBytes)
666 {
667 return false;
668 }
669 }
670
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000671 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000672 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000673 const int rows = VariableRowCount(targetUniform->type);
674 const int cols = VariableColumnCount(targetUniform->type);
675 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
676 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000677 else if (uniformType == UniformComponentType(targetUniform->type))
678 {
679 unsigned int size = UniformComponentCount(targetUniform->type);
680 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
681 size * sizeof(T));
682 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000683 else
684 {
685 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000686 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000687 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000688 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000689 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000690 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000691
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000692 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000693 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000694 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000695 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000696 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000697 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000698
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000699 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000700 {
701 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
702
703 for (unsigned int i = 0; i < size; i++)
704 {
705 params[i] = static_cast<T>(floatParams[i]);
706 }
707 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000708 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000709
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000710 case GL_INT:
711 {
712 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
713
714 for (unsigned int i = 0; i < size; i++)
715 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000716 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000717 }
718 }
719 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000720
721 case GL_UNSIGNED_INT:
722 {
723 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000724
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000725 for (unsigned int i = 0; i < size; i++)
726 {
727 params[i] = static_cast<T>(uintParams[i]);
728 }
729 }
730 break;
731
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000732 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000733 }
734 }
735
736 return true;
737}
738
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000739bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
740{
741 return getUniformv(location, bufSize, params, GL_FLOAT);
742}
743
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000744bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
745{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000746 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000747}
748
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000749bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
750{
751 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
752}
753
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000754void ProgramBinary::dirtyAllUniforms()
755{
756 unsigned int numUniforms = mUniforms.size();
757 for (unsigned int index = 0; index < numUniforms; index++)
758 {
759 mUniforms[index]->dirty = true;
760 }
761}
762
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000763// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000764void ProgramBinary::applyUniforms()
765{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000766 // Retrieve sampler uniform values
767 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
768 {
769 Uniform *targetUniform = *ub;
770
771 if (targetUniform->dirty)
772 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000773 if (targetUniform->type == GL_SAMPLER_2D ||
774 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000775 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000776 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000777 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000778
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000779 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000780 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000781 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000782
783 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000784 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000785 unsigned int samplerIndex = firstIndex + i;
786
787 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000788 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000789 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000790 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000791 }
792 }
793 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000794
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000795 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000796 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000797 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000798
799 for (int i = 0; i < count; i++)
800 {
801 unsigned int samplerIndex = firstIndex + i;
802
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000803 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000804 {
805 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000806 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000807 }
808 }
809 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000810 }
811 }
812 }
813
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000814 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000815}
816
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000817bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
818{
819 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
820 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
821
822 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
823 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
824
825 ASSERT(boundBuffers.size() == mUniformBlocks.size());
826
827 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
828 {
829 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
830 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
831
832 ASSERT(uniformBlock && uniformBuffer);
833
834 if (uniformBuffer->size() < uniformBlock->dataSize)
835 {
836 // undefined behaviour
837 return false;
838 }
839
840 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
841
842 if (uniformBlock->isReferencedByVertexShader())
843 {
844 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
845 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
846 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
847 vertexUniformBuffers[registerIndex] = uniformBuffer;
848 }
849
850 if (uniformBlock->isReferencedByFragmentShader())
851 {
852 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
853 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
854 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
855 fragmentUniformBuffers[registerIndex] = uniformBuffer;
856 }
857 }
858
859 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
860}
861
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000862// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
863// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000864int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000865{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000866 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000867
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000868 fragmentShader->resetVaryingsRegisterAssignment();
869
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000870 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
871 {
872 int n = VariableRowCount(varying->type) * varying->size;
873 int m = VariableColumnCount(varying->type);
874 bool success = false;
875
876 if (m == 2 || m == 3 || m == 4)
877 {
878 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
879 {
880 bool available = true;
881
882 for (int y = 0; y < n && available; y++)
883 {
884 for (int x = 0; x < m && available; x++)
885 {
886 if (packing[r + y][x])
887 {
888 available = false;
889 }
890 }
891 }
892
893 if (available)
894 {
895 varying->reg = r;
896 varying->col = 0;
897
898 for (int y = 0; y < n; y++)
899 {
900 for (int x = 0; x < m; x++)
901 {
902 packing[r + y][x] = &*varying;
903 }
904 }
905
906 success = true;
907 }
908 }
909
910 if (!success && m == 2)
911 {
912 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
913 {
914 bool available = true;
915
916 for (int y = 0; y < n && available; y++)
917 {
918 for (int x = 2; x < 4 && available; x++)
919 {
920 if (packing[r + y][x])
921 {
922 available = false;
923 }
924 }
925 }
926
927 if (available)
928 {
929 varying->reg = r;
930 varying->col = 2;
931
932 for (int y = 0; y < n; y++)
933 {
934 for (int x = 2; x < 4; x++)
935 {
936 packing[r + y][x] = &*varying;
937 }
938 }
939
940 success = true;
941 }
942 }
943 }
944 }
945 else if (m == 1)
946 {
947 int space[4] = {0};
948
949 for (int y = 0; y < maxVaryingVectors; y++)
950 {
951 for (int x = 0; x < 4; x++)
952 {
953 space[x] += packing[y][x] ? 0 : 1;
954 }
955 }
956
957 int column = 0;
958
959 for (int x = 0; x < 4; x++)
960 {
961 if (space[x] >= n && space[x] < space[column])
962 {
963 column = x;
964 }
965 }
966
967 if (space[column] >= n)
968 {
969 for (int r = 0; r < maxVaryingVectors; r++)
970 {
971 if (!packing[r][column])
972 {
973 varying->reg = r;
974
975 for (int y = r; y < r + n; y++)
976 {
977 packing[y][column] = &*varying;
978 }
979
980 break;
981 }
982 }
983
984 varying->col = column;
985
986 success = true;
987 }
988 }
989 else UNREACHABLE();
990
991 if (!success)
992 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000993 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000994
995 return -1;
996 }
997 }
998
999 // Return the number of used registers
1000 int registers = 0;
1001
1002 for (int r = 0; r < maxVaryingVectors; r++)
1003 {
1004 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1005 {
1006 registers++;
1007 }
1008 }
1009
1010 return registers;
1011}
1012
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001013bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1014 std::string& pixelHLSL, std::string& vertexHLSL,
1015 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001016{
1017 if (pixelHLSL.empty() || vertexHLSL.empty())
1018 {
1019 return false;
1020 }
1021
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001022 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1023 bool usesFragColor = fragmentShader->mUsesFragColor;
1024 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001025 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001026 {
1027 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1028 return false;
1029 }
1030
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001031 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001032 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001033 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001034
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001035 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1036
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001037 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1038 // - with a 3.0 context, the output color is copied to channel 0
1039 // - with a 2.0 context, the output color is broadcast to all channels
1040 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1041 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1042
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001043 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001044 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001045 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001046
1047 return false;
1048 }
1049
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001050 vertexShader->resetVaryingsRegisterAssignment();
1051
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001052 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1053 {
1054 bool matched = false;
1055
1056 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1057 {
1058 if (output->name == input->name)
1059 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001060 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001061 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001062 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 +00001063
1064 return false;
1065 }
1066
1067 output->reg = input->reg;
1068 output->col = input->col;
1069
1070 matched = true;
1071 break;
1072 }
1073 }
1074
1075 if (!matched)
1076 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001077 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001078
1079 return false;
1080 }
1081 }
1082
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001083 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001084 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001085 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001086 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1087
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001088 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1089
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001090 // special varyings that use reserved registers
1091 int reservedRegisterIndex = registers;
1092 std::string fragCoordSemantic;
1093 std::string pointCoordSemantic;
1094
1095 if (fragmentShader->mUsesFragCoord)
1096 {
1097 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1098 }
1099
1100 if (fragmentShader->mUsesPointCoord)
1101 {
1102 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1103 // In DX11 we compute this in the GS.
1104 if (shaderModel == 3)
1105 {
1106 pointCoordSemantic = "TEXCOORD0";
1107 }
1108 else if (shaderModel >= 4)
1109 {
1110 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1111 }
1112 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001113
1114 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001115 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001116
1117 int semanticIndex = 0;
1118 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1119 {
1120 switch (attribute->type)
1121 {
1122 case GL_FLOAT: vertexHLSL += " float "; break;
1123 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1124 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1125 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1126 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1127 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1128 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1129 default: UNREACHABLE();
1130 }
1131
1132 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1133
1134 semanticIndex += VariableRowCount(attribute->type);
1135 }
1136
1137 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001138 "\n"
1139 "struct VS_OUTPUT\n"
1140 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001141
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001142 if (shaderModel < 4)
1143 {
1144 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1145 }
1146
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001147 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001148
1149 if (fragmentShader->mUsesFragCoord)
1150 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001151 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001152 }
1153
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001154 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155 {
1156 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1157 }
1158
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001159 if (shaderModel >= 4)
1160 {
1161 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1162 }
1163
1164 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001165 "\n"
1166 "VS_OUTPUT main(VS_INPUT input)\n"
1167 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001168
1169 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1170 {
1171 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1172
1173 if (VariableRowCount(attribute->type) > 1) // Matrix
1174 {
1175 vertexHLSL += "transpose";
1176 }
1177
1178 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1179 }
1180
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001181 if (shaderModel >= 4)
1182 {
1183 vertexHLSL += "\n"
1184 " gl_main();\n"
1185 "\n"
1186 " VS_OUTPUT output;\n"
1187 " output.gl_Position.x = gl_Position.x;\n"
1188 " output.gl_Position.y = -gl_Position.y;\n"
1189 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1190 " output.gl_Position.w = gl_Position.w;\n";
1191 }
1192 else
1193 {
1194 vertexHLSL += "\n"
1195 " gl_main();\n"
1196 "\n"
1197 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001198 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1199 " 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 +00001200 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1201 " output.gl_Position.w = gl_Position.w;\n";
1202 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001203
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001204 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001205 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001206 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001207 }
1208
1209 if (fragmentShader->mUsesFragCoord)
1210 {
1211 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1212 }
1213
1214 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1215 {
1216 if (varying->reg >= 0)
1217 {
1218 for (int i = 0; i < varying->size; i++)
1219 {
1220 int rows = VariableRowCount(varying->type);
1221
1222 for (int j = 0; j < rows; j++)
1223 {
1224 int r = varying->reg + i * rows + j;
1225 vertexHLSL += " output.v" + str(r);
1226
1227 bool sharedRegister = false; // Register used by multiple varyings
1228
1229 for (int x = 0; x < 4; x++)
1230 {
1231 if (packing[r][x] && packing[r][x] != packing[r][0])
1232 {
1233 sharedRegister = true;
1234 break;
1235 }
1236 }
1237
1238 if(sharedRegister)
1239 {
1240 vertexHLSL += ".";
1241
1242 for (int x = 0; x < 4; x++)
1243 {
1244 if (packing[r][x] == &*varying)
1245 {
1246 switch(x)
1247 {
1248 case 0: vertexHLSL += "x"; break;
1249 case 1: vertexHLSL += "y"; break;
1250 case 2: vertexHLSL += "z"; break;
1251 case 3: vertexHLSL += "w"; break;
1252 }
1253 }
1254 }
1255 }
1256
1257 vertexHLSL += " = " + varying->name;
1258
1259 if (varying->array)
1260 {
1261 vertexHLSL += "[" + str(i) + "]";
1262 }
1263
1264 if (rows > 1)
1265 {
1266 vertexHLSL += "[" + str(j) + "]";
1267 }
1268
1269 vertexHLSL += ";\n";
1270 }
1271 }
1272 }
1273 }
1274
1275 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001276 " return output;\n"
1277 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001278
1279 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001280 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001281
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001282 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001283
1284 if (fragmentShader->mUsesFragCoord)
1285 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001286 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001287 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001288
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001289 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1290 {
1291 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1292 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001293
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001294 // Must consume the PSIZE element if the geometry shader is not active
1295 // We won't know if we use a GS until we draw
1296 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1297 {
1298 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1299 }
1300
1301 if (fragmentShader->mUsesFragCoord)
1302 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001303 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001304 {
1305 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1306 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001307 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001308 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001309 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1310 }
1311 }
1312
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001313 pixelHLSL += "};\n"
1314 "\n"
1315 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001316 "{\n";
1317
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001318 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001319 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001320 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001321 }
1322
1323 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001324 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001325
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001326 if (fragmentShader->mUsesFrontFacing)
1327 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001328 if (shaderModel >= 4)
1329 {
1330 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1331 "{\n";
1332 }
1333 else
1334 {
1335 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1336 "{\n";
1337 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001338 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001339 else
1340 {
1341 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1342 "{\n";
1343 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001344
1345 if (fragmentShader->mUsesFragCoord)
1346 {
1347 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1348
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001349 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001350 {
1351 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1352 " gl_FragCoord.y = input.dx_VPos.y;\n";
1353 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001354 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001355 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001356 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001357 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001358 }
1359 else
1360 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001361 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1362 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1363 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001364 }
1365
daniel@transgaming.com12985182012-12-20 20:56:31 +00001366 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001367 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001368 }
1369
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001370 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001371 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001372 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1373 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001374 }
1375
1376 if (fragmentShader->mUsesFrontFacing)
1377 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001378 if (shaderModel <= 3)
1379 {
1380 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1381 }
1382 else
1383 {
1384 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1385 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001386 }
1387
1388 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1389 {
1390 if (varying->reg >= 0)
1391 {
1392 for (int i = 0; i < varying->size; i++)
1393 {
1394 int rows = VariableRowCount(varying->type);
1395 for (int j = 0; j < rows; j++)
1396 {
1397 std::string n = str(varying->reg + i * rows + j);
1398 pixelHLSL += " " + varying->name;
1399
1400 if (varying->array)
1401 {
1402 pixelHLSL += "[" + str(i) + "]";
1403 }
1404
1405 if (rows > 1)
1406 {
1407 pixelHLSL += "[" + str(j) + "]";
1408 }
1409
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001410 switch (VariableColumnCount(varying->type))
1411 {
1412 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1413 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1414 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1415 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1416 default: UNREACHABLE();
1417 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001418 }
1419 }
1420 }
1421 else UNREACHABLE();
1422 }
1423
1424 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001425 " gl_main();\n"
1426 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001427 " PS_OUTPUT output;\n";
1428
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001429 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001430 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001431 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001432
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001433 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001434 }
1435
1436 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001437 " return output;\n"
1438 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001439
1440 return true;
1441}
1442
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001443std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1444{
1445 std::string varyingHLSL;
1446
1447 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1448 {
1449 if (varying->reg >= 0)
1450 {
1451 for (int i = 0; i < varying->size; i++)
1452 {
1453 int rows = VariableRowCount(varying->type);
1454 for (int j = 0; j < rows; j++)
1455 {
1456 switch (varying->interpolation)
1457 {
1458 case Smooth: varyingHLSL += " "; break;
1459 case Flat: varyingHLSL += " nointerpolation "; break;
1460 case Centroid: varyingHLSL += " centroid "; break;
1461 default: UNREACHABLE();
1462 }
1463
1464 std::string n = str(varying->reg + i * rows + j);
1465 varyingHLSL += "float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
1466 }
1467 }
1468 }
1469 else UNREACHABLE();
1470 }
1471
1472 return varyingHLSL;
1473}
1474
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001475bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1476{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001477 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001478
1479 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001480 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001481 if (format != GL_PROGRAM_BINARY_ANGLE)
1482 {
1483 infoLog.append("Invalid program binary format.");
1484 return false;
1485 }
1486
1487 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001488 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001489 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001490 {
1491 infoLog.append("Invalid program binary version.");
1492 return false;
1493 }
1494
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001495 int compileFlags = 0;
1496 stream.read(&compileFlags);
1497 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1498 {
1499 infoLog.append("Mismatched compilation flags.");
1500 return false;
1501 }
1502
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001503 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1504 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001505 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001506 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001507 stream.read(&name);
1508 mLinkedAttribute[i].name = name;
1509 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001510 }
1511
1512 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1513 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001514 stream.read(&mSamplersPS[i].active);
1515 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001516
1517 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001518 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001519 mSamplersPS[i].textureType = (TextureType) textureType;
1520 }
1521
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001522 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001523 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001524 stream.read(&mSamplersVS[i].active);
1525 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001526
1527 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001528 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001529 mSamplersVS[i].textureType = (TextureType) textureType;
1530 }
1531
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001532 stream.read(&mUsedVertexSamplerRange);
1533 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001534 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001535
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001536 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001537 stream.read(&size);
1538 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001539 {
1540 infoLog.append("Invalid program binary.");
1541 return false;
1542 }
1543
1544 mUniforms.resize(size);
1545 for (unsigned int i = 0; i < size; ++i)
1546 {
1547 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001548 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001549 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001550 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001551 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001552
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001553 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001554 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001555 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001556 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001557 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001558
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001559 int offset;
1560 int arrayStride;
1561 int matrixStride;
1562 bool isRowMajorMatrix;
1563
1564 stream.read(&offset);
1565 stream.read(&arrayStride);
1566 stream.read(&matrixStride);
1567 stream.read(&isRowMajorMatrix);
1568
1569 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1570
1571 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001572
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001573 stream.read(&mUniforms[i]->psRegisterIndex);
1574 stream.read(&mUniforms[i]->vsRegisterIndex);
1575 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001576 }
1577
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001578 stream.read(&size);
1579 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001580 {
1581 infoLog.append("Invalid program binary.");
1582 return false;
1583 }
1584
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001585 mUniformBlocks.resize(size);
1586 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1587 {
1588 std::string name;
1589 unsigned int elementIndex;
1590 unsigned int dataSize;
1591
1592 stream.read(&name);
1593 stream.read(&elementIndex);
1594 stream.read(&dataSize);
1595
1596 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1597
1598 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1599 stream.read(&uniformBlock.psRegisterIndex);
1600 stream.read(&uniformBlock.vsRegisterIndex);
1601
1602 size_t numMembers;
1603 stream.read(&numMembers);
1604 uniformBlock.memberUniformIndexes.resize(numMembers);
1605 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1606 {
1607 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1608 }
1609 }
1610
1611 stream.read(&size);
1612 if (stream.error())
1613 {
1614 infoLog.append("Invalid program binary.");
1615 return false;
1616 }
1617
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001618 mUniformIndex.resize(size);
1619 for (unsigned int i = 0; i < size; ++i)
1620 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001621 stream.read(&mUniformIndex[i].name);
1622 stream.read(&mUniformIndex[i].element);
1623 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001624 }
1625
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001626 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001627 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001628
1629 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001630 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001631
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001632 unsigned int geometryShaderSize;
1633 stream.read(&geometryShaderSize);
1634
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001635 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001636
daniel@transgaming.com36038542012-11-28 20:59:26 +00001637 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 ptr += sizeof(GUID);
1639
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001640 GUID identifier = mRenderer->getAdapterIdentifier();
1641 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001642 {
1643 infoLog.append("Invalid program binary.");
1644 return false;
1645 }
1646
1647 const char *pixelShaderFunction = ptr;
1648 ptr += pixelShaderSize;
1649
1650 const char *vertexShaderFunction = ptr;
1651 ptr += vertexShaderSize;
1652
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001653 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1654 ptr += geometryShaderSize;
1655
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001656 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001657 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001658 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001659 {
1660 infoLog.append("Could not create pixel shader.");
1661 return false;
1662 }
1663
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001664 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001665 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001666 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667 {
1668 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001669 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001670 mPixelExecutable = NULL;
1671 return false;
1672 }
1673
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001674 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1675 {
1676 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1677 geometryShaderSize, rx::SHADER_GEOMETRY);
1678 if (!mGeometryExecutable)
1679 {
1680 infoLog.append("Could not create geometry shader.");
1681 delete mPixelExecutable;
1682 mPixelExecutable = NULL;
1683 delete mVertexExecutable;
1684 mVertexExecutable = NULL;
1685 return false;
1686 }
1687 }
1688 else
1689 {
1690 mGeometryExecutable = NULL;
1691 }
1692
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001693 return true;
1694}
1695
1696bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1697{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001698 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001699
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001700 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001701 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001702 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001703
1704 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1705 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001706 stream.write(mLinkedAttribute[i].type);
1707 stream.write(mLinkedAttribute[i].name);
1708 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001709 }
1710
1711 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1712 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001713 stream.write(mSamplersPS[i].active);
1714 stream.write(mSamplersPS[i].logicalTextureUnit);
1715 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001716 }
1717
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001718 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001719 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001720 stream.write(mSamplersVS[i].active);
1721 stream.write(mSamplersVS[i].logicalTextureUnit);
1722 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001723 }
1724
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001725 stream.write(mUsedVertexSamplerRange);
1726 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001727 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001728
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001729 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001730 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001731 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001732 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001733
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001734 stream.write(uniform.type);
1735 stream.write(uniform.precision);
1736 stream.write(uniform.name);
1737 stream.write(uniform.arraySize);
1738 stream.write(uniform.blockIndex);
1739
1740 stream.write(uniform.blockInfo.offset);
1741 stream.write(uniform.blockInfo.arrayStride);
1742 stream.write(uniform.blockInfo.matrixStride);
1743 stream.write(uniform.blockInfo.isRowMajorMatrix);
1744
1745 stream.write(uniform.psRegisterIndex);
1746 stream.write(uniform.vsRegisterIndex);
1747 stream.write(uniform.registerCount);
1748 }
1749
1750 stream.write(mUniformBlocks.size());
1751 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1752 {
1753 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1754
1755 stream.write(uniformBlock.name);
1756 stream.write(uniformBlock.elementIndex);
1757 stream.write(uniformBlock.dataSize);
1758
1759 stream.write(uniformBlock.memberUniformIndexes.size());
1760 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1761 {
1762 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1763 }
1764
1765 stream.write(uniformBlock.psRegisterIndex);
1766 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767 }
1768
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001769 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001770 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1771 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001772 stream.write(mUniformIndex[i].name);
1773 stream.write(mUniformIndex[i].element);
1774 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001775 }
1776
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001777 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001778 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001779
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001780 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001781 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001782
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001783 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1784 stream.write(geometryShaderSize);
1785
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001786 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001787
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001788 GLsizei streamLength = stream.length();
1789 const void *streamData = stream.data();
1790
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001791 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001792 if (totalLength > bufSize)
1793 {
1794 if (length)
1795 {
1796 *length = 0;
1797 }
1798
1799 return false;
1800 }
1801
1802 if (binary)
1803 {
1804 char *ptr = (char*) binary;
1805
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001806 memcpy(ptr, streamData, streamLength);
1807 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001809 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001810 ptr += sizeof(GUID);
1811
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001812 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001813 ptr += pixelShaderSize;
1814
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001815 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001816 ptr += vertexShaderSize;
1817
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001818 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1819 {
1820 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1821 ptr += geometryShaderSize;
1822 }
1823
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001824 ASSERT(ptr - totalLength == binary);
1825 }
1826
1827 if (length)
1828 {
1829 *length = totalLength;
1830 }
1831
1832 return true;
1833}
1834
1835GLint ProgramBinary::getLength()
1836{
1837 GLint length;
1838 if (save(NULL, INT_MAX, &length))
1839 {
1840 return length;
1841 }
1842 else
1843 {
1844 return 0;
1845 }
1846}
1847
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001848bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001849{
1850 if (!fragmentShader || !fragmentShader->isCompiled())
1851 {
1852 return false;
1853 }
1854
1855 if (!vertexShader || !vertexShader->isCompiled())
1856 {
1857 return false;
1858 }
1859
1860 std::string pixelHLSL = fragmentShader->getHLSL();
1861 std::string vertexHLSL = vertexShader->getHLSL();
1862
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001863 // Map the varyings to the register file
1864 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1865 int registers = packVaryings(infoLog, packing, fragmentShader);
1866
1867 if (registers < 0)
1868 {
1869 return false;
1870 }
1871
1872 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001873 {
1874 return false;
1875 }
1876
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001877 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001878 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1879 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001880
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001881 if (usesGeometryShader())
1882 {
1883 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1884 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1885 }
1886
1887 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001888 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001889 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001890 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001891
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001892 delete mVertexExecutable;
1893 mVertexExecutable = NULL;
1894 delete mPixelExecutable;
1895 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001896 delete mGeometryExecutable;
1897 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001898 }
1899
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001900 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1901 {
1902 success = false;
1903 }
1904
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001905 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001906 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001907 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001908 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001909
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001910 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1911 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1912 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001913 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1914 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1915 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 +00001916 }
1917
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001918 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1919 {
1920 success = false;
1921 }
1922
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001923 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001924}
1925
1926// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001927bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001928{
1929 unsigned int usedLocations = 0;
1930
1931 // Link attributes that have a binding location
1932 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1933 {
1934 int location = attributeBindings.getAttributeBinding(attribute->name);
1935
1936 if (location != -1) // Set by glBindAttribLocation
1937 {
1938 if (!mLinkedAttribute[location].name.empty())
1939 {
1940 // Multiple active attributes bound to the same location; not an error
1941 }
1942
1943 mLinkedAttribute[location] = *attribute;
1944
1945 int rows = VariableRowCount(attribute->type);
1946
1947 if (rows + location > MAX_VERTEX_ATTRIBS)
1948 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001949 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 +00001950
1951 return false;
1952 }
1953
1954 for (int i = 0; i < rows; i++)
1955 {
1956 usedLocations |= 1 << (location + i);
1957 }
1958 }
1959 }
1960
1961 // Link attributes that don't have a binding location
1962 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1963 {
1964 int location = attributeBindings.getAttributeBinding(attribute->name);
1965
1966 if (location == -1) // Not set by glBindAttribLocation
1967 {
1968 int rows = VariableRowCount(attribute->type);
1969 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1970
1971 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1972 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001973 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001974
1975 return false; // Fail to link
1976 }
1977
1978 mLinkedAttribute[availableIndex] = *attribute;
1979 }
1980 }
1981
1982 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1983 {
1984 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1985 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1986
1987 for (int r = 0; r < rows; r++)
1988 {
1989 mSemanticIndex[attributeIndex++] = index++;
1990 }
1991 }
1992
1993 return true;
1994}
1995
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00001996bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
1997{
1998 if (vertexUniform.type != fragmentUniform.type)
1999 {
2000 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2001 return false;
2002 }
2003 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2004 {
2005 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2006 return false;
2007 }
2008 else if (vertexUniform.precision != fragmentUniform.precision)
2009 {
2010 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2011 return false;
2012 }
2013 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2014 {
2015 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2016 }
2017
2018 const unsigned int numMembers = vertexUniform.fields.size();
2019 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2020 {
2021 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2022 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2023
2024 if (vertexMember.name != fragmentMember.name)
2025 {
2026 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2027 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2028 return false;
2029 }
2030
2031 const std::string memberName = uniformName + "." + vertexUniform.name;
2032 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2033 {
2034 return false;
2035 }
2036 }
2037
2038 return true;
2039}
2040
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002041bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002042{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002043 // Check that uniforms defined in the vertex and fragment shaders are identical
2044 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2045 UniformMap linkedUniforms;
2046
2047 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2048 {
2049 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2050 linkedUniforms[vertexUniform.name] = &vertexUniform;
2051 }
2052
2053 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2054 {
2055 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2056 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2057 if (entry != linkedUniforms.end())
2058 {
2059 const sh::Uniform &vertexUniform = *entry->second;
2060 const std::string &uniformName = "uniform " + vertexUniform.name;
2061 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2062 {
2063 return false;
2064 }
2065 }
2066 }
2067
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002068 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002069 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002070 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002071 {
2072 return false;
2073 }
2074 }
2075
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002076 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002077 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002078 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002079 {
2080 return false;
2081 }
2082 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002083
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002084 return true;
2085}
2086
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002087int totalRegisterCount(const sh::Uniform &uniform)
2088{
2089 int registerCount = 0;
2090
2091 if (!uniform.fields.empty())
2092 {
2093 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2094 {
2095 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2096 }
2097 }
2098 else
2099 {
2100 registerCount = 1;
2101 }
2102
2103 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2104}
2105
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002106bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002107{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002108 if (!constant.fields.empty())
2109 {
2110 if (constant.arraySize > 0)
2111 {
2112 unsigned int elementRegisterIndex = constant.registerIndex;
2113
2114 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2115 {
2116 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2117 {
2118 const sh::Uniform &field = constant.fields[fieldIndex];
2119 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2120 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2121 if (!defineUniform(shader, fieldUniform, infoLog))
2122 {
2123 return false;
2124 }
2125 elementRegisterIndex += totalRegisterCount(field);
2126 }
2127 }
2128 }
2129 else
2130 {
2131 unsigned int fieldRegisterIndex = constant.registerIndex;
2132
2133 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2134 {
2135 const sh::Uniform &field = constant.fields[fieldIndex];
2136 const std::string &uniformName = constant.name + "." + field.name;
2137
2138 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2139 fieldUniform.fields = field.fields;
2140
2141 if (!defineUniform(shader, fieldUniform, infoLog))
2142 {
2143 return false;
2144 }
2145 fieldRegisterIndex += totalRegisterCount(field);
2146 }
2147 }
2148
2149 return true;
2150 }
2151
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002152 if (constant.type == GL_SAMPLER_2D ||
2153 constant.type == GL_SAMPLER_CUBE)
2154 {
2155 unsigned int samplerIndex = constant.registerIndex;
2156
2157 do
2158 {
2159 if (shader == GL_VERTEX_SHADER)
2160 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002161 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002162 {
2163 mSamplersVS[samplerIndex].active = true;
2164 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2165 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2166 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2167 }
2168 else
2169 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002170 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002171 return false;
2172 }
2173 }
2174 else if (shader == GL_FRAGMENT_SHADER)
2175 {
2176 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2177 {
2178 mSamplersPS[samplerIndex].active = true;
2179 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2180 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2181 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2182 }
2183 else
2184 {
2185 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2186 return false;
2187 }
2188 }
2189 else UNREACHABLE();
2190
2191 samplerIndex++;
2192 }
2193 while (samplerIndex < constant.registerIndex + constant.arraySize);
2194 }
2195
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002196 Uniform *uniform = NULL;
2197 GLint location = getUniformLocation(constant.name);
2198
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002199 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002200 {
2201 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002202 }
2203 else
2204 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002205 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002206 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002207
2208 if (!uniform)
2209 {
2210 return false;
2211 }
2212
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002213 if (shader == GL_FRAGMENT_SHADER)
2214 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002215 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002216 }
2217 else if (shader == GL_VERTEX_SHADER)
2218 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002219 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002220 }
2221 else UNREACHABLE();
2222
2223 if (location >= 0)
2224 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002225 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002226 }
2227
2228 mUniforms.push_back(uniform);
2229 unsigned int uniformIndex = mUniforms.size() - 1;
2230
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002231 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002232 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002233 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002234 }
2235
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002236 if (shader == GL_VERTEX_SHADER)
2237 {
2238 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2239 {
2240 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2241 return false;
2242 }
2243 }
2244 else if (shader == GL_FRAGMENT_SHADER)
2245 {
2246 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2247 {
2248 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2249 return false;
2250 }
2251 }
2252 else UNREACHABLE();
2253
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002254 return true;
2255}
2256
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002257bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2258{
2259 const char* blockName = vertexInterfaceBlock.name.c_str();
2260
2261 // validate blocks for the same member types
2262 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2263 {
2264 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2265 return false;
2266 }
2267
2268 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2269 {
2270 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2271 return false;
2272 }
2273
2274 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2275 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2276 {
2277 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2278 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2279
2280 if (vertexMember.name != fragmentMember.name)
2281 {
2282 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2283 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2284 return false;
2285 }
2286
2287 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2288 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2289 {
2290 return false;
2291 }
2292 }
2293
2294 return true;
2295}
2296
2297bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2298{
2299 // Check that interface blocks defined in the vertex and fragment shaders are identical
2300 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2301 UniformBlockMap linkedUniformBlocks;
2302
2303 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2304 {
2305 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2306 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2307 }
2308
2309 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2310 {
2311 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2312 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2313 if (entry != linkedUniformBlocks.end())
2314 {
2315 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2316 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2317 {
2318 return false;
2319 }
2320 }
2321 }
2322
2323 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2324 {
2325 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2326 {
2327 return false;
2328 }
2329 }
2330
2331 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2332 {
2333 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2334 {
2335 return false;
2336 }
2337 }
2338
2339 return true;
2340}
2341
2342bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2343{
2344 // create uniform block entries if they do not exist
2345 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2346 {
2347 std::vector<unsigned int> blockUniformIndexes;
2348 const unsigned int blockIndex = mUniformBlocks.size();
2349
2350 // define member uniforms
2351 for (unsigned int activeUniformIndex = 0; activeUniformIndex < interfaceBlock.activeUniforms.size(); activeUniformIndex++)
2352 {
2353 const sh::Uniform &constant = interfaceBlock.activeUniforms[activeUniformIndex];
2354 Uniform *uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize,
2355 blockIndex, interfaceBlock.blockInfo[activeUniformIndex]);
2356
2357 // add to uniform list, but not index, since uniform block uniforms have no location
2358 blockUniformIndexes.push_back(mUniforms.size());
2359 mUniforms.push_back(uniform);
2360 }
2361
2362 // create all the uniform blocks
2363 if (interfaceBlock.arraySize > 0)
2364 {
2365 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2366 {
2367 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2368 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2369 mUniformBlocks.push_back(newUniformBlock);
2370 }
2371 }
2372 else
2373 {
2374 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2375 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2376 mUniformBlocks.push_back(newUniformBlock);
2377 }
2378 }
2379
2380 // Assign registers to the uniform blocks
2381 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2382 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2383 ASSERT(blockIndex != GL_INVALID_INDEX);
2384 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2385
2386 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2387 {
2388 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2389 ASSERT(uniformBlock->name == interfaceBlock.name);
2390
2391 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2392 {
2393 return false;
2394 }
2395 }
2396
2397 return true;
2398}
2399
2400bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2401{
2402 if (shader == GL_VERTEX_SHADER)
2403 {
2404 uniformBlock->vsRegisterIndex = registerIndex;
2405 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2406
2407 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2408 {
2409 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2410 return false;
2411 }
2412 }
2413 else if (shader == GL_FRAGMENT_SHADER)
2414 {
2415 uniformBlock->psRegisterIndex = registerIndex;
2416 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2417
2418 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2419 {
2420 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2421 return false;
2422 }
2423 }
2424 else UNREACHABLE();
2425
2426 return true;
2427}
2428
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002429std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2430{
2431 // for now we only handle point sprite emulation
2432 ASSERT(usesPointSpriteEmulation());
2433 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2434}
2435
2436std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2437{
2438 ASSERT(registers >= 0);
2439 ASSERT(vertexShader->mUsesPointSize);
2440 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2441
2442 std::string geomHLSL;
2443
2444 std::string varyingSemantic = "TEXCOORD";
2445
2446 std::string fragCoordSemantic;
2447 std::string pointCoordSemantic;
2448
2449 int reservedRegisterIndex = registers;
2450
2451 if (fragmentShader->mUsesFragCoord)
2452 {
2453 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2454 }
2455
2456 if (fragmentShader->mUsesPointCoord)
2457 {
2458 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2459 }
2460
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002461 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2462 "\n"
2463 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002464 "{\n";
2465
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002466 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002467
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002468 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002469
2470 if (fragmentShader->mUsesFragCoord)
2471 {
2472 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2473 }
2474
2475 geomHLSL += " float gl_PointSize : PSIZE;\n"
2476 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002477 "};\n"
2478 "\n"
2479 "struct GS_OUTPUT\n"
2480 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002481
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002482 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002483
2484 if (fragmentShader->mUsesFragCoord)
2485 {
2486 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2487 }
2488
2489 if (fragmentShader->mUsesPointCoord)
2490 {
2491 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2492 }
2493
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002494 geomHLSL += " float gl_PointSize : PSIZE;\n"
2495 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002496 "};\n"
2497 "\n"
2498 "static float2 pointSpriteCorners[] = \n"
2499 "{\n"
2500 " float2( 0.5f, -0.5f),\n"
2501 " float2( 0.5f, 0.5f),\n"
2502 " float2(-0.5f, -0.5f),\n"
2503 " float2(-0.5f, 0.5f)\n"
2504 "};\n"
2505 "\n"
2506 "static float2 pointSpriteTexcoords[] = \n"
2507 "{\n"
2508 " float2(1.0f, 1.0f),\n"
2509 " float2(1.0f, 0.0f),\n"
2510 " float2(0.0f, 1.0f),\n"
2511 " float2(0.0f, 0.0f)\n"
2512 "};\n"
2513 "\n"
2514 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2515 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2516 "\n"
2517 "[maxvertexcount(4)]\n"
2518 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2519 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002520 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2521 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002522
2523 for (int r = 0; r < registers; r++)
2524 {
2525 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2526 }
2527
2528 if (fragmentShader->mUsesFragCoord)
2529 {
2530 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2531 }
2532
2533 geomHLSL += " \n"
2534 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2535 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002536 " 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 +00002537
2538 for (int corner = 0; corner < 4; corner++)
2539 {
2540 geomHLSL += " \n"
2541 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2542
2543 if (fragmentShader->mUsesPointCoord)
2544 {
2545 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2546 }
2547
2548 geomHLSL += " outStream.Append(output);\n";
2549 }
2550
2551 geomHLSL += " \n"
2552 " outStream.RestartStrip();\n"
2553 "}\n";
2554
2555 return geomHLSL;
2556}
2557
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002558// This method needs to match OutputHLSL::decorate
2559std::string ProgramBinary::decorateAttribute(const std::string &name)
2560{
2561 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2562 {
2563 return "_" + name;
2564 }
2565
2566 return name;
2567}
2568
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002569bool ProgramBinary::isValidated() const
2570{
2571 return mValidated;
2572}
2573
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002574void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002575{
2576 // Skip over inactive attributes
2577 unsigned int activeAttribute = 0;
2578 unsigned int attribute;
2579 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2580 {
2581 if (mLinkedAttribute[attribute].name.empty())
2582 {
2583 continue;
2584 }
2585
2586 if (activeAttribute == index)
2587 {
2588 break;
2589 }
2590
2591 activeAttribute++;
2592 }
2593
2594 if (bufsize > 0)
2595 {
2596 const char *string = mLinkedAttribute[attribute].name.c_str();
2597
2598 strncpy(name, string, bufsize);
2599 name[bufsize - 1] = '\0';
2600
2601 if (length)
2602 {
2603 *length = strlen(name);
2604 }
2605 }
2606
2607 *size = 1; // Always a single 'type' instance
2608
2609 *type = mLinkedAttribute[attribute].type;
2610}
2611
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002612GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002613{
2614 int count = 0;
2615
2616 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2617 {
2618 if (!mLinkedAttribute[attributeIndex].name.empty())
2619 {
2620 count++;
2621 }
2622 }
2623
2624 return count;
2625}
2626
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002627GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002628{
2629 int maxLength = 0;
2630
2631 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2632 {
2633 if (!mLinkedAttribute[attributeIndex].name.empty())
2634 {
2635 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2636 }
2637 }
2638
2639 return maxLength;
2640}
2641
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002642void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002643{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002644 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002645
2646 if (bufsize > 0)
2647 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002648 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002649
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002650 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002651 {
2652 string += "[0]";
2653 }
2654
2655 strncpy(name, string.c_str(), bufsize);
2656 name[bufsize - 1] = '\0';
2657
2658 if (length)
2659 {
2660 *length = strlen(name);
2661 }
2662 }
2663
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002664 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002665
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002666 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002667}
2668
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002669GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002670{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002671 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002672}
2673
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002674GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002675{
2676 int maxLength = 0;
2677
2678 unsigned int numUniforms = mUniforms.size();
2679 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2680 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002681 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002682 {
2683 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2684 if (mUniforms[uniformIndex]->isArray())
2685 {
2686 length += 3; // Counting in "[0]".
2687 }
2688 maxLength = std::max(length, maxLength);
2689 }
2690 }
2691
2692 return maxLength;
2693}
2694
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002695GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2696{
2697 const gl::Uniform& uniform = *mUniforms[index];
2698
2699 switch (pname)
2700 {
2701 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2702 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
2703 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002704 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002705
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002706 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2707 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2708 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2709 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002710
2711 default:
2712 UNREACHABLE();
2713 break;
2714 }
2715 return 0;
2716}
2717
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002718void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2719{
2720 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2721
2722 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2723
2724 if (bufSize > 0)
2725 {
2726 std::string string = uniformBlock.name;
2727
2728 if (uniformBlock.isArrayElement())
2729 {
2730 string += "[" + str(uniformBlock.elementIndex) + "]";
2731 }
2732
2733 strncpy(uniformBlockName, string.c_str(), bufSize);
2734 uniformBlockName[bufSize - 1] = '\0';
2735
2736 if (length)
2737 {
2738 *length = strlen(uniformBlockName);
2739 }
2740 }
2741}
2742
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002743void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2744{
2745 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2746
2747 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2748
2749 switch (pname)
2750 {
2751 case GL_UNIFORM_BLOCK_DATA_SIZE:
2752 *params = static_cast<GLint>(uniformBlock.dataSize);
2753 break;
2754 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2755 *params = static_cast<GLint>(uniformBlock.name.size() + 1);
2756 break;
2757 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2758 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2759 break;
2760 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2761 {
2762 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2763 {
2764 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2765 }
2766 }
2767 break;
2768 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2769 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2770 break;
2771 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2772 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2773 break;
2774 default: UNREACHABLE();
2775 }
2776}
2777
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002778GLuint ProgramBinary::getActiveUniformBlockCount() const
2779{
2780 return mUniformBlocks.size();
2781}
2782
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002783GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2784{
2785 unsigned int maxLength = 0;
2786
2787 unsigned int numUniformBlocks = mUniformBlocks.size();
2788 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2789 {
2790 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2791 if (!uniformBlock.name.empty())
2792 {
2793 const unsigned int length = uniformBlock.name.length() + 1;
2794
2795 // Counting in "[0]".
2796 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2797
2798 maxLength = std::max(length + arrayLength, maxLength);
2799 }
2800 }
2801
2802 return maxLength;
2803}
2804
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002805void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002806{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002807 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002808 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002809 {
2810 mValidated = false;
2811 }
2812 else
2813 {
2814 mValidated = true;
2815 }
2816}
2817
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002818bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002819{
2820 // if any two active samplers in a program are of different types, but refer to the same
2821 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2822 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2823
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002824 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002825 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002826
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002827 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002828 {
2829 textureUnitType[i] = TEXTURE_UNKNOWN;
2830 }
2831
2832 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2833 {
2834 if (mSamplersPS[i].active)
2835 {
2836 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2837
2838 if (unit >= maxCombinedTextureImageUnits)
2839 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002840 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002841 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002842 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002843 }
2844
2845 return false;
2846 }
2847
2848 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2849 {
2850 if (mSamplersPS[i].textureType != textureUnitType[unit])
2851 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002852 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002853 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002854 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002855 }
2856
2857 return false;
2858 }
2859 }
2860 else
2861 {
2862 textureUnitType[unit] = mSamplersPS[i].textureType;
2863 }
2864 }
2865 }
2866
2867 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2868 {
2869 if (mSamplersVS[i].active)
2870 {
2871 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2872
2873 if (unit >= maxCombinedTextureImageUnits)
2874 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002875 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002876 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002877 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002878 }
2879
2880 return false;
2881 }
2882
2883 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2884 {
2885 if (mSamplersVS[i].textureType != textureUnitType[unit])
2886 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002887 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002888 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002889 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002890 }
2891
2892 return false;
2893 }
2894 }
2895 else
2896 {
2897 textureUnitType[unit] = mSamplersVS[i].textureType;
2898 }
2899 }
2900 }
2901
2902 return true;
2903}
2904
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002905ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2906{
2907}
2908
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002909struct AttributeSorter
2910{
2911 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2912 : originalIndices(semanticIndices)
2913 {
2914 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2915 {
2916 indices[i] = i;
2917 }
2918
2919 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2920 }
2921
2922 bool operator()(int a, int b)
2923 {
2924 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2925 }
2926
2927 int indices[MAX_VERTEX_ATTRIBS];
2928 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2929};
2930
2931void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2932{
2933 AttributeSorter sorter(mSemanticIndex);
2934
2935 int oldIndices[MAX_VERTEX_ATTRIBS];
2936 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2937
2938 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2939 {
2940 oldIndices[i] = mSemanticIndex[i];
2941 oldTranslatedAttributes[i] = attributes[i];
2942 }
2943
2944 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2945 {
2946 int oldIndex = sorter.indices[i];
2947 sortedSemanticIndices[i] = oldIndices[oldIndex];
2948 attributes[i] = oldTranslatedAttributes[oldIndex];
2949 }
2950}
2951
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002952}