blob: 36a8f1e3d9d00b9df0b9b84de09e266af9e98747 [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;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +000093 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000094}
95
96ProgramBinary::~ProgramBinary()
97{
daniel@transgaming.com95892412012-11-28 20:59:09 +000098 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +000099 mPixelExecutable = NULL;
100
daniel@transgaming.com95892412012-11-28 20:59:09 +0000101 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000102 mVertexExecutable = NULL;
103
104 delete mGeometryExecutable;
105 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000106
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000107 while (!mUniforms.empty())
108 {
109 delete mUniforms.back();
110 mUniforms.pop_back();
111 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000112
113 while (!mUniformBlocks.empty())
114 {
115 delete mUniformBlocks.back();
116 mUniformBlocks.pop_back();
117 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000118}
119
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000120unsigned int ProgramBinary::getSerial() const
121{
122 return mSerial;
123}
124
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000125int ProgramBinary::getShaderVersion() const
126{
127 return mShaderVersion;
128}
129
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000130unsigned int ProgramBinary::issueSerial()
131{
132 return mCurrentSerial++;
133}
134
daniel@transgaming.com95892412012-11-28 20:59:09 +0000135rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000136{
137 return mPixelExecutable;
138}
139
daniel@transgaming.com95892412012-11-28 20:59:09 +0000140rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000141{
142 return mVertexExecutable;
143}
144
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000145rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
146{
147 return mGeometryExecutable;
148}
149
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000150GLuint ProgramBinary::getAttributeLocation(const char *name)
151{
152 if (name)
153 {
154 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
155 {
156 if (mLinkedAttribute[index].name == std::string(name))
157 {
158 return index;
159 }
160 }
161 }
162
163 return -1;
164}
165
166int ProgramBinary::getSemanticIndex(int attributeIndex)
167{
168 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
169
170 return mSemanticIndex[attributeIndex];
171}
172
173// Returns one more than the highest sampler index used.
174GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
175{
176 switch (type)
177 {
178 case SAMPLER_PIXEL:
179 return mUsedPixelSamplerRange;
180 case SAMPLER_VERTEX:
181 return mUsedVertexSamplerRange;
182 default:
183 UNREACHABLE();
184 return 0;
185 }
186}
187
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000188bool ProgramBinary::usesPointSize() const
189{
190 return mUsesPointSize;
191}
192
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000193bool ProgramBinary::usesPointSpriteEmulation() const
194{
195 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
196}
197
198bool ProgramBinary::usesGeometryShader() const
199{
200 return usesPointSpriteEmulation();
201}
202
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000203// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
204// index (0-15 for the pixel shader and 0-3 for the vertex shader).
205GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
206{
207 GLint logicalTextureUnit = -1;
208
209 switch (type)
210 {
211 case SAMPLER_PIXEL:
212 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
213
214 if (mSamplersPS[samplerIndex].active)
215 {
216 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
217 }
218 break;
219 case SAMPLER_VERTEX:
220 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
221
222 if (mSamplersVS[samplerIndex].active)
223 {
224 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
225 }
226 break;
227 default: UNREACHABLE();
228 }
229
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000230 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000231 {
232 return logicalTextureUnit;
233 }
234
235 return -1;
236}
237
238// Returns the texture type for a given Direct3D 9 sampler type and
239// index (0-15 for the pixel shader and 0-3 for the vertex shader).
240TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
241{
242 switch (type)
243 {
244 case SAMPLER_PIXEL:
245 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
246 ASSERT(mSamplersPS[samplerIndex].active);
247 return mSamplersPS[samplerIndex].textureType;
248 case SAMPLER_VERTEX:
249 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
250 ASSERT(mSamplersVS[samplerIndex].active);
251 return mSamplersVS[samplerIndex].textureType;
252 default: UNREACHABLE();
253 }
254
255 return TEXTURE_2D;
256}
257
258GLint ProgramBinary::getUniformLocation(std::string name)
259{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000260 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000261
262 unsigned int numUniforms = mUniformIndex.size();
263 for (unsigned int location = 0; location < numUniforms; location++)
264 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000265 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000266 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000267 const int index = mUniformIndex[location].index;
268 const bool isArray = mUniforms[index]->isArray();
269
270 if ((isArray && mUniformIndex[location].element == subscript) ||
271 (subscript == GL_INVALID_INDEX))
272 {
273 return location;
274 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000275 }
276 }
277
278 return -1;
279}
280
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000281GLuint ProgramBinary::getUniformIndex(std::string name)
282{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000283 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000284
285 // The app is not allowed to specify array indices other than 0 for arrays of basic types
286 if (subscript != 0 && subscript != GL_INVALID_INDEX)
287 {
288 return GL_INVALID_INDEX;
289 }
290
291 unsigned int numUniforms = mUniforms.size();
292 for (unsigned int index = 0; index < numUniforms; index++)
293 {
294 if (mUniforms[index]->name == name)
295 {
296 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
297 {
298 return index;
299 }
300 }
301 }
302
303 return GL_INVALID_INDEX;
304}
305
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000306GLuint ProgramBinary::getUniformBlockIndex(std::string name)
307{
308 unsigned int subscript = parseAndStripArrayIndex(&name);
309
310 unsigned int numUniformBlocks = mUniformBlocks.size();
311 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
312 {
313 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
314 if (uniformBlock.name == name)
315 {
316 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
317 if (subscript == uniformBlock.elementIndex || arrayElementZero)
318 {
319 return blockIndex;
320 }
321 }
322 }
323
324 return GL_INVALID_INDEX;
325}
326
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000327UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
328{
329 ASSERT(blockIndex < mUniformBlocks.size());
330 return mUniformBlocks[blockIndex];
331}
332
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000333template <typename T>
334bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000335{
336 if (location < 0 || location >= (int)mUniformIndex.size())
337 {
338 return false;
339 }
340
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000341 const int components = UniformComponentCount(targetUniformType);
342 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
343
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000344 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
345 targetUniform->dirty = true;
346
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000347 int elementCount = targetUniform->elementCount();
348
349 if (elementCount == 1 && count > 1)
350 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
351
352 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
353
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000354 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000355 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000356 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000357
358 for (int i = 0; i < count; i++)
359 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000360 for (int c = 0; c < components; c++)
361 {
362 target[c] = v[c];
363 }
364 for (int c = components; c < 4; c++)
365 {
366 target[c] = 0;
367 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000368 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000369 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000370 }
371 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000372 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000373 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000374 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000375
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000376 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000377 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000378 for (int c = 0; c < components; c++)
379 {
380 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
381 }
382 for (int c = components; c < 4; c++)
383 {
384 boolParams[c] = GL_FALSE;
385 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000386 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000387 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000388 }
389 }
390 else
391 {
392 return false;
393 }
394
395 return true;
396}
397
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000398bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
399{
400 return setUniform(location, count, v, GL_FLOAT);
401}
402
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000403bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
404{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000405 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000406}
407
408bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
409{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000410 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000411}
412
413bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
414{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000415 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000416}
417
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000418template<typename T>
419void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000420{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000421 int copyWidth = std::min(targetHeight, srcWidth);
422 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000423
424 for (int x = 0; x < copyWidth; x++)
425 {
426 for (int y = 0; y < copyHeight; y++)
427 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000428 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000429 }
430 }
431 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000432 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000433 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000434 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000435 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000436 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000437 }
438 }
439 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000440 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000441 {
442 for (int x = 0; x < targetWidth; x++)
443 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000444 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000445 }
446 }
447}
448
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000449template<typename T>
450void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
451{
452 int copyWidth = std::min(targetWidth, srcWidth);
453 int copyHeight = std::min(targetHeight, srcHeight);
454
455 for (int y = 0; y < copyHeight; y++)
456 {
457 for (int x = 0; x < copyWidth; x++)
458 {
459 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
460 }
461 }
462 // clear unfilled right side
463 for (int y = 0; y < copyHeight; y++)
464 {
465 for (int x = copyWidth; x < targetWidth; x++)
466 {
467 target[y * targetWidth + x] = static_cast<T>(0);
468 }
469 }
470 // clear unfilled bottom.
471 for (int y = copyHeight; y < targetHeight; y++)
472 {
473 for (int x = 0; x < targetWidth; x++)
474 {
475 target[y * targetWidth + x] = static_cast<T>(0);
476 }
477 }
478}
479
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000480template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000481bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000482{
483 if (location < 0 || location >= (int)mUniformIndex.size())
484 {
485 return false;
486 }
487
488 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
489 targetUniform->dirty = true;
490
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000491 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000492 {
493 return false;
494 }
495
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000496 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000497
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000498 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000499 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
500
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000501 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000502 const unsigned int targetMatrixStride = (4 * rows);
503 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000504
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000505 for (int i = 0; i < count; i++)
506 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000507 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
508 if (transpose == GL_FALSE)
509 {
510 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
511 }
512 else
513 {
514 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
515 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000516 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000517 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000518 }
519
520 return true;
521}
522
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000523bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000524{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000525 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000526}
527
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000528bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000529{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000530 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000531}
532
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000533bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000534{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000535 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000536}
537
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000538bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000539{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000540 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000541}
542
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000543bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000544{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000545 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000546}
547
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000548bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000549{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000550 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000551}
552
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000553bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000554{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000555 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000556}
557
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000558bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000559{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000560 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000561}
562
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000563bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000564{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000565 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000566}
567
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000568bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
569{
570 if (location < 0 || location >= (int)mUniformIndex.size())
571 {
572 return false;
573 }
574
575 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
576 targetUniform->dirty = true;
577
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000578 int elementCount = targetUniform->elementCount();
579
580 if (elementCount == 1 && count > 1)
581 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
582
583 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
584
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000585 if (targetUniform->type == GL_INT ||
586 targetUniform->type == GL_SAMPLER_2D ||
587 targetUniform->type == GL_SAMPLER_CUBE)
588 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000589 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000590
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000591 for (int i = 0; i < count; i++)
592 {
593 target[0] = v[0];
594 target[1] = 0;
595 target[2] = 0;
596 target[3] = 0;
597 target += 4;
598 v += 1;
599 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000600 }
601 else if (targetUniform->type == GL_BOOL)
602 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000603 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000604
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000605 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000606 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000607 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
608 boolParams[1] = GL_FALSE;
609 boolParams[2] = GL_FALSE;
610 boolParams[3] = GL_FALSE;
611 boolParams += 4;
612 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000613 }
614 }
615 else
616 {
617 return false;
618 }
619
620 return true;
621}
622
623bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
624{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000625 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000626}
627
628bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
629{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000630 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000631}
632
633bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
634{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000635 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000636}
637
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000638bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
639{
640 return setUniform(location, count, v, GL_UNSIGNED_INT);
641}
642
643bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
644{
645 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
646}
647
648bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
649{
650 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
651}
652
653bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
654{
655 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
656}
657
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000658template <typename T>
659bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000660{
661 if (location < 0 || location >= (int)mUniformIndex.size())
662 {
663 return false;
664 }
665
666 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
667
668 // sized queries -- ensure the provided buffer is large enough
669 if (bufSize)
670 {
671 int requiredBytes = UniformExternalSize(targetUniform->type);
672 if (*bufSize < requiredBytes)
673 {
674 return false;
675 }
676 }
677
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000678 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000679 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000680 const int rows = VariableRowCount(targetUniform->type);
681 const int cols = VariableColumnCount(targetUniform->type);
682 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
683 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000684 else if (uniformType == UniformComponentType(targetUniform->type))
685 {
686 unsigned int size = UniformComponentCount(targetUniform->type);
687 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
688 size * sizeof(T));
689 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000690 else
691 {
692 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000693 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000694 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000695 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000696 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000697 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000698
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000699 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000700 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000701 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000702 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000703 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000704 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000705
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000706 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000707 {
708 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
709
710 for (unsigned int i = 0; i < size; i++)
711 {
712 params[i] = static_cast<T>(floatParams[i]);
713 }
714 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000715 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000716
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000717 case GL_INT:
718 {
719 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
720
721 for (unsigned int i = 0; i < size; i++)
722 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000723 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000724 }
725 }
726 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000727
728 case GL_UNSIGNED_INT:
729 {
730 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000731
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000732 for (unsigned int i = 0; i < size; i++)
733 {
734 params[i] = static_cast<T>(uintParams[i]);
735 }
736 }
737 break;
738
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000739 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000740 }
741 }
742
743 return true;
744}
745
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000746bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
747{
748 return getUniformv(location, bufSize, params, GL_FLOAT);
749}
750
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000751bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
752{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000753 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000754}
755
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000756bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
757{
758 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
759}
760
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000761void ProgramBinary::dirtyAllUniforms()
762{
763 unsigned int numUniforms = mUniforms.size();
764 for (unsigned int index = 0; index < numUniforms; index++)
765 {
766 mUniforms[index]->dirty = true;
767 }
768}
769
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000770// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000771void ProgramBinary::applyUniforms()
772{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000773 // Retrieve sampler uniform values
774 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
775 {
776 Uniform *targetUniform = *ub;
777
778 if (targetUniform->dirty)
779 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000780 if (targetUniform->type == GL_SAMPLER_2D ||
781 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000782 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000783 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000784 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000785
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000786 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000787 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000788 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000789
790 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000791 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000792 unsigned int samplerIndex = firstIndex + i;
793
794 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000795 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000796 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000797 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000798 }
799 }
800 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000801
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000802 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000803 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000804 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000805
806 for (int i = 0; i < count; i++)
807 {
808 unsigned int samplerIndex = firstIndex + i;
809
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000810 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000811 {
812 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000813 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000814 }
815 }
816 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000817 }
818 }
819 }
820
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000821 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000822}
823
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000824bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
825{
826 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
827 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
828
829 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
830 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
831
832 ASSERT(boundBuffers.size() == mUniformBlocks.size());
833
834 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
835 {
836 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
837 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
838
839 ASSERT(uniformBlock && uniformBuffer);
840
841 if (uniformBuffer->size() < uniformBlock->dataSize)
842 {
843 // undefined behaviour
844 return false;
845 }
846
847 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
848
849 if (uniformBlock->isReferencedByVertexShader())
850 {
851 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
852 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
853 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
854 vertexUniformBuffers[registerIndex] = uniformBuffer;
855 }
856
857 if (uniformBlock->isReferencedByFragmentShader())
858 {
859 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
860 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
861 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
862 fragmentUniformBuffers[registerIndex] = uniformBuffer;
863 }
864 }
865
866 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
867}
868
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000869// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
870// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000871int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000872{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000873 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000874
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000875 fragmentShader->resetVaryingsRegisterAssignment();
876
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000877 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
878 {
879 int n = VariableRowCount(varying->type) * varying->size;
880 int m = VariableColumnCount(varying->type);
881 bool success = false;
882
883 if (m == 2 || m == 3 || m == 4)
884 {
885 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
886 {
887 bool available = true;
888
889 for (int y = 0; y < n && available; y++)
890 {
891 for (int x = 0; x < m && available; x++)
892 {
893 if (packing[r + y][x])
894 {
895 available = false;
896 }
897 }
898 }
899
900 if (available)
901 {
902 varying->reg = r;
903 varying->col = 0;
904
905 for (int y = 0; y < n; y++)
906 {
907 for (int x = 0; x < m; x++)
908 {
909 packing[r + y][x] = &*varying;
910 }
911 }
912
913 success = true;
914 }
915 }
916
917 if (!success && m == 2)
918 {
919 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
920 {
921 bool available = true;
922
923 for (int y = 0; y < n && available; y++)
924 {
925 for (int x = 2; x < 4 && available; x++)
926 {
927 if (packing[r + y][x])
928 {
929 available = false;
930 }
931 }
932 }
933
934 if (available)
935 {
936 varying->reg = r;
937 varying->col = 2;
938
939 for (int y = 0; y < n; y++)
940 {
941 for (int x = 2; x < 4; x++)
942 {
943 packing[r + y][x] = &*varying;
944 }
945 }
946
947 success = true;
948 }
949 }
950 }
951 }
952 else if (m == 1)
953 {
954 int space[4] = {0};
955
956 for (int y = 0; y < maxVaryingVectors; y++)
957 {
958 for (int x = 0; x < 4; x++)
959 {
960 space[x] += packing[y][x] ? 0 : 1;
961 }
962 }
963
964 int column = 0;
965
966 for (int x = 0; x < 4; x++)
967 {
968 if (space[x] >= n && space[x] < space[column])
969 {
970 column = x;
971 }
972 }
973
974 if (space[column] >= n)
975 {
976 for (int r = 0; r < maxVaryingVectors; r++)
977 {
978 if (!packing[r][column])
979 {
980 varying->reg = r;
981
982 for (int y = r; y < r + n; y++)
983 {
984 packing[y][column] = &*varying;
985 }
986
987 break;
988 }
989 }
990
991 varying->col = column;
992
993 success = true;
994 }
995 }
996 else UNREACHABLE();
997
998 if (!success)
999 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001000 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001001
1002 return -1;
1003 }
1004 }
1005
1006 // Return the number of used registers
1007 int registers = 0;
1008
1009 for (int r = 0; r < maxVaryingVectors; r++)
1010 {
1011 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1012 {
1013 registers++;
1014 }
1015 }
1016
1017 return registers;
1018}
1019
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001020bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1021 std::string& pixelHLSL, std::string& vertexHLSL,
1022 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001023{
1024 if (pixelHLSL.empty() || vertexHLSL.empty())
1025 {
1026 return false;
1027 }
1028
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001029 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1030 bool usesFragColor = fragmentShader->mUsesFragColor;
1031 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001032 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001033 {
1034 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1035 return false;
1036 }
1037
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001038 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001039 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001040 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001041
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001042 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1043
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001044 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1045 // - with a 3.0 context, the output color is copied to channel 0
1046 // - with a 2.0 context, the output color is broadcast to all channels
1047 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1048 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1049
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001050 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001051 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001052 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001053
1054 return false;
1055 }
1056
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001057 vertexShader->resetVaryingsRegisterAssignment();
1058
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001059 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1060 {
1061 bool matched = false;
1062
1063 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1064 {
1065 if (output->name == input->name)
1066 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001067 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001068 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001069 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 +00001070
1071 return false;
1072 }
1073
1074 output->reg = input->reg;
1075 output->col = input->col;
1076
1077 matched = true;
1078 break;
1079 }
1080 }
1081
1082 if (!matched)
1083 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001084 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001085
1086 return false;
1087 }
1088 }
1089
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001090 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001091 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001092 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001093 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1094
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001095 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1096
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001097 // special varyings that use reserved registers
1098 int reservedRegisterIndex = registers;
1099 std::string fragCoordSemantic;
1100 std::string pointCoordSemantic;
1101
1102 if (fragmentShader->mUsesFragCoord)
1103 {
1104 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1105 }
1106
1107 if (fragmentShader->mUsesPointCoord)
1108 {
1109 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1110 // In DX11 we compute this in the GS.
1111 if (shaderModel == 3)
1112 {
1113 pointCoordSemantic = "TEXCOORD0";
1114 }
1115 else if (shaderModel >= 4)
1116 {
1117 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1118 }
1119 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001120
1121 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001122 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001123
1124 int semanticIndex = 0;
1125 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1126 {
1127 switch (attribute->type)
1128 {
1129 case GL_FLOAT: vertexHLSL += " float "; break;
1130 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1131 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1132 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1133 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1134 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1135 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
1136 default: UNREACHABLE();
1137 }
1138
1139 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1140
1141 semanticIndex += VariableRowCount(attribute->type);
1142 }
1143
1144 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001145 "\n"
1146 "struct VS_OUTPUT\n"
1147 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001148
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001149 if (shaderModel < 4)
1150 {
1151 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1152 }
1153
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001154 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155
1156 if (fragmentShader->mUsesFragCoord)
1157 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001158 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001159 }
1160
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001161 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001162 {
1163 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1164 }
1165
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001166 if (shaderModel >= 4)
1167 {
1168 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1169 }
1170
1171 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001172 "\n"
1173 "VS_OUTPUT main(VS_INPUT input)\n"
1174 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001175
1176 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1177 {
1178 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1179
1180 if (VariableRowCount(attribute->type) > 1) // Matrix
1181 {
1182 vertexHLSL += "transpose";
1183 }
1184
1185 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1186 }
1187
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001188 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1189 {
1190 vertexHLSL += "\n"
1191 " dx_initConstantBuffers();\n";
1192 }
1193
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001194 if (shaderModel >= 4)
1195 {
1196 vertexHLSL += "\n"
1197 " gl_main();\n"
1198 "\n"
1199 " VS_OUTPUT output;\n"
1200 " output.gl_Position.x = gl_Position.x;\n"
1201 " output.gl_Position.y = -gl_Position.y;\n"
1202 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1203 " output.gl_Position.w = gl_Position.w;\n";
1204 }
1205 else
1206 {
1207 vertexHLSL += "\n"
1208 " gl_main();\n"
1209 "\n"
1210 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001211 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1212 " 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 +00001213 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1214 " output.gl_Position.w = gl_Position.w;\n";
1215 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001216
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001217 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001218 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001219 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001220 }
1221
1222 if (fragmentShader->mUsesFragCoord)
1223 {
1224 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1225 }
1226
1227 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1228 {
1229 if (varying->reg >= 0)
1230 {
1231 for (int i = 0; i < varying->size; i++)
1232 {
1233 int rows = VariableRowCount(varying->type);
1234
1235 for (int j = 0; j < rows; j++)
1236 {
1237 int r = varying->reg + i * rows + j;
1238 vertexHLSL += " output.v" + str(r);
1239
1240 bool sharedRegister = false; // Register used by multiple varyings
1241
1242 for (int x = 0; x < 4; x++)
1243 {
1244 if (packing[r][x] && packing[r][x] != packing[r][0])
1245 {
1246 sharedRegister = true;
1247 break;
1248 }
1249 }
1250
1251 if(sharedRegister)
1252 {
1253 vertexHLSL += ".";
1254
1255 for (int x = 0; x < 4; x++)
1256 {
1257 if (packing[r][x] == &*varying)
1258 {
1259 switch(x)
1260 {
1261 case 0: vertexHLSL += "x"; break;
1262 case 1: vertexHLSL += "y"; break;
1263 case 2: vertexHLSL += "z"; break;
1264 case 3: vertexHLSL += "w"; break;
1265 }
1266 }
1267 }
1268 }
1269
1270 vertexHLSL += " = " + varying->name;
1271
1272 if (varying->array)
1273 {
1274 vertexHLSL += "[" + str(i) + "]";
1275 }
1276
1277 if (rows > 1)
1278 {
1279 vertexHLSL += "[" + str(j) + "]";
1280 }
1281
1282 vertexHLSL += ";\n";
1283 }
1284 }
1285 }
1286 }
1287
1288 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001289 " return output;\n"
1290 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001291
1292 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001293 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001294
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001295 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001296
1297 if (fragmentShader->mUsesFragCoord)
1298 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001299 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001300 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001301
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001302 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1303 {
1304 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1305 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001306
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001307 // Must consume the PSIZE element if the geometry shader is not active
1308 // We won't know if we use a GS until we draw
1309 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1310 {
1311 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1312 }
1313
1314 if (fragmentShader->mUsesFragCoord)
1315 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001316 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001317 {
1318 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1319 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001320 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001321 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001322 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1323 }
1324 }
1325
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001326 pixelHLSL += "};\n"
1327 "\n"
1328 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001329 "{\n";
1330
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001331 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001332 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001333 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001334 }
1335
1336 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001337 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001338
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001339 if (fragmentShader->mUsesFrontFacing)
1340 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001341 if (shaderModel >= 4)
1342 {
1343 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1344 "{\n";
1345 }
1346 else
1347 {
1348 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1349 "{\n";
1350 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001351 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001352 else
1353 {
1354 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1355 "{\n";
1356 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001357
1358 if (fragmentShader->mUsesFragCoord)
1359 {
1360 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1361
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001362 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001363 {
1364 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1365 " gl_FragCoord.y = input.dx_VPos.y;\n";
1366 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001367 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001368 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001369 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001370 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001371 }
1372 else
1373 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001374 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1375 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1376 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001377 }
1378
daniel@transgaming.com12985182012-12-20 20:56:31 +00001379 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001380 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001381 }
1382
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001383 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001384 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001385 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1386 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001387 }
1388
1389 if (fragmentShader->mUsesFrontFacing)
1390 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001391 if (shaderModel <= 3)
1392 {
1393 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1394 }
1395 else
1396 {
1397 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1398 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001399 }
1400
1401 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1402 {
1403 if (varying->reg >= 0)
1404 {
1405 for (int i = 0; i < varying->size; i++)
1406 {
1407 int rows = VariableRowCount(varying->type);
1408 for (int j = 0; j < rows; j++)
1409 {
1410 std::string n = str(varying->reg + i * rows + j);
1411 pixelHLSL += " " + varying->name;
1412
1413 if (varying->array)
1414 {
1415 pixelHLSL += "[" + str(i) + "]";
1416 }
1417
1418 if (rows > 1)
1419 {
1420 pixelHLSL += "[" + str(j) + "]";
1421 }
1422
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001423 switch (VariableColumnCount(varying->type))
1424 {
1425 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1426 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1427 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1428 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1429 default: UNREACHABLE();
1430 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001431 }
1432 }
1433 }
1434 else UNREACHABLE();
1435 }
1436
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001437 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1438 {
1439 pixelHLSL += "\n"
1440 " dx_initConstantBuffers();\n";
1441 }
1442
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001443 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001444 " gl_main();\n"
1445 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001446 " PS_OUTPUT output;\n";
1447
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001448 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001449 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001450 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001451
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001452 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001453 }
1454
1455 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001456 " return output;\n"
1457 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001458
1459 return true;
1460}
1461
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001462std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1463{
1464 std::string varyingHLSL;
1465
1466 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1467 {
1468 if (varying->reg >= 0)
1469 {
1470 for (int i = 0; i < varying->size; i++)
1471 {
1472 int rows = VariableRowCount(varying->type);
1473 for (int j = 0; j < rows; j++)
1474 {
1475 switch (varying->interpolation)
1476 {
1477 case Smooth: varyingHLSL += " "; break;
1478 case Flat: varyingHLSL += " nointerpolation "; break;
1479 case Centroid: varyingHLSL += " centroid "; break;
1480 default: UNREACHABLE();
1481 }
1482
1483 std::string n = str(varying->reg + i * rows + j);
1484 varyingHLSL += "float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
1485 }
1486 }
1487 }
1488 else UNREACHABLE();
1489 }
1490
1491 return varyingHLSL;
1492}
1493
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001494bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1495{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001496 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001497
1498 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001499 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001500 if (format != GL_PROGRAM_BINARY_ANGLE)
1501 {
1502 infoLog.append("Invalid program binary format.");
1503 return false;
1504 }
1505
1506 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001507 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001508 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001509 {
1510 infoLog.append("Invalid program binary version.");
1511 return false;
1512 }
1513
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001514 int compileFlags = 0;
1515 stream.read(&compileFlags);
1516 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1517 {
1518 infoLog.append("Mismatched compilation flags.");
1519 return false;
1520 }
1521
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001522 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1523 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001524 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001525 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001526 stream.read(&name);
1527 mLinkedAttribute[i].name = name;
1528 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001529 }
1530
1531 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1532 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001533 stream.read(&mSamplersPS[i].active);
1534 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001535
1536 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001537 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001538 mSamplersPS[i].textureType = (TextureType) textureType;
1539 }
1540
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001541 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001542 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001543 stream.read(&mSamplersVS[i].active);
1544 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001545
1546 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001547 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001548 mSamplersVS[i].textureType = (TextureType) textureType;
1549 }
1550
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001551 stream.read(&mUsedVertexSamplerRange);
1552 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001553 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001554 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001555
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001556 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001557 stream.read(&size);
1558 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001559 {
1560 infoLog.append("Invalid program binary.");
1561 return false;
1562 }
1563
1564 mUniforms.resize(size);
1565 for (unsigned int i = 0; i < size; ++i)
1566 {
1567 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001568 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001569 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001570 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001571 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001572
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001573 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001574 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001575 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001576 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001577 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001578
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001579 int offset;
1580 int arrayStride;
1581 int matrixStride;
1582 bool isRowMajorMatrix;
1583
1584 stream.read(&offset);
1585 stream.read(&arrayStride);
1586 stream.read(&matrixStride);
1587 stream.read(&isRowMajorMatrix);
1588
1589 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1590
1591 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001592
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001593 stream.read(&mUniforms[i]->psRegisterIndex);
1594 stream.read(&mUniforms[i]->vsRegisterIndex);
1595 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001596 }
1597
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001598 stream.read(&size);
1599 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001600 {
1601 infoLog.append("Invalid program binary.");
1602 return false;
1603 }
1604
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001605 mUniformBlocks.resize(size);
1606 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1607 {
1608 std::string name;
1609 unsigned int elementIndex;
1610 unsigned int dataSize;
1611
1612 stream.read(&name);
1613 stream.read(&elementIndex);
1614 stream.read(&dataSize);
1615
1616 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1617
1618 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1619 stream.read(&uniformBlock.psRegisterIndex);
1620 stream.read(&uniformBlock.vsRegisterIndex);
1621
1622 size_t numMembers;
1623 stream.read(&numMembers);
1624 uniformBlock.memberUniformIndexes.resize(numMembers);
1625 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1626 {
1627 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1628 }
1629 }
1630
1631 stream.read(&size);
1632 if (stream.error())
1633 {
1634 infoLog.append("Invalid program binary.");
1635 return false;
1636 }
1637
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 mUniformIndex.resize(size);
1639 for (unsigned int i = 0; i < size; ++i)
1640 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001641 stream.read(&mUniformIndex[i].name);
1642 stream.read(&mUniformIndex[i].element);
1643 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001644 }
1645
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001646 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001647 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001648
1649 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001650 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001652 unsigned int geometryShaderSize;
1653 stream.read(&geometryShaderSize);
1654
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001655 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001656
daniel@transgaming.com36038542012-11-28 20:59:26 +00001657 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001658 ptr += sizeof(GUID);
1659
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001660 GUID identifier = mRenderer->getAdapterIdentifier();
1661 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001662 {
1663 infoLog.append("Invalid program binary.");
1664 return false;
1665 }
1666
1667 const char *pixelShaderFunction = ptr;
1668 ptr += pixelShaderSize;
1669
1670 const char *vertexShaderFunction = ptr;
1671 ptr += vertexShaderSize;
1672
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001673 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1674 ptr += geometryShaderSize;
1675
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001676 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001677 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001678 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001679 {
1680 infoLog.append("Could not create pixel shader.");
1681 return false;
1682 }
1683
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001684 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001685 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001686 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001687 {
1688 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001689 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001690 mPixelExecutable = NULL;
1691 return false;
1692 }
1693
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001694 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1695 {
1696 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1697 geometryShaderSize, rx::SHADER_GEOMETRY);
1698 if (!mGeometryExecutable)
1699 {
1700 infoLog.append("Could not create geometry shader.");
1701 delete mPixelExecutable;
1702 mPixelExecutable = NULL;
1703 delete mVertexExecutable;
1704 mVertexExecutable = NULL;
1705 return false;
1706 }
1707 }
1708 else
1709 {
1710 mGeometryExecutable = NULL;
1711 }
1712
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001713 return true;
1714}
1715
1716bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1717{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001718 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001719
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001720 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001721 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001722 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001723
1724 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1725 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001726 stream.write(mLinkedAttribute[i].type);
1727 stream.write(mLinkedAttribute[i].name);
1728 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001729 }
1730
1731 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1732 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001733 stream.write(mSamplersPS[i].active);
1734 stream.write(mSamplersPS[i].logicalTextureUnit);
1735 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001736 }
1737
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001738 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001739 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001740 stream.write(mSamplersVS[i].active);
1741 stream.write(mSamplersVS[i].logicalTextureUnit);
1742 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001743 }
1744
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001745 stream.write(mUsedVertexSamplerRange);
1746 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001747 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001748 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001749
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001750 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001751 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001753 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001755 stream.write(uniform.type);
1756 stream.write(uniform.precision);
1757 stream.write(uniform.name);
1758 stream.write(uniform.arraySize);
1759 stream.write(uniform.blockIndex);
1760
1761 stream.write(uniform.blockInfo.offset);
1762 stream.write(uniform.blockInfo.arrayStride);
1763 stream.write(uniform.blockInfo.matrixStride);
1764 stream.write(uniform.blockInfo.isRowMajorMatrix);
1765
1766 stream.write(uniform.psRegisterIndex);
1767 stream.write(uniform.vsRegisterIndex);
1768 stream.write(uniform.registerCount);
1769 }
1770
1771 stream.write(mUniformBlocks.size());
1772 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1773 {
1774 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1775
1776 stream.write(uniformBlock.name);
1777 stream.write(uniformBlock.elementIndex);
1778 stream.write(uniformBlock.dataSize);
1779
1780 stream.write(uniformBlock.memberUniformIndexes.size());
1781 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1782 {
1783 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1784 }
1785
1786 stream.write(uniformBlock.psRegisterIndex);
1787 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001788 }
1789
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001790 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001791 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1792 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001793 stream.write(mUniformIndex[i].name);
1794 stream.write(mUniformIndex[i].element);
1795 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001796 }
1797
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001798 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001799 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001800
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001801 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001802 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001803
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001804 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1805 stream.write(geometryShaderSize);
1806
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001807 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001808
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001809 GLsizei streamLength = stream.length();
1810 const void *streamData = stream.data();
1811
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001812 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001813 if (totalLength > bufSize)
1814 {
1815 if (length)
1816 {
1817 *length = 0;
1818 }
1819
1820 return false;
1821 }
1822
1823 if (binary)
1824 {
1825 char *ptr = (char*) binary;
1826
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001827 memcpy(ptr, streamData, streamLength);
1828 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001830 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001831 ptr += sizeof(GUID);
1832
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001833 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001834 ptr += pixelShaderSize;
1835
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001836 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001837 ptr += vertexShaderSize;
1838
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001839 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1840 {
1841 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1842 ptr += geometryShaderSize;
1843 }
1844
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001845 ASSERT(ptr - totalLength == binary);
1846 }
1847
1848 if (length)
1849 {
1850 *length = totalLength;
1851 }
1852
1853 return true;
1854}
1855
1856GLint ProgramBinary::getLength()
1857{
1858 GLint length;
1859 if (save(NULL, INT_MAX, &length))
1860 {
1861 return length;
1862 }
1863 else
1864 {
1865 return 0;
1866 }
1867}
1868
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001869bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001870{
1871 if (!fragmentShader || !fragmentShader->isCompiled())
1872 {
1873 return false;
1874 }
1875
1876 if (!vertexShader || !vertexShader->isCompiled())
1877 {
1878 return false;
1879 }
1880
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001881 mShaderVersion = vertexShader->getShaderVersion();
1882
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001883 std::string pixelHLSL = fragmentShader->getHLSL();
1884 std::string vertexHLSL = vertexShader->getHLSL();
1885
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001886 // Map the varyings to the register file
1887 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1888 int registers = packVaryings(infoLog, packing, fragmentShader);
1889
1890 if (registers < 0)
1891 {
1892 return false;
1893 }
1894
1895 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001896 {
1897 return false;
1898 }
1899
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001900 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001901 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1902 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001903
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001904 if (usesGeometryShader())
1905 {
1906 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1907 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1908 }
1909
1910 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001911 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001912 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001913 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001914
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001915 delete mVertexExecutable;
1916 mVertexExecutable = NULL;
1917 delete mPixelExecutable;
1918 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001919 delete mGeometryExecutable;
1920 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001921 }
1922
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001923 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1924 {
1925 success = false;
1926 }
1927
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001928 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001929 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001930 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001931 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001932
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001933 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1934 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1935 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001936 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1937 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1938 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 +00001939 }
1940
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001941 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1942 {
1943 success = false;
1944 }
1945
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001946 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001947}
1948
1949// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001950bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001951{
1952 unsigned int usedLocations = 0;
1953
1954 // Link attributes that have a binding location
1955 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1956 {
1957 int location = attributeBindings.getAttributeBinding(attribute->name);
1958
1959 if (location != -1) // Set by glBindAttribLocation
1960 {
1961 if (!mLinkedAttribute[location].name.empty())
1962 {
1963 // Multiple active attributes bound to the same location; not an error
1964 }
1965
1966 mLinkedAttribute[location] = *attribute;
1967
1968 int rows = VariableRowCount(attribute->type);
1969
1970 if (rows + location > MAX_VERTEX_ATTRIBS)
1971 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001972 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 +00001973
1974 return false;
1975 }
1976
1977 for (int i = 0; i < rows; i++)
1978 {
1979 usedLocations |= 1 << (location + i);
1980 }
1981 }
1982 }
1983
1984 // Link attributes that don't have a binding location
1985 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1986 {
1987 int location = attributeBindings.getAttributeBinding(attribute->name);
1988
1989 if (location == -1) // Not set by glBindAttribLocation
1990 {
1991 int rows = VariableRowCount(attribute->type);
1992 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
1993
1994 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
1995 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001996 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001997
1998 return false; // Fail to link
1999 }
2000
2001 mLinkedAttribute[availableIndex] = *attribute;
2002 }
2003 }
2004
2005 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2006 {
2007 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
2008 int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
2009
2010 for (int r = 0; r < rows; r++)
2011 {
2012 mSemanticIndex[attributeIndex++] = index++;
2013 }
2014 }
2015
2016 return true;
2017}
2018
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002019bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2020{
2021 if (vertexUniform.type != fragmentUniform.type)
2022 {
2023 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2024 return false;
2025 }
2026 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2027 {
2028 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2029 return false;
2030 }
2031 else if (vertexUniform.precision != fragmentUniform.precision)
2032 {
2033 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2034 return false;
2035 }
2036 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2037 {
2038 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2039 }
2040
2041 const unsigned int numMembers = vertexUniform.fields.size();
2042 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2043 {
2044 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2045 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2046
2047 if (vertexMember.name != fragmentMember.name)
2048 {
2049 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2050 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2051 return false;
2052 }
2053
2054 const std::string memberName = uniformName + "." + vertexUniform.name;
2055 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2056 {
2057 return false;
2058 }
2059 }
2060
2061 return true;
2062}
2063
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002064bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002065{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002066 // Check that uniforms defined in the vertex and fragment shaders are identical
2067 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2068 UniformMap linkedUniforms;
2069
2070 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2071 {
2072 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2073 linkedUniforms[vertexUniform.name] = &vertexUniform;
2074 }
2075
2076 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2077 {
2078 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2079 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2080 if (entry != linkedUniforms.end())
2081 {
2082 const sh::Uniform &vertexUniform = *entry->second;
2083 const std::string &uniformName = "uniform " + vertexUniform.name;
2084 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2085 {
2086 return false;
2087 }
2088 }
2089 }
2090
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002091 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002092 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002093 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002094 {
2095 return false;
2096 }
2097 }
2098
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002099 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002100 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002101 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002102 {
2103 return false;
2104 }
2105 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002106
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002107 return true;
2108}
2109
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002110int totalRegisterCount(const sh::Uniform &uniform)
2111{
2112 int registerCount = 0;
2113
2114 if (!uniform.fields.empty())
2115 {
2116 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2117 {
2118 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2119 }
2120 }
2121 else
2122 {
2123 registerCount = 1;
2124 }
2125
2126 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2127}
2128
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002129bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002130{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002131 if (!constant.fields.empty())
2132 {
2133 if (constant.arraySize > 0)
2134 {
2135 unsigned int elementRegisterIndex = constant.registerIndex;
2136
2137 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2138 {
2139 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2140 {
2141 const sh::Uniform &field = constant.fields[fieldIndex];
2142 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2143 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2144 if (!defineUniform(shader, fieldUniform, infoLog))
2145 {
2146 return false;
2147 }
2148 elementRegisterIndex += totalRegisterCount(field);
2149 }
2150 }
2151 }
2152 else
2153 {
2154 unsigned int fieldRegisterIndex = constant.registerIndex;
2155
2156 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2157 {
2158 const sh::Uniform &field = constant.fields[fieldIndex];
2159 const std::string &uniformName = constant.name + "." + field.name;
2160
2161 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2162 fieldUniform.fields = field.fields;
2163
2164 if (!defineUniform(shader, fieldUniform, infoLog))
2165 {
2166 return false;
2167 }
2168 fieldRegisterIndex += totalRegisterCount(field);
2169 }
2170 }
2171
2172 return true;
2173 }
2174
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002175 if (constant.type == GL_SAMPLER_2D ||
2176 constant.type == GL_SAMPLER_CUBE)
2177 {
2178 unsigned int samplerIndex = constant.registerIndex;
2179
2180 do
2181 {
2182 if (shader == GL_VERTEX_SHADER)
2183 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002184 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002185 {
2186 mSamplersVS[samplerIndex].active = true;
2187 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2188 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2189 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2190 }
2191 else
2192 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002193 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002194 return false;
2195 }
2196 }
2197 else if (shader == GL_FRAGMENT_SHADER)
2198 {
2199 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2200 {
2201 mSamplersPS[samplerIndex].active = true;
2202 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2203 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2204 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2205 }
2206 else
2207 {
2208 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2209 return false;
2210 }
2211 }
2212 else UNREACHABLE();
2213
2214 samplerIndex++;
2215 }
2216 while (samplerIndex < constant.registerIndex + constant.arraySize);
2217 }
2218
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002219 Uniform *uniform = NULL;
2220 GLint location = getUniformLocation(constant.name);
2221
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002222 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002223 {
2224 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002225 }
2226 else
2227 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002228 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002229 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002230
2231 if (!uniform)
2232 {
2233 return false;
2234 }
2235
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002236 if (shader == GL_FRAGMENT_SHADER)
2237 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002238 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002239 }
2240 else if (shader == GL_VERTEX_SHADER)
2241 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002242 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002243 }
2244 else UNREACHABLE();
2245
2246 if (location >= 0)
2247 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002248 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002249 }
2250
2251 mUniforms.push_back(uniform);
2252 unsigned int uniformIndex = mUniforms.size() - 1;
2253
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002254 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002255 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002256 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002257 }
2258
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002259 if (shader == GL_VERTEX_SHADER)
2260 {
2261 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2262 {
2263 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2264 return false;
2265 }
2266 }
2267 else if (shader == GL_FRAGMENT_SHADER)
2268 {
2269 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2270 {
2271 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2272 return false;
2273 }
2274 }
2275 else UNREACHABLE();
2276
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002277 return true;
2278}
2279
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002280bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2281{
2282 const char* blockName = vertexInterfaceBlock.name.c_str();
2283
2284 // validate blocks for the same member types
2285 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2286 {
2287 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2288 return false;
2289 }
2290
2291 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2292 {
2293 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2294 return false;
2295 }
2296
2297 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2298 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2299 {
2300 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2301 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2302
2303 if (vertexMember.name != fragmentMember.name)
2304 {
2305 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2306 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2307 return false;
2308 }
2309
2310 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2311 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2312 {
2313 return false;
2314 }
2315 }
2316
2317 return true;
2318}
2319
2320bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2321{
2322 // Check that interface blocks defined in the vertex and fragment shaders are identical
2323 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2324 UniformBlockMap linkedUniformBlocks;
2325
2326 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2327 {
2328 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2329 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2330 }
2331
2332 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2333 {
2334 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2335 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2336 if (entry != linkedUniformBlocks.end())
2337 {
2338 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2339 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2340 {
2341 return false;
2342 }
2343 }
2344 }
2345
2346 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2347 {
2348 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2349 {
2350 return false;
2351 }
2352 }
2353
2354 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2355 {
2356 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2357 {
2358 return false;
2359 }
2360 }
2361
2362 return true;
2363}
2364
2365bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2366{
2367 // create uniform block entries if they do not exist
2368 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2369 {
2370 std::vector<unsigned int> blockUniformIndexes;
2371 const unsigned int blockIndex = mUniformBlocks.size();
2372
2373 // define member uniforms
2374 for (unsigned int activeUniformIndex = 0; activeUniformIndex < interfaceBlock.activeUniforms.size(); activeUniformIndex++)
2375 {
2376 const sh::Uniform &constant = interfaceBlock.activeUniforms[activeUniformIndex];
2377 Uniform *uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize,
2378 blockIndex, interfaceBlock.blockInfo[activeUniformIndex]);
2379
2380 // add to uniform list, but not index, since uniform block uniforms have no location
2381 blockUniformIndexes.push_back(mUniforms.size());
2382 mUniforms.push_back(uniform);
2383 }
2384
2385 // create all the uniform blocks
2386 if (interfaceBlock.arraySize > 0)
2387 {
2388 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2389 {
2390 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2391 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2392 mUniformBlocks.push_back(newUniformBlock);
2393 }
2394 }
2395 else
2396 {
2397 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2398 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2399 mUniformBlocks.push_back(newUniformBlock);
2400 }
2401 }
2402
2403 // Assign registers to the uniform blocks
2404 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2405 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2406 ASSERT(blockIndex != GL_INVALID_INDEX);
2407 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2408
2409 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2410 {
2411 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2412 ASSERT(uniformBlock->name == interfaceBlock.name);
2413
2414 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2415 {
2416 return false;
2417 }
2418 }
2419
2420 return true;
2421}
2422
2423bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2424{
2425 if (shader == GL_VERTEX_SHADER)
2426 {
2427 uniformBlock->vsRegisterIndex = registerIndex;
2428 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2429
2430 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= 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 if (shader == GL_FRAGMENT_SHADER)
2437 {
2438 uniformBlock->psRegisterIndex = registerIndex;
2439 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2440
2441 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2442 {
2443 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2444 return false;
2445 }
2446 }
2447 else UNREACHABLE();
2448
2449 return true;
2450}
2451
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002452std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2453{
2454 // for now we only handle point sprite emulation
2455 ASSERT(usesPointSpriteEmulation());
2456 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2457}
2458
2459std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2460{
2461 ASSERT(registers >= 0);
2462 ASSERT(vertexShader->mUsesPointSize);
2463 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2464
2465 std::string geomHLSL;
2466
2467 std::string varyingSemantic = "TEXCOORD";
2468
2469 std::string fragCoordSemantic;
2470 std::string pointCoordSemantic;
2471
2472 int reservedRegisterIndex = registers;
2473
2474 if (fragmentShader->mUsesFragCoord)
2475 {
2476 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2477 }
2478
2479 if (fragmentShader->mUsesPointCoord)
2480 {
2481 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2482 }
2483
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002484 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2485 "\n"
2486 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002487 "{\n";
2488
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002489 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002490
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002491 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002492
2493 if (fragmentShader->mUsesFragCoord)
2494 {
2495 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2496 }
2497
2498 geomHLSL += " float gl_PointSize : PSIZE;\n"
2499 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002500 "};\n"
2501 "\n"
2502 "struct GS_OUTPUT\n"
2503 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002504
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002505 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002506
2507 if (fragmentShader->mUsesFragCoord)
2508 {
2509 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2510 }
2511
2512 if (fragmentShader->mUsesPointCoord)
2513 {
2514 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2515 }
2516
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002517 geomHLSL += " float gl_PointSize : PSIZE;\n"
2518 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002519 "};\n"
2520 "\n"
2521 "static float2 pointSpriteCorners[] = \n"
2522 "{\n"
2523 " float2( 0.5f, -0.5f),\n"
2524 " float2( 0.5f, 0.5f),\n"
2525 " float2(-0.5f, -0.5f),\n"
2526 " float2(-0.5f, 0.5f)\n"
2527 "};\n"
2528 "\n"
2529 "static float2 pointSpriteTexcoords[] = \n"
2530 "{\n"
2531 " float2(1.0f, 1.0f),\n"
2532 " float2(1.0f, 0.0f),\n"
2533 " float2(0.0f, 1.0f),\n"
2534 " float2(0.0f, 0.0f)\n"
2535 "};\n"
2536 "\n"
2537 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2538 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2539 "\n"
2540 "[maxvertexcount(4)]\n"
2541 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2542 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002543 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2544 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002545
2546 for (int r = 0; r < registers; r++)
2547 {
2548 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2549 }
2550
2551 if (fragmentShader->mUsesFragCoord)
2552 {
2553 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2554 }
2555
2556 geomHLSL += " \n"
2557 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2558 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002559 " 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 +00002560
2561 for (int corner = 0; corner < 4; corner++)
2562 {
2563 geomHLSL += " \n"
2564 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2565
2566 if (fragmentShader->mUsesPointCoord)
2567 {
2568 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2569 }
2570
2571 geomHLSL += " outStream.Append(output);\n";
2572 }
2573
2574 geomHLSL += " \n"
2575 " outStream.RestartStrip();\n"
2576 "}\n";
2577
2578 return geomHLSL;
2579}
2580
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002581// This method needs to match OutputHLSL::decorate
2582std::string ProgramBinary::decorateAttribute(const std::string &name)
2583{
2584 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2585 {
2586 return "_" + name;
2587 }
2588
2589 return name;
2590}
2591
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002592bool ProgramBinary::isValidated() const
2593{
2594 return mValidated;
2595}
2596
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002597void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002598{
2599 // Skip over inactive attributes
2600 unsigned int activeAttribute = 0;
2601 unsigned int attribute;
2602 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2603 {
2604 if (mLinkedAttribute[attribute].name.empty())
2605 {
2606 continue;
2607 }
2608
2609 if (activeAttribute == index)
2610 {
2611 break;
2612 }
2613
2614 activeAttribute++;
2615 }
2616
2617 if (bufsize > 0)
2618 {
2619 const char *string = mLinkedAttribute[attribute].name.c_str();
2620
2621 strncpy(name, string, bufsize);
2622 name[bufsize - 1] = '\0';
2623
2624 if (length)
2625 {
2626 *length = strlen(name);
2627 }
2628 }
2629
2630 *size = 1; // Always a single 'type' instance
2631
2632 *type = mLinkedAttribute[attribute].type;
2633}
2634
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002635GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002636{
2637 int count = 0;
2638
2639 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2640 {
2641 if (!mLinkedAttribute[attributeIndex].name.empty())
2642 {
2643 count++;
2644 }
2645 }
2646
2647 return count;
2648}
2649
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002650GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002651{
2652 int maxLength = 0;
2653
2654 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2655 {
2656 if (!mLinkedAttribute[attributeIndex].name.empty())
2657 {
2658 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2659 }
2660 }
2661
2662 return maxLength;
2663}
2664
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002665void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002666{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002667 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002668
2669 if (bufsize > 0)
2670 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002671 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002672
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002673 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002674 {
2675 string += "[0]";
2676 }
2677
2678 strncpy(name, string.c_str(), bufsize);
2679 name[bufsize - 1] = '\0';
2680
2681 if (length)
2682 {
2683 *length = strlen(name);
2684 }
2685 }
2686
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002687 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002688
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002689 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002690}
2691
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002692GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002693{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002694 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002695}
2696
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002697GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002698{
2699 int maxLength = 0;
2700
2701 unsigned int numUniforms = mUniforms.size();
2702 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2703 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002704 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002705 {
2706 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2707 if (mUniforms[uniformIndex]->isArray())
2708 {
2709 length += 3; // Counting in "[0]".
2710 }
2711 maxLength = std::max(length, maxLength);
2712 }
2713 }
2714
2715 return maxLength;
2716}
2717
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002718GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2719{
2720 const gl::Uniform& uniform = *mUniforms[index];
2721
2722 switch (pname)
2723 {
2724 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2725 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
2726 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002727 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002728
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002729 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2730 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2731 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2732 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002733
2734 default:
2735 UNREACHABLE();
2736 break;
2737 }
2738 return 0;
2739}
2740
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002741void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2742{
2743 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2744
2745 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2746
2747 if (bufSize > 0)
2748 {
2749 std::string string = uniformBlock.name;
2750
2751 if (uniformBlock.isArrayElement())
2752 {
2753 string += "[" + str(uniformBlock.elementIndex) + "]";
2754 }
2755
2756 strncpy(uniformBlockName, string.c_str(), bufSize);
2757 uniformBlockName[bufSize - 1] = '\0';
2758
2759 if (length)
2760 {
2761 *length = strlen(uniformBlockName);
2762 }
2763 }
2764}
2765
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002766void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2767{
2768 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2769
2770 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2771
2772 switch (pname)
2773 {
2774 case GL_UNIFORM_BLOCK_DATA_SIZE:
2775 *params = static_cast<GLint>(uniformBlock.dataSize);
2776 break;
2777 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002778 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002779 break;
2780 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2781 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2782 break;
2783 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2784 {
2785 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2786 {
2787 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2788 }
2789 }
2790 break;
2791 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2792 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2793 break;
2794 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2795 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2796 break;
2797 default: UNREACHABLE();
2798 }
2799}
2800
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002801GLuint ProgramBinary::getActiveUniformBlockCount() const
2802{
2803 return mUniformBlocks.size();
2804}
2805
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002806GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2807{
2808 unsigned int maxLength = 0;
2809
2810 unsigned int numUniformBlocks = mUniformBlocks.size();
2811 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2812 {
2813 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2814 if (!uniformBlock.name.empty())
2815 {
2816 const unsigned int length = uniformBlock.name.length() + 1;
2817
2818 // Counting in "[0]".
2819 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2820
2821 maxLength = std::max(length + arrayLength, maxLength);
2822 }
2823 }
2824
2825 return maxLength;
2826}
2827
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002828void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002829{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002830 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002831 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002832 {
2833 mValidated = false;
2834 }
2835 else
2836 {
2837 mValidated = true;
2838 }
2839}
2840
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002841bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002842{
2843 // if any two active samplers in a program are of different types, but refer to the same
2844 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2845 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2846
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002847 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002848 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002849
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002850 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002851 {
2852 textureUnitType[i] = TEXTURE_UNKNOWN;
2853 }
2854
2855 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2856 {
2857 if (mSamplersPS[i].active)
2858 {
2859 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2860
2861 if (unit >= maxCombinedTextureImageUnits)
2862 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002863 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002864 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002865 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002866 }
2867
2868 return false;
2869 }
2870
2871 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2872 {
2873 if (mSamplersPS[i].textureType != textureUnitType[unit])
2874 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002875 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002876 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002877 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002878 }
2879
2880 return false;
2881 }
2882 }
2883 else
2884 {
2885 textureUnitType[unit] = mSamplersPS[i].textureType;
2886 }
2887 }
2888 }
2889
2890 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2891 {
2892 if (mSamplersVS[i].active)
2893 {
2894 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2895
2896 if (unit >= maxCombinedTextureImageUnits)
2897 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002898 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002899 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002900 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002901 }
2902
2903 return false;
2904 }
2905
2906 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2907 {
2908 if (mSamplersVS[i].textureType != textureUnitType[unit])
2909 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002910 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002911 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002912 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002913 }
2914
2915 return false;
2916 }
2917 }
2918 else
2919 {
2920 textureUnitType[unit] = mSamplersVS[i].textureType;
2921 }
2922 }
2923 }
2924
2925 return true;
2926}
2927
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002928ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2929{
2930}
2931
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002932struct AttributeSorter
2933{
2934 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2935 : originalIndices(semanticIndices)
2936 {
2937 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2938 {
2939 indices[i] = i;
2940 }
2941
2942 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2943 }
2944
2945 bool operator()(int a, int b)
2946 {
2947 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2948 }
2949
2950 int indices[MAX_VERTEX_ATTRIBS];
2951 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2952};
2953
2954void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2955{
2956 AttributeSorter sorter(mSemanticIndex);
2957
2958 int oldIndices[MAX_VERTEX_ATTRIBS];
2959 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2960
2961 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2962 {
2963 oldIndices[i] = mSemanticIndex[i];
2964 oldTranslatedAttributes[i] = attributes[i];
2965 }
2966
2967 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2968 {
2969 int oldIndex = sorter.indices[i];
2970 sortedSemanticIndices[i] = oldIndices[oldIndex];
2971 attributes[i] = oldTranslatedAttributes[oldIndex];
2972 }
2973}
2974
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002975}