blob: 64efe44504c3198e95a93b012edc2d5a89386fa5 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002//
daniel@transgaming.coma390e1e2013-01-11 04:09:39 +00003// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Program.cpp: Implements the gl::Program class. Implements GL program objects
9// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
10
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +000011#include "libGLESv2/BinaryStream.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000012#include "libGLESv2/ProgramBinary.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000013#include "libGLESv2/renderer/ShaderExecutable.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000014
15#include "common/debug.h"
apatrick@chromium.org90080e32012-07-09 22:15:33 +000016#include "common/version.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000017#include "common/utilities.h"
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000018
19#include "libGLESv2/main.h"
20#include "libGLESv2/Shader.h"
shannon.woods@transgaming.comd2811d62013-02-28 23:11:19 +000021#include "libGLESv2/Program.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000022#include "libGLESv2/renderer/Renderer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000023#include "libGLESv2/renderer/VertexDataManager.h"
shannon.woods%transgaming.com@gtempaccount.com0b05b7a2013-04-13 03:34:58 +000024#include "libGLESv2/Context.h"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000025#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000026
daniel@transgaming.com88853c52012-12-20 20:56:40 +000027#undef near
28#undef far
29
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000030namespace gl
31{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000032std::string str(int i)
33{
34 char buffer[20];
35 snprintf(buffer, sizeof(buffer), "%d", i);
36 return buffer;
37}
38
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000039namespace
40{
41
42unsigned int parseAndStripArrayIndex(std::string* name)
43{
44 unsigned int subscript = GL_INVALID_INDEX;
45
46 // Strip any trailing array operator and retrieve the subscript
47 size_t open = name->find_last_of('[');
48 size_t close = name->find_last_of(']');
49 if (open != std::string::npos && close == name->length() - 1)
50 {
51 subscript = atoi(name->substr(open + 1).c_str());
52 name->erase(open);
53 }
54
55 return subscript;
56}
57
58}
59
daniel@transgaming.comdb019952012-12-20 21:13:32 +000060UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
61 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000062{
63}
64
daniel@transgaming.come87ca002012-07-24 18:30:43 +000065unsigned int ProgramBinary::mCurrentSerial = 1;
66
daniel@transgaming.com77fbf972012-11-28 21:02:55 +000067ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000068{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000069 mPixelExecutable = NULL;
70 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000071 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000072
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000073 mValidated = false;
74
75 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
76 {
77 mSemanticIndex[index] = -1;
78 }
79
80 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
81 {
82 mSamplersPS[index].active = false;
83 }
84
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +000085 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000086 {
87 mSamplersVS[index].active = false;
88 }
89
90 mUsedVertexSamplerRange = 0;
91 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +000092 mUsesPointSize = false;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000093}
94
95ProgramBinary::~ProgramBinary()
96{
daniel@transgaming.com95892412012-11-28 20:59:09 +000097 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000098 mPixelExecutable = NULL;
99
daniel@transgaming.com95892412012-11-28 20:59:09 +0000100 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000101 mVertexExecutable = NULL;
102
103 delete mGeometryExecutable;
104 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000105
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106 while (!mUniforms.empty())
107 {
108 delete mUniforms.back();
109 mUniforms.pop_back();
110 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000111
112 while (!mUniformBlocks.empty())
113 {
114 delete mUniformBlocks.back();
115 mUniformBlocks.pop_back();
116 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000117}
118
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000119unsigned int ProgramBinary::getSerial() const
120{
121 return mSerial;
122}
123
124unsigned int ProgramBinary::issueSerial()
125{
126 return mCurrentSerial++;
127}
128
daniel@transgaming.com95892412012-11-28 20:59:09 +0000129rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000130{
131 return mPixelExecutable;
132}
133
daniel@transgaming.com95892412012-11-28 20:59:09 +0000134rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135{
136 return mVertexExecutable;
137}
138
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000139rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
140{
141 return mGeometryExecutable;
142}
143
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000144GLuint ProgramBinary::getAttributeLocation(const char *name)
145{
146 if (name)
147 {
148 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
149 {
150 if (mLinkedAttribute[index].name == std::string(name))
151 {
152 return index;
153 }
154 }
155 }
156
157 return -1;
158}
159
160int ProgramBinary::getSemanticIndex(int attributeIndex)
161{
162 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
163
164 return mSemanticIndex[attributeIndex];
165}
166
167// Returns one more than the highest sampler index used.
168GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
169{
170 switch (type)
171 {
172 case SAMPLER_PIXEL:
173 return mUsedPixelSamplerRange;
174 case SAMPLER_VERTEX:
175 return mUsedVertexSamplerRange;
176 default:
177 UNREACHABLE();
178 return 0;
179 }
180}
181
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000182bool ProgramBinary::usesPointSize() const
183{
184 return mUsesPointSize;
185}
186
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000187bool ProgramBinary::usesPointSpriteEmulation() const
188{
189 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
190}
191
192bool ProgramBinary::usesGeometryShader() const
193{
194 return usesPointSpriteEmulation();
195}
196
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000197// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
198// index (0-15 for the pixel shader and 0-3 for the vertex shader).
199GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
200{
201 GLint logicalTextureUnit = -1;
202
203 switch (type)
204 {
205 case SAMPLER_PIXEL:
206 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
207
208 if (mSamplersPS[samplerIndex].active)
209 {
210 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
211 }
212 break;
213 case SAMPLER_VERTEX:
214 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
215
216 if (mSamplersVS[samplerIndex].active)
217 {
218 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
219 }
220 break;
221 default: UNREACHABLE();
222 }
223
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000224 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000225 {
226 return logicalTextureUnit;
227 }
228
229 return -1;
230}
231
232// Returns the texture type for a given Direct3D 9 sampler type and
233// index (0-15 for the pixel shader and 0-3 for the vertex shader).
234TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
235{
236 switch (type)
237 {
238 case SAMPLER_PIXEL:
239 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
240 ASSERT(mSamplersPS[samplerIndex].active);
241 return mSamplersPS[samplerIndex].textureType;
242 case SAMPLER_VERTEX:
243 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
244 ASSERT(mSamplersVS[samplerIndex].active);
245 return mSamplersVS[samplerIndex].textureType;
246 default: UNREACHABLE();
247 }
248
249 return TEXTURE_2D;
250}
251
252GLint ProgramBinary::getUniformLocation(std::string name)
253{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000254 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000255
256 unsigned int numUniforms = mUniformIndex.size();
257 for (unsigned int location = 0; location < numUniforms; location++)
258 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000259 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000260 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000261 const int index = mUniformIndex[location].index;
262 const bool isArray = mUniforms[index]->isArray();
263
264 if ((isArray && mUniformIndex[location].element == subscript) ||
265 (subscript == GL_INVALID_INDEX))
266 {
267 return location;
268 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000269 }
270 }
271
272 return -1;
273}
274
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000275GLuint ProgramBinary::getUniformIndex(std::string name)
276{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000277 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000278
279 // The app is not allowed to specify array indices other than 0 for arrays of basic types
280 if (subscript != 0 && subscript != GL_INVALID_INDEX)
281 {
282 return GL_INVALID_INDEX;
283 }
284
285 unsigned int numUniforms = mUniforms.size();
286 for (unsigned int index = 0; index < numUniforms; index++)
287 {
288 if (mUniforms[index]->name == name)
289 {
290 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
291 {
292 return index;
293 }
294 }
295 }
296
297 return GL_INVALID_INDEX;
298}
299
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000300GLuint ProgramBinary::getUniformBlockIndex(std::string name)
301{
302 unsigned int subscript = parseAndStripArrayIndex(&name);
303
304 unsigned int numUniformBlocks = mUniformBlocks.size();
305 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
306 {
307 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
308 if (uniformBlock.name == name)
309 {
310 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
311 if (subscript == uniformBlock.elementIndex || arrayElementZero)
312 {
313 return blockIndex;
314 }
315 }
316 }
317
318 return GL_INVALID_INDEX;
319}
320
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000321UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
322{
323 ASSERT(blockIndex < mUniformBlocks.size());
324 return mUniformBlocks[blockIndex];
325}
326
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000327template <typename T>
328bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000329{
330 if (location < 0 || location >= (int)mUniformIndex.size())
331 {
332 return false;
333 }
334
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000335 const int components = UniformComponentCount(targetUniformType);
336 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
337
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000338 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
339 targetUniform->dirty = true;
340
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000341 int elementCount = targetUniform->elementCount();
342
343 if (elementCount == 1 && count > 1)
344 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
345
346 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
347
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000348 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000349 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000350 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000351
352 for (int i = 0; i < count; i++)
353 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000354 for (int c = 0; c < components; c++)
355 {
356 target[c] = v[c];
357 }
358 for (int c = components; c < 4; c++)
359 {
360 target[c] = 0;
361 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000362 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000363 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000364 }
365 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000366 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000367 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000368 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000369
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000370 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000371 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000372 for (int c = 0; c < components; c++)
373 {
374 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
375 }
376 for (int c = components; c < 4; c++)
377 {
378 boolParams[c] = GL_FALSE;
379 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000380 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000381 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000382 }
383 }
384 else
385 {
386 return false;
387 }
388
389 return true;
390}
391
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000392bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
393{
394 return setUniform(location, count, v, GL_FLOAT);
395}
396
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000397bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
398{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000399 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000400}
401
402bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
403{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000404 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000405}
406
407bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
408{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000409 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000410}
411
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000412template<typename T>
413void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000414{
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
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001181 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1182 {
1183 vertexHLSL += "\n"
1184 " dx_initConstantBuffers();\n";
1185 }
1186
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001187 if (shaderModel >= 4)
1188 {
1189 vertexHLSL += "\n"
1190 " gl_main();\n"
1191 "\n"
1192 " VS_OUTPUT output;\n"
1193 " output.gl_Position.x = gl_Position.x;\n"
1194 " output.gl_Position.y = -gl_Position.y;\n"
1195 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1196 " output.gl_Position.w = gl_Position.w;\n";
1197 }
1198 else
1199 {
1200 vertexHLSL += "\n"
1201 " gl_main();\n"
1202 "\n"
1203 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001204 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1205 " 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 +00001206 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1207 " output.gl_Position.w = gl_Position.w;\n";
1208 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001209
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001210 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001211 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001212 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001213 }
1214
1215 if (fragmentShader->mUsesFragCoord)
1216 {
1217 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1218 }
1219
1220 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1221 {
1222 if (varying->reg >= 0)
1223 {
1224 for (int i = 0; i < varying->size; i++)
1225 {
1226 int rows = VariableRowCount(varying->type);
1227
1228 for (int j = 0; j < rows; j++)
1229 {
1230 int r = varying->reg + i * rows + j;
1231 vertexHLSL += " output.v" + str(r);
1232
1233 bool sharedRegister = false; // Register used by multiple varyings
1234
1235 for (int x = 0; x < 4; x++)
1236 {
1237 if (packing[r][x] && packing[r][x] != packing[r][0])
1238 {
1239 sharedRegister = true;
1240 break;
1241 }
1242 }
1243
1244 if(sharedRegister)
1245 {
1246 vertexHLSL += ".";
1247
1248 for (int x = 0; x < 4; x++)
1249 {
1250 if (packing[r][x] == &*varying)
1251 {
1252 switch(x)
1253 {
1254 case 0: vertexHLSL += "x"; break;
1255 case 1: vertexHLSL += "y"; break;
1256 case 2: vertexHLSL += "z"; break;
1257 case 3: vertexHLSL += "w"; break;
1258 }
1259 }
1260 }
1261 }
1262
1263 vertexHLSL += " = " + varying->name;
1264
1265 if (varying->array)
1266 {
1267 vertexHLSL += "[" + str(i) + "]";
1268 }
1269
1270 if (rows > 1)
1271 {
1272 vertexHLSL += "[" + str(j) + "]";
1273 }
1274
1275 vertexHLSL += ";\n";
1276 }
1277 }
1278 }
1279 }
1280
1281 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001282 " return output;\n"
1283 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001284
1285 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001286 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001287
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001288 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001289
1290 if (fragmentShader->mUsesFragCoord)
1291 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001292 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001293 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001294
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001295 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1296 {
1297 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1298 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001299
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001300 // Must consume the PSIZE element if the geometry shader is not active
1301 // We won't know if we use a GS until we draw
1302 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1303 {
1304 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1305 }
1306
1307 if (fragmentShader->mUsesFragCoord)
1308 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001309 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001310 {
1311 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1312 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001313 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001314 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001315 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1316 }
1317 }
1318
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001319 pixelHLSL += "};\n"
1320 "\n"
1321 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001322 "{\n";
1323
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001324 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001325 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001326 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001327 }
1328
1329 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001330 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001331
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001332 if (fragmentShader->mUsesFrontFacing)
1333 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001334 if (shaderModel >= 4)
1335 {
1336 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1337 "{\n";
1338 }
1339 else
1340 {
1341 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1342 "{\n";
1343 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001344 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001345 else
1346 {
1347 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1348 "{\n";
1349 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001350
1351 if (fragmentShader->mUsesFragCoord)
1352 {
1353 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1354
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001355 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001356 {
1357 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1358 " gl_FragCoord.y = input.dx_VPos.y;\n";
1359 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001360 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001361 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001362 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001363 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001364 }
1365 else
1366 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001367 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1368 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1369 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001370 }
1371
daniel@transgaming.com12985182012-12-20 20:56:31 +00001372 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001373 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001374 }
1375
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001376 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001377 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001378 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1379 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001380 }
1381
1382 if (fragmentShader->mUsesFrontFacing)
1383 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001384 if (shaderModel <= 3)
1385 {
1386 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1387 }
1388 else
1389 {
1390 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1391 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001392 }
1393
1394 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1395 {
1396 if (varying->reg >= 0)
1397 {
1398 for (int i = 0; i < varying->size; i++)
1399 {
1400 int rows = VariableRowCount(varying->type);
1401 for (int j = 0; j < rows; j++)
1402 {
1403 std::string n = str(varying->reg + i * rows + j);
1404 pixelHLSL += " " + varying->name;
1405
1406 if (varying->array)
1407 {
1408 pixelHLSL += "[" + str(i) + "]";
1409 }
1410
1411 if (rows > 1)
1412 {
1413 pixelHLSL += "[" + str(j) + "]";
1414 }
1415
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001416 switch (VariableColumnCount(varying->type))
1417 {
1418 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1419 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1420 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1421 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1422 default: UNREACHABLE();
1423 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001424 }
1425 }
1426 }
1427 else UNREACHABLE();
1428 }
1429
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001430 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1431 {
1432 pixelHLSL += "\n"
1433 " dx_initConstantBuffers();\n";
1434 }
1435
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001436 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001437 " gl_main();\n"
1438 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001439 " PS_OUTPUT output;\n";
1440
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001441 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001442 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001443 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001444
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001445 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001446 }
1447
1448 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001449 " return output;\n"
1450 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001451
1452 return true;
1453}
1454
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001455std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1456{
1457 std::string varyingHLSL;
1458
1459 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1460 {
1461 if (varying->reg >= 0)
1462 {
1463 for (int i = 0; i < varying->size; i++)
1464 {
1465 int rows = VariableRowCount(varying->type);
1466 for (int j = 0; j < rows; j++)
1467 {
1468 switch (varying->interpolation)
1469 {
1470 case Smooth: varyingHLSL += " "; break;
1471 case Flat: varyingHLSL += " nointerpolation "; break;
1472 case Centroid: varyingHLSL += " centroid "; break;
1473 default: UNREACHABLE();
1474 }
1475
1476 std::string n = str(varying->reg + i * rows + j);
1477 varyingHLSL += "float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
1478 }
1479 }
1480 }
1481 else UNREACHABLE();
1482 }
1483
1484 return varyingHLSL;
1485}
1486
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001487bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1488{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001489 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001490
1491 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001492 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001493 if (format != GL_PROGRAM_BINARY_ANGLE)
1494 {
1495 infoLog.append("Invalid program binary format.");
1496 return false;
1497 }
1498
1499 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001500 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001501 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001502 {
1503 infoLog.append("Invalid program binary version.");
1504 return false;
1505 }
1506
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001507 int compileFlags = 0;
1508 stream.read(&compileFlags);
1509 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1510 {
1511 infoLog.append("Mismatched compilation flags.");
1512 return false;
1513 }
1514
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001515 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1516 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001517 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001518 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001519 stream.read(&name);
1520 mLinkedAttribute[i].name = name;
1521 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001522 }
1523
1524 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1525 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001526 stream.read(&mSamplersPS[i].active);
1527 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001528
1529 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001530 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001531 mSamplersPS[i].textureType = (TextureType) textureType;
1532 }
1533
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001534 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001535 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001536 stream.read(&mSamplersVS[i].active);
1537 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001538
1539 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001540 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001541 mSamplersVS[i].textureType = (TextureType) textureType;
1542 }
1543
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001544 stream.read(&mUsedVertexSamplerRange);
1545 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001546 stream.read(&mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001547
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001548 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001549 stream.read(&size);
1550 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001551 {
1552 infoLog.append("Invalid program binary.");
1553 return false;
1554 }
1555
1556 mUniforms.resize(size);
1557 for (unsigned int i = 0; i < size; ++i)
1558 {
1559 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001560 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001561 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001562 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001563 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001564
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001565 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001566 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001567 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001568 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001569 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001570
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001571 int offset;
1572 int arrayStride;
1573 int matrixStride;
1574 bool isRowMajorMatrix;
1575
1576 stream.read(&offset);
1577 stream.read(&arrayStride);
1578 stream.read(&matrixStride);
1579 stream.read(&isRowMajorMatrix);
1580
1581 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1582
1583 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001584
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001585 stream.read(&mUniforms[i]->psRegisterIndex);
1586 stream.read(&mUniforms[i]->vsRegisterIndex);
1587 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001588 }
1589
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001590 stream.read(&size);
1591 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001592 {
1593 infoLog.append("Invalid program binary.");
1594 return false;
1595 }
1596
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001597 mUniformBlocks.resize(size);
1598 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1599 {
1600 std::string name;
1601 unsigned int elementIndex;
1602 unsigned int dataSize;
1603
1604 stream.read(&name);
1605 stream.read(&elementIndex);
1606 stream.read(&dataSize);
1607
1608 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1609
1610 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1611 stream.read(&uniformBlock.psRegisterIndex);
1612 stream.read(&uniformBlock.vsRegisterIndex);
1613
1614 size_t numMembers;
1615 stream.read(&numMembers);
1616 uniformBlock.memberUniformIndexes.resize(numMembers);
1617 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1618 {
1619 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1620 }
1621 }
1622
1623 stream.read(&size);
1624 if (stream.error())
1625 {
1626 infoLog.append("Invalid program binary.");
1627 return false;
1628 }
1629
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001630 mUniformIndex.resize(size);
1631 for (unsigned int i = 0; i < size; ++i)
1632 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001633 stream.read(&mUniformIndex[i].name);
1634 stream.read(&mUniformIndex[i].element);
1635 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001636 }
1637
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001639 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001640
1641 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001642 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001643
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001644 unsigned int geometryShaderSize;
1645 stream.read(&geometryShaderSize);
1646
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001648
daniel@transgaming.com36038542012-11-28 20:59:26 +00001649 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001650 ptr += sizeof(GUID);
1651
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001652 GUID identifier = mRenderer->getAdapterIdentifier();
1653 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001654 {
1655 infoLog.append("Invalid program binary.");
1656 return false;
1657 }
1658
1659 const char *pixelShaderFunction = ptr;
1660 ptr += pixelShaderSize;
1661
1662 const char *vertexShaderFunction = ptr;
1663 ptr += vertexShaderSize;
1664
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001665 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1666 ptr += geometryShaderSize;
1667
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001668 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001669 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001670 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671 {
1672 infoLog.append("Could not create pixel shader.");
1673 return false;
1674 }
1675
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001676 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001677 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001678 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 {
1680 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001681 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001682 mPixelExecutable = NULL;
1683 return false;
1684 }
1685
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001686 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1687 {
1688 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1689 geometryShaderSize, rx::SHADER_GEOMETRY);
1690 if (!mGeometryExecutable)
1691 {
1692 infoLog.append("Could not create geometry shader.");
1693 delete mPixelExecutable;
1694 mPixelExecutable = NULL;
1695 delete mVertexExecutable;
1696 mVertexExecutable = NULL;
1697 return false;
1698 }
1699 }
1700 else
1701 {
1702 mGeometryExecutable = NULL;
1703 }
1704
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001705 return true;
1706}
1707
1708bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1709{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001710 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001711
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001712 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001713 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001714 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001715
1716 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1717 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001718 stream.write(mLinkedAttribute[i].type);
1719 stream.write(mLinkedAttribute[i].name);
1720 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001721 }
1722
1723 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1724 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001725 stream.write(mSamplersPS[i].active);
1726 stream.write(mSamplersPS[i].logicalTextureUnit);
1727 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001728 }
1729
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001730 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001731 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001732 stream.write(mSamplersVS[i].active);
1733 stream.write(mSamplersVS[i].logicalTextureUnit);
1734 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001735 }
1736
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001737 stream.write(mUsedVertexSamplerRange);
1738 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001739 stream.write(mUsesPointSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001740
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001741 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001742 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001744 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001745
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001746 stream.write(uniform.type);
1747 stream.write(uniform.precision);
1748 stream.write(uniform.name);
1749 stream.write(uniform.arraySize);
1750 stream.write(uniform.blockIndex);
1751
1752 stream.write(uniform.blockInfo.offset);
1753 stream.write(uniform.blockInfo.arrayStride);
1754 stream.write(uniform.blockInfo.matrixStride);
1755 stream.write(uniform.blockInfo.isRowMajorMatrix);
1756
1757 stream.write(uniform.psRegisterIndex);
1758 stream.write(uniform.vsRegisterIndex);
1759 stream.write(uniform.registerCount);
1760 }
1761
1762 stream.write(mUniformBlocks.size());
1763 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1764 {
1765 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1766
1767 stream.write(uniformBlock.name);
1768 stream.write(uniformBlock.elementIndex);
1769 stream.write(uniformBlock.dataSize);
1770
1771 stream.write(uniformBlock.memberUniformIndexes.size());
1772 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1773 {
1774 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1775 }
1776
1777 stream.write(uniformBlock.psRegisterIndex);
1778 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001779 }
1780
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001781 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001782 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1783 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001784 stream.write(mUniformIndex[i].name);
1785 stream.write(mUniformIndex[i].element);
1786 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001787 }
1788
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001789 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001790 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001792 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001793 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001794
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001795 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1796 stream.write(geometryShaderSize);
1797
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001798 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001799
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001800 GLsizei streamLength = stream.length();
1801 const void *streamData = stream.data();
1802
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001803 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001804 if (totalLength > bufSize)
1805 {
1806 if (length)
1807 {
1808 *length = 0;
1809 }
1810
1811 return false;
1812 }
1813
1814 if (binary)
1815 {
1816 char *ptr = (char*) binary;
1817
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001818 memcpy(ptr, streamData, streamLength);
1819 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001820
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001821 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822 ptr += sizeof(GUID);
1823
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001824 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001825 ptr += pixelShaderSize;
1826
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001827 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001828 ptr += vertexShaderSize;
1829
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001830 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1831 {
1832 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1833 ptr += geometryShaderSize;
1834 }
1835
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001836 ASSERT(ptr - totalLength == binary);
1837 }
1838
1839 if (length)
1840 {
1841 *length = totalLength;
1842 }
1843
1844 return true;
1845}
1846
1847GLint ProgramBinary::getLength()
1848{
1849 GLint length;
1850 if (save(NULL, INT_MAX, &length))
1851 {
1852 return length;
1853 }
1854 else
1855 {
1856 return 0;
1857 }
1858}
1859
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001860bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001861{
1862 if (!fragmentShader || !fragmentShader->isCompiled())
1863 {
1864 return false;
1865 }
1866
1867 if (!vertexShader || !vertexShader->isCompiled())
1868 {
1869 return false;
1870 }
1871
1872 std::string pixelHLSL = fragmentShader->getHLSL();
1873 std::string vertexHLSL = vertexShader->getHLSL();
1874
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001875 // Map the varyings to the register file
1876 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1877 int registers = packVaryings(infoLog, packing, fragmentShader);
1878
1879 if (registers < 0)
1880 {
1881 return false;
1882 }
1883
1884 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001885 {
1886 return false;
1887 }
1888
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001889 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001890 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1891 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001892
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001893 if (usesGeometryShader())
1894 {
1895 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1896 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1897 }
1898
1899 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001900 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001901 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001902 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001903
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001904 delete mVertexExecutable;
1905 mVertexExecutable = NULL;
1906 delete mPixelExecutable;
1907 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001908 delete mGeometryExecutable;
1909 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001910 }
1911
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001912 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1913 {
1914 success = false;
1915 }
1916
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001917 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001918 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001919 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001920 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001921
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001922 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1923 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1924 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001925 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1926 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1927 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 +00001928 }
1929
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001930 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1931 {
1932 success = false;
1933 }
1934
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001935 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001936}
1937
1938// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001939bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001940{
1941 unsigned int usedLocations = 0;
1942
1943 // Link attributes that have a binding location
1944 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1945 {
1946 int location = attributeBindings.getAttributeBinding(attribute->name);
1947
1948 if (location != -1) // Set by glBindAttribLocation
1949 {
1950 if (!mLinkedAttribute[location].name.empty())
1951 {
1952 // Multiple active attributes bound to the same location; not an error
1953 }
1954
1955 mLinkedAttribute[location] = *attribute;
1956
1957 int rows = VariableRowCount(attribute->type);
1958
1959 if (rows + location > MAX_VERTEX_ATTRIBS)
1960 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001961 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 +00001962
1963 return false;
1964 }
1965
1966 for (int i = 0; i < rows; i++)
1967 {
1968 usedLocations |= 1 << (location + i);
1969 }
1970 }
1971 }
1972
1973 // Link attributes that don't have a binding location
1974 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1975 {
1976 int location = attributeBindings.getAttributeBinding(attribute->name);
1977
1978 if (location == -1) // Not set by glBindAttribLocation
1979 {
1980 int rows = VariableRowCount(attribute->type);
1981 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1982
1983 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1984 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001985 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001986
1987 return false; // Fail to link
1988 }
1989
1990 mLinkedAttribute[availableIndex] = *attribute;
1991 }
1992 }
1993
1994 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
1995 {
1996 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
1997 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
1998
1999 for (int r = 0; r < rows; r++)
2000 {
2001 mSemanticIndex[attributeIndex++] = index++;
2002 }
2003 }
2004
2005 return true;
2006}
2007
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002008bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2009{
2010 if (vertexUniform.type != fragmentUniform.type)
2011 {
2012 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2013 return false;
2014 }
2015 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2016 {
2017 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2018 return false;
2019 }
2020 else if (vertexUniform.precision != fragmentUniform.precision)
2021 {
2022 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2023 return false;
2024 }
2025 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2026 {
2027 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2028 }
2029
2030 const unsigned int numMembers = vertexUniform.fields.size();
2031 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2032 {
2033 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2034 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2035
2036 if (vertexMember.name != fragmentMember.name)
2037 {
2038 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2039 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2040 return false;
2041 }
2042
2043 const std::string memberName = uniformName + "." + vertexUniform.name;
2044 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2045 {
2046 return false;
2047 }
2048 }
2049
2050 return true;
2051}
2052
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002053bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002054{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002055 // Check that uniforms defined in the vertex and fragment shaders are identical
2056 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2057 UniformMap linkedUniforms;
2058
2059 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2060 {
2061 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2062 linkedUniforms[vertexUniform.name] = &vertexUniform;
2063 }
2064
2065 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2066 {
2067 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2068 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2069 if (entry != linkedUniforms.end())
2070 {
2071 const sh::Uniform &vertexUniform = *entry->second;
2072 const std::string &uniformName = "uniform " + vertexUniform.name;
2073 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2074 {
2075 return false;
2076 }
2077 }
2078 }
2079
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002080 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002081 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002082 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002083 {
2084 return false;
2085 }
2086 }
2087
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002088 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002089 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002090 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002091 {
2092 return false;
2093 }
2094 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002095
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002096 return true;
2097}
2098
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002099int totalRegisterCount(const sh::Uniform &uniform)
2100{
2101 int registerCount = 0;
2102
2103 if (!uniform.fields.empty())
2104 {
2105 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2106 {
2107 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2108 }
2109 }
2110 else
2111 {
2112 registerCount = 1;
2113 }
2114
2115 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2116}
2117
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002118bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002119{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002120 if (!constant.fields.empty())
2121 {
2122 if (constant.arraySize > 0)
2123 {
2124 unsigned int elementRegisterIndex = constant.registerIndex;
2125
2126 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2127 {
2128 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2129 {
2130 const sh::Uniform &field = constant.fields[fieldIndex];
2131 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2132 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2133 if (!defineUniform(shader, fieldUniform, infoLog))
2134 {
2135 return false;
2136 }
2137 elementRegisterIndex += totalRegisterCount(field);
2138 }
2139 }
2140 }
2141 else
2142 {
2143 unsigned int fieldRegisterIndex = constant.registerIndex;
2144
2145 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2146 {
2147 const sh::Uniform &field = constant.fields[fieldIndex];
2148 const std::string &uniformName = constant.name + "." + field.name;
2149
2150 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2151 fieldUniform.fields = field.fields;
2152
2153 if (!defineUniform(shader, fieldUniform, infoLog))
2154 {
2155 return false;
2156 }
2157 fieldRegisterIndex += totalRegisterCount(field);
2158 }
2159 }
2160
2161 return true;
2162 }
2163
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002164 if (constant.type == GL_SAMPLER_2D ||
2165 constant.type == GL_SAMPLER_CUBE)
2166 {
2167 unsigned int samplerIndex = constant.registerIndex;
2168
2169 do
2170 {
2171 if (shader == GL_VERTEX_SHADER)
2172 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002173 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002174 {
2175 mSamplersVS[samplerIndex].active = true;
2176 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2177 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2178 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2179 }
2180 else
2181 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002182 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002183 return false;
2184 }
2185 }
2186 else if (shader == GL_FRAGMENT_SHADER)
2187 {
2188 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2189 {
2190 mSamplersPS[samplerIndex].active = true;
2191 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2192 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2193 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2194 }
2195 else
2196 {
2197 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2198 return false;
2199 }
2200 }
2201 else UNREACHABLE();
2202
2203 samplerIndex++;
2204 }
2205 while (samplerIndex < constant.registerIndex + constant.arraySize);
2206 }
2207
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002208 Uniform *uniform = NULL;
2209 GLint location = getUniformLocation(constant.name);
2210
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002211 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002212 {
2213 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002214 }
2215 else
2216 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002217 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002218 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002219
2220 if (!uniform)
2221 {
2222 return false;
2223 }
2224
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002225 if (shader == GL_FRAGMENT_SHADER)
2226 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002227 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002228 }
2229 else if (shader == GL_VERTEX_SHADER)
2230 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002231 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002232 }
2233 else UNREACHABLE();
2234
2235 if (location >= 0)
2236 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002237 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002238 }
2239
2240 mUniforms.push_back(uniform);
2241 unsigned int uniformIndex = mUniforms.size() - 1;
2242
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002243 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002244 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002245 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002246 }
2247
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002248 if (shader == GL_VERTEX_SHADER)
2249 {
2250 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2251 {
2252 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2253 return false;
2254 }
2255 }
2256 else if (shader == GL_FRAGMENT_SHADER)
2257 {
2258 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2259 {
2260 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2261 return false;
2262 }
2263 }
2264 else UNREACHABLE();
2265
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002266 return true;
2267}
2268
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002269bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2270{
2271 const char* blockName = vertexInterfaceBlock.name.c_str();
2272
2273 // validate blocks for the same member types
2274 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2275 {
2276 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2277 return false;
2278 }
2279
2280 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2281 {
2282 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2283 return false;
2284 }
2285
2286 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2287 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2288 {
2289 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2290 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2291
2292 if (vertexMember.name != fragmentMember.name)
2293 {
2294 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2295 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2296 return false;
2297 }
2298
2299 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2300 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2301 {
2302 return false;
2303 }
2304 }
2305
2306 return true;
2307}
2308
2309bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2310{
2311 // Check that interface blocks defined in the vertex and fragment shaders are identical
2312 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2313 UniformBlockMap linkedUniformBlocks;
2314
2315 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2316 {
2317 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2318 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2319 }
2320
2321 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2322 {
2323 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2324 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2325 if (entry != linkedUniformBlocks.end())
2326 {
2327 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2328 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2329 {
2330 return false;
2331 }
2332 }
2333 }
2334
2335 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2336 {
2337 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2338 {
2339 return false;
2340 }
2341 }
2342
2343 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2344 {
2345 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2346 {
2347 return false;
2348 }
2349 }
2350
2351 return true;
2352}
2353
2354bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2355{
2356 // create uniform block entries if they do not exist
2357 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2358 {
2359 std::vector<unsigned int> blockUniformIndexes;
2360 const unsigned int blockIndex = mUniformBlocks.size();
2361
2362 // define member uniforms
2363 for (unsigned int activeUniformIndex = 0; activeUniformIndex < interfaceBlock.activeUniforms.size(); activeUniformIndex++)
2364 {
2365 const sh::Uniform &constant = interfaceBlock.activeUniforms[activeUniformIndex];
2366 Uniform *uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize,
2367 blockIndex, interfaceBlock.blockInfo[activeUniformIndex]);
2368
2369 // add to uniform list, but not index, since uniform block uniforms have no location
2370 blockUniformIndexes.push_back(mUniforms.size());
2371 mUniforms.push_back(uniform);
2372 }
2373
2374 // create all the uniform blocks
2375 if (interfaceBlock.arraySize > 0)
2376 {
2377 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2378 {
2379 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2380 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2381 mUniformBlocks.push_back(newUniformBlock);
2382 }
2383 }
2384 else
2385 {
2386 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2387 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2388 mUniformBlocks.push_back(newUniformBlock);
2389 }
2390 }
2391
2392 // Assign registers to the uniform blocks
2393 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2394 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2395 ASSERT(blockIndex != GL_INVALID_INDEX);
2396 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2397
2398 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2399 {
2400 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2401 ASSERT(uniformBlock->name == interfaceBlock.name);
2402
2403 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2404 {
2405 return false;
2406 }
2407 }
2408
2409 return true;
2410}
2411
2412bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2413{
2414 if (shader == GL_VERTEX_SHADER)
2415 {
2416 uniformBlock->vsRegisterIndex = registerIndex;
2417 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2418
2419 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2420 {
2421 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2422 return false;
2423 }
2424 }
2425 else if (shader == GL_FRAGMENT_SHADER)
2426 {
2427 uniformBlock->psRegisterIndex = registerIndex;
2428 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2429
2430 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2431 {
2432 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2433 return false;
2434 }
2435 }
2436 else UNREACHABLE();
2437
2438 return true;
2439}
2440
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002441std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2442{
2443 // for now we only handle point sprite emulation
2444 ASSERT(usesPointSpriteEmulation());
2445 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2446}
2447
2448std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2449{
2450 ASSERT(registers >= 0);
2451 ASSERT(vertexShader->mUsesPointSize);
2452 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2453
2454 std::string geomHLSL;
2455
2456 std::string varyingSemantic = "TEXCOORD";
2457
2458 std::string fragCoordSemantic;
2459 std::string pointCoordSemantic;
2460
2461 int reservedRegisterIndex = registers;
2462
2463 if (fragmentShader->mUsesFragCoord)
2464 {
2465 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2466 }
2467
2468 if (fragmentShader->mUsesPointCoord)
2469 {
2470 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2471 }
2472
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002473 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2474 "\n"
2475 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002476 "{\n";
2477
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002478 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002479
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002480 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002481
2482 if (fragmentShader->mUsesFragCoord)
2483 {
2484 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2485 }
2486
2487 geomHLSL += " float gl_PointSize : PSIZE;\n"
2488 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002489 "};\n"
2490 "\n"
2491 "struct GS_OUTPUT\n"
2492 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002493
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002494 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002495
2496 if (fragmentShader->mUsesFragCoord)
2497 {
2498 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2499 }
2500
2501 if (fragmentShader->mUsesPointCoord)
2502 {
2503 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2504 }
2505
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002506 geomHLSL += " float gl_PointSize : PSIZE;\n"
2507 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002508 "};\n"
2509 "\n"
2510 "static float2 pointSpriteCorners[] = \n"
2511 "{\n"
2512 " float2( 0.5f, -0.5f),\n"
2513 " float2( 0.5f, 0.5f),\n"
2514 " float2(-0.5f, -0.5f),\n"
2515 " float2(-0.5f, 0.5f)\n"
2516 "};\n"
2517 "\n"
2518 "static float2 pointSpriteTexcoords[] = \n"
2519 "{\n"
2520 " float2(1.0f, 1.0f),\n"
2521 " float2(1.0f, 0.0f),\n"
2522 " float2(0.0f, 1.0f),\n"
2523 " float2(0.0f, 0.0f)\n"
2524 "};\n"
2525 "\n"
2526 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2527 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2528 "\n"
2529 "[maxvertexcount(4)]\n"
2530 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2531 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002532 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2533 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002534
2535 for (int r = 0; r < registers; r++)
2536 {
2537 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2538 }
2539
2540 if (fragmentShader->mUsesFragCoord)
2541 {
2542 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2543 }
2544
2545 geomHLSL += " \n"
2546 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2547 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002548 " 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 +00002549
2550 for (int corner = 0; corner < 4; corner++)
2551 {
2552 geomHLSL += " \n"
2553 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2554
2555 if (fragmentShader->mUsesPointCoord)
2556 {
2557 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2558 }
2559
2560 geomHLSL += " outStream.Append(output);\n";
2561 }
2562
2563 geomHLSL += " \n"
2564 " outStream.RestartStrip();\n"
2565 "}\n";
2566
2567 return geomHLSL;
2568}
2569
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002570// This method needs to match OutputHLSL::decorate
2571std::string ProgramBinary::decorateAttribute(const std::string &name)
2572{
2573 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2574 {
2575 return "_" + name;
2576 }
2577
2578 return name;
2579}
2580
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002581bool ProgramBinary::isValidated() const
2582{
2583 return mValidated;
2584}
2585
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002586void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002587{
2588 // Skip over inactive attributes
2589 unsigned int activeAttribute = 0;
2590 unsigned int attribute;
2591 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2592 {
2593 if (mLinkedAttribute[attribute].name.empty())
2594 {
2595 continue;
2596 }
2597
2598 if (activeAttribute == index)
2599 {
2600 break;
2601 }
2602
2603 activeAttribute++;
2604 }
2605
2606 if (bufsize > 0)
2607 {
2608 const char *string = mLinkedAttribute[attribute].name.c_str();
2609
2610 strncpy(name, string, bufsize);
2611 name[bufsize - 1] = '\0';
2612
2613 if (length)
2614 {
2615 *length = strlen(name);
2616 }
2617 }
2618
2619 *size = 1; // Always a single 'type' instance
2620
2621 *type = mLinkedAttribute[attribute].type;
2622}
2623
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002624GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002625{
2626 int count = 0;
2627
2628 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2629 {
2630 if (!mLinkedAttribute[attributeIndex].name.empty())
2631 {
2632 count++;
2633 }
2634 }
2635
2636 return count;
2637}
2638
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002639GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002640{
2641 int maxLength = 0;
2642
2643 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2644 {
2645 if (!mLinkedAttribute[attributeIndex].name.empty())
2646 {
2647 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2648 }
2649 }
2650
2651 return maxLength;
2652}
2653
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002654void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002655{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002656 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002657
2658 if (bufsize > 0)
2659 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002660 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002661
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002662 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002663 {
2664 string += "[0]";
2665 }
2666
2667 strncpy(name, string.c_str(), bufsize);
2668 name[bufsize - 1] = '\0';
2669
2670 if (length)
2671 {
2672 *length = strlen(name);
2673 }
2674 }
2675
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002676 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002677
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002678 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002679}
2680
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002681GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002682{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002683 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002684}
2685
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002686GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002687{
2688 int maxLength = 0;
2689
2690 unsigned int numUniforms = mUniforms.size();
2691 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2692 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002693 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002694 {
2695 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2696 if (mUniforms[uniformIndex]->isArray())
2697 {
2698 length += 3; // Counting in "[0]".
2699 }
2700 maxLength = std::max(length, maxLength);
2701 }
2702 }
2703
2704 return maxLength;
2705}
2706
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002707GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2708{
2709 const gl::Uniform& uniform = *mUniforms[index];
2710
2711 switch (pname)
2712 {
2713 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2714 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
2715 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002716 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002717
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002718 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2719 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2720 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2721 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002722
2723 default:
2724 UNREACHABLE();
2725 break;
2726 }
2727 return 0;
2728}
2729
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002730void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2731{
2732 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2733
2734 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2735
2736 if (bufSize > 0)
2737 {
2738 std::string string = uniformBlock.name;
2739
2740 if (uniformBlock.isArrayElement())
2741 {
2742 string += "[" + str(uniformBlock.elementIndex) + "]";
2743 }
2744
2745 strncpy(uniformBlockName, string.c_str(), bufSize);
2746 uniformBlockName[bufSize - 1] = '\0';
2747
2748 if (length)
2749 {
2750 *length = strlen(uniformBlockName);
2751 }
2752 }
2753}
2754
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002755void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2756{
2757 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2758
2759 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2760
2761 switch (pname)
2762 {
2763 case GL_UNIFORM_BLOCK_DATA_SIZE:
2764 *params = static_cast<GLint>(uniformBlock.dataSize);
2765 break;
2766 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2767 *params = static_cast<GLint>(uniformBlock.name.size() + 1);
2768 break;
2769 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2770 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2771 break;
2772 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2773 {
2774 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2775 {
2776 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2777 }
2778 }
2779 break;
2780 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2781 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2782 break;
2783 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2784 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2785 break;
2786 default: UNREACHABLE();
2787 }
2788}
2789
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002790GLuint ProgramBinary::getActiveUniformBlockCount() const
2791{
2792 return mUniformBlocks.size();
2793}
2794
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002795GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2796{
2797 unsigned int maxLength = 0;
2798
2799 unsigned int numUniformBlocks = mUniformBlocks.size();
2800 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2801 {
2802 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2803 if (!uniformBlock.name.empty())
2804 {
2805 const unsigned int length = uniformBlock.name.length() + 1;
2806
2807 // Counting in "[0]".
2808 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2809
2810 maxLength = std::max(length + arrayLength, maxLength);
2811 }
2812 }
2813
2814 return maxLength;
2815}
2816
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002817void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002818{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002819 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002820 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002821 {
2822 mValidated = false;
2823 }
2824 else
2825 {
2826 mValidated = true;
2827 }
2828}
2829
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002830bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002831{
2832 // if any two active samplers in a program are of different types, but refer to the same
2833 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2834 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2835
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002836 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002837 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002838
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002839 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002840 {
2841 textureUnitType[i] = TEXTURE_UNKNOWN;
2842 }
2843
2844 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2845 {
2846 if (mSamplersPS[i].active)
2847 {
2848 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2849
2850 if (unit >= maxCombinedTextureImageUnits)
2851 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002852 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002853 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002854 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002855 }
2856
2857 return false;
2858 }
2859
2860 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2861 {
2862 if (mSamplersPS[i].textureType != textureUnitType[unit])
2863 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002864 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002865 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002866 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002867 }
2868
2869 return false;
2870 }
2871 }
2872 else
2873 {
2874 textureUnitType[unit] = mSamplersPS[i].textureType;
2875 }
2876 }
2877 }
2878
2879 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2880 {
2881 if (mSamplersVS[i].active)
2882 {
2883 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2884
2885 if (unit >= maxCombinedTextureImageUnits)
2886 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002887 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002888 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002889 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002890 }
2891
2892 return false;
2893 }
2894
2895 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2896 {
2897 if (mSamplersVS[i].textureType != textureUnitType[unit])
2898 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002899 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002900 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002901 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002902 }
2903
2904 return false;
2905 }
2906 }
2907 else
2908 {
2909 textureUnitType[unit] = mSamplersVS[i].textureType;
2910 }
2911 }
2912 }
2913
2914 return true;
2915}
2916
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002917ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2918{
2919}
2920
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002921struct AttributeSorter
2922{
2923 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2924 : originalIndices(semanticIndices)
2925 {
2926 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2927 {
2928 indices[i] = i;
2929 }
2930
2931 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2932 }
2933
2934 bool operator()(int a, int b)
2935 {
2936 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2937 }
2938
2939 int indices[MAX_VERTEX_ATTRIBS];
2940 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2941};
2942
2943void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2944{
2945 AttributeSorter sorter(mSemanticIndex);
2946
2947 int oldIndices[MAX_VERTEX_ATTRIBS];
2948 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2949
2950 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2951 {
2952 oldIndices[i] = mSemanticIndex[i];
2953 oldTranslatedAttributes[i] = attributes[i];
2954 }
2955
2956 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2957 {
2958 int oldIndex = sorter.indices[i];
2959 sortedSemanticIndices[i] = oldIndices[oldIndex];
2960 attributes[i] = oldTranslatedAttributes[oldIndex];
2961 }
2962}
2963
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002964}