blob: fb1b438b43a3805a74e077eca784cb11a13ac6d9 [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 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000879 GLenum transposedType = TransposeMatrixType(varying->type);
880 int n = VariableRowCount(transposedType) * varying->size;
881 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000882 bool success = false;
883
884 if (m == 2 || m == 3 || m == 4)
885 {
886 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
887 {
888 bool available = true;
889
890 for (int y = 0; y < n && available; y++)
891 {
892 for (int x = 0; x < m && available; x++)
893 {
894 if (packing[r + y][x])
895 {
896 available = false;
897 }
898 }
899 }
900
901 if (available)
902 {
903 varying->reg = r;
904 varying->col = 0;
905
906 for (int y = 0; y < n; y++)
907 {
908 for (int x = 0; x < m; x++)
909 {
910 packing[r + y][x] = &*varying;
911 }
912 }
913
914 success = true;
915 }
916 }
917
918 if (!success && m == 2)
919 {
920 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
921 {
922 bool available = true;
923
924 for (int y = 0; y < n && available; y++)
925 {
926 for (int x = 2; x < 4 && available; x++)
927 {
928 if (packing[r + y][x])
929 {
930 available = false;
931 }
932 }
933 }
934
935 if (available)
936 {
937 varying->reg = r;
938 varying->col = 2;
939
940 for (int y = 0; y < n; y++)
941 {
942 for (int x = 2; x < 4; x++)
943 {
944 packing[r + y][x] = &*varying;
945 }
946 }
947
948 success = true;
949 }
950 }
951 }
952 }
953 else if (m == 1)
954 {
955 int space[4] = {0};
956
957 for (int y = 0; y < maxVaryingVectors; y++)
958 {
959 for (int x = 0; x < 4; x++)
960 {
961 space[x] += packing[y][x] ? 0 : 1;
962 }
963 }
964
965 int column = 0;
966
967 for (int x = 0; x < 4; x++)
968 {
969 if (space[x] >= n && space[x] < space[column])
970 {
971 column = x;
972 }
973 }
974
975 if (space[column] >= n)
976 {
977 for (int r = 0; r < maxVaryingVectors; r++)
978 {
979 if (!packing[r][column])
980 {
981 varying->reg = r;
982
983 for (int y = r; y < r + n; y++)
984 {
985 packing[y][column] = &*varying;
986 }
987
988 break;
989 }
990 }
991
992 varying->col = column;
993
994 success = true;
995 }
996 }
997 else UNREACHABLE();
998
999 if (!success)
1000 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001001 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001002
1003 return -1;
1004 }
1005 }
1006
1007 // Return the number of used registers
1008 int registers = 0;
1009
1010 for (int r = 0; r < maxVaryingVectors; r++)
1011 {
1012 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1013 {
1014 registers++;
1015 }
1016 }
1017
1018 return registers;
1019}
1020
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001021bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1022 std::string& pixelHLSL, std::string& vertexHLSL,
1023 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001024{
1025 if (pixelHLSL.empty() || vertexHLSL.empty())
1026 {
1027 return false;
1028 }
1029
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001030 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1031 bool usesFragColor = fragmentShader->mUsesFragColor;
1032 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001033 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001034 {
1035 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1036 return false;
1037 }
1038
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001039 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001040 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001041 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001042
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001043 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1044
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001045 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1046 // - with a 3.0 context, the output color is copied to channel 0
1047 // - with a 2.0 context, the output color is broadcast to all channels
1048 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1049 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1050
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001051 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001052 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001053 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001054
1055 return false;
1056 }
1057
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001058 vertexShader->resetVaryingsRegisterAssignment();
1059
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001060 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1061 {
1062 bool matched = false;
1063
1064 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1065 {
1066 if (output->name == input->name)
1067 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001068 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001069 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001070 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 +00001071
1072 return false;
1073 }
1074
1075 output->reg = input->reg;
1076 output->col = input->col;
1077
1078 matched = true;
1079 break;
1080 }
1081 }
1082
1083 if (!matched)
1084 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001085 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001086
1087 return false;
1088 }
1089 }
1090
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001091 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001092 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001093 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001094 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
1095
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001096 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1097
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001098 // special varyings that use reserved registers
1099 int reservedRegisterIndex = registers;
1100 std::string fragCoordSemantic;
1101 std::string pointCoordSemantic;
1102
1103 if (fragmentShader->mUsesFragCoord)
1104 {
1105 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1106 }
1107
1108 if (fragmentShader->mUsesPointCoord)
1109 {
1110 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1111 // In DX11 we compute this in the GS.
1112 if (shaderModel == 3)
1113 {
1114 pointCoordSemantic = "TEXCOORD0";
1115 }
1116 else if (shaderModel >= 4)
1117 {
1118 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1119 }
1120 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001121
1122 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001123 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001124
1125 int semanticIndex = 0;
1126 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1127 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001128 switch (TransposeMatrixType(attribute->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001129 {
1130 case GL_FLOAT: vertexHLSL += " float "; break;
1131 case GL_FLOAT_VEC2: vertexHLSL += " float2 "; break;
1132 case GL_FLOAT_VEC3: vertexHLSL += " float3 "; break;
1133 case GL_FLOAT_VEC4: vertexHLSL += " float4 "; break;
1134 case GL_FLOAT_MAT2: vertexHLSL += " float2x2 "; break;
1135 case GL_FLOAT_MAT3: vertexHLSL += " float3x3 "; break;
1136 case GL_FLOAT_MAT4: vertexHLSL += " float4x4 "; break;
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001137 case GL_FLOAT_MAT2x3: vertexHLSL += " float2x3 "; break;
1138 case GL_FLOAT_MAT3x2: vertexHLSL += " float3x2 "; break;
1139 case GL_FLOAT_MAT2x4: vertexHLSL += " float2x4 "; break;
1140 case GL_FLOAT_MAT4x2: vertexHLSL += " float4x2 "; break;
1141 case GL_FLOAT_MAT3x4: vertexHLSL += " float3x4 "; break;
1142 case GL_FLOAT_MAT4x3: vertexHLSL += " float4x3 "; break;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001143 default: UNREACHABLE();
1144 }
1145
1146 vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
1147
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001148 semanticIndex += AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001149 }
1150
1151 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001152 "\n"
1153 "struct VS_OUTPUT\n"
1154 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001156 if (shaderModel < 4)
1157 {
1158 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1159 }
1160
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001161 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001162
1163 if (fragmentShader->mUsesFragCoord)
1164 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001165 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001166 }
1167
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001168 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001169 {
1170 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1171 }
1172
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001173 if (shaderModel >= 4)
1174 {
1175 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1176 }
1177
1178 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001179 "\n"
1180 "VS_OUTPUT main(VS_INPUT input)\n"
1181 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001182
1183 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1184 {
1185 vertexHLSL += " " + decorateAttribute(attribute->name) + " = ";
1186
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001187 if (IsMatrixType(attribute->type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001188 {
1189 vertexHLSL += "transpose";
1190 }
1191
1192 vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
1193 }
1194
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001195 if (vertexHLSL.find("dx_initConstantBuffers") != std::string::npos)
1196 {
1197 vertexHLSL += "\n"
1198 " dx_initConstantBuffers();\n";
1199 }
1200
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001201 if (shaderModel >= 4)
1202 {
1203 vertexHLSL += "\n"
1204 " gl_main();\n"
1205 "\n"
1206 " VS_OUTPUT output;\n"
1207 " output.gl_Position.x = gl_Position.x;\n"
1208 " output.gl_Position.y = -gl_Position.y;\n"
1209 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1210 " output.gl_Position.w = gl_Position.w;\n";
1211 }
1212 else
1213 {
1214 vertexHLSL += "\n"
1215 " gl_main();\n"
1216 "\n"
1217 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001218 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1219 " 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 +00001220 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1221 " output.gl_Position.w = gl_Position.w;\n";
1222 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001223
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001224 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001225 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001226 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001227 }
1228
1229 if (fragmentShader->mUsesFragCoord)
1230 {
1231 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1232 }
1233
1234 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1235 {
1236 if (varying->reg >= 0)
1237 {
1238 for (int i = 0; i < varying->size; i++)
1239 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001240 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001241
1242 for (int j = 0; j < rows; j++)
1243 {
1244 int r = varying->reg + i * rows + j;
1245 vertexHLSL += " output.v" + str(r);
1246
1247 bool sharedRegister = false; // Register used by multiple varyings
1248
1249 for (int x = 0; x < 4; x++)
1250 {
1251 if (packing[r][x] && packing[r][x] != packing[r][0])
1252 {
1253 sharedRegister = true;
1254 break;
1255 }
1256 }
1257
1258 if(sharedRegister)
1259 {
1260 vertexHLSL += ".";
1261
1262 for (int x = 0; x < 4; x++)
1263 {
1264 if (packing[r][x] == &*varying)
1265 {
1266 switch(x)
1267 {
1268 case 0: vertexHLSL += "x"; break;
1269 case 1: vertexHLSL += "y"; break;
1270 case 2: vertexHLSL += "z"; break;
1271 case 3: vertexHLSL += "w"; break;
1272 }
1273 }
1274 }
1275 }
1276
1277 vertexHLSL += " = " + varying->name;
1278
1279 if (varying->array)
1280 {
1281 vertexHLSL += "[" + str(i) + "]";
1282 }
1283
1284 if (rows > 1)
1285 {
1286 vertexHLSL += "[" + str(j) + "]";
1287 }
1288
1289 vertexHLSL += ";\n";
1290 }
1291 }
1292 }
1293 }
1294
1295 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001296 " return output;\n"
1297 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001298
1299 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001300 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001301
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001302 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001303
1304 if (fragmentShader->mUsesFragCoord)
1305 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001306 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001307 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001308
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001309 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1310 {
1311 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1312 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001313
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001314 // Must consume the PSIZE element if the geometry shader is not active
1315 // We won't know if we use a GS until we draw
1316 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1317 {
1318 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1319 }
1320
1321 if (fragmentShader->mUsesFragCoord)
1322 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001323 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001324 {
1325 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1326 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001327 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001328 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001329 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1330 }
1331 }
1332
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001333 pixelHLSL += "};\n"
1334 "\n"
1335 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001336 "{\n";
1337
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001338 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001339 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001340 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001341 }
1342
1343 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001344 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001345
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001346 if (fragmentShader->mUsesFrontFacing)
1347 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001348 if (shaderModel >= 4)
1349 {
1350 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1351 "{\n";
1352 }
1353 else
1354 {
1355 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1356 "{\n";
1357 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001358 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001359 else
1360 {
1361 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1362 "{\n";
1363 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001364
1365 if (fragmentShader->mUsesFragCoord)
1366 {
1367 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1368
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001369 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001370 {
1371 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1372 " gl_FragCoord.y = input.dx_VPos.y;\n";
1373 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001374 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001375 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001376 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001377 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001378 }
1379 else
1380 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001381 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1382 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1383 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001384 }
1385
daniel@transgaming.com12985182012-12-20 20:56:31 +00001386 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001387 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001388 }
1389
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001390 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001391 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001392 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1393 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001394 }
1395
1396 if (fragmentShader->mUsesFrontFacing)
1397 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001398 if (shaderModel <= 3)
1399 {
1400 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1401 }
1402 else
1403 {
1404 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1405 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001406 }
1407
1408 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1409 {
1410 if (varying->reg >= 0)
1411 {
1412 for (int i = 0; i < varying->size; i++)
1413 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001414 GLenum transposedType = TransposeMatrixType(varying->type);
1415 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001416 for (int j = 0; j < rows; j++)
1417 {
1418 std::string n = str(varying->reg + i * rows + j);
1419 pixelHLSL += " " + varying->name;
1420
1421 if (varying->array)
1422 {
1423 pixelHLSL += "[" + str(i) + "]";
1424 }
1425
1426 if (rows > 1)
1427 {
1428 pixelHLSL += "[" + str(j) + "]";
1429 }
1430
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001431 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001432 {
1433 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1434 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1435 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1436 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1437 default: UNREACHABLE();
1438 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001439 }
1440 }
1441 }
1442 else UNREACHABLE();
1443 }
1444
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00001445 if (pixelHLSL.find("dx_initConstantBuffers") != std::string::npos)
1446 {
1447 pixelHLSL += "\n"
1448 " dx_initConstantBuffers();\n";
1449 }
1450
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001451 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001452 " gl_main();\n"
1453 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001454 " PS_OUTPUT output;\n";
1455
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001456 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001457 {
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001458 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001459
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001460 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001461 }
1462
1463 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001464 " return output;\n"
1465 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001466
1467 return true;
1468}
1469
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001470std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1471{
1472 std::string varyingHLSL;
1473
1474 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1475 {
1476 if (varying->reg >= 0)
1477 {
1478 for (int i = 0; i < varying->size; i++)
1479 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001480 GLenum transposedType = TransposeMatrixType(varying->type);
1481 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001482 for (int j = 0; j < rows; j++)
1483 {
1484 switch (varying->interpolation)
1485 {
1486 case Smooth: varyingHLSL += " "; break;
1487 case Flat: varyingHLSL += " nointerpolation "; break;
1488 case Centroid: varyingHLSL += " centroid "; break;
1489 default: UNREACHABLE();
1490 }
1491
1492 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001493 varyingHLSL += "float" + str(VariableColumnCount(transposedType)) + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001494 }
1495 }
1496 }
1497 else UNREACHABLE();
1498 }
1499
1500 return varyingHLSL;
1501}
1502
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001503bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1504{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001505 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001506
1507 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001508 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001509 if (format != GL_PROGRAM_BINARY_ANGLE)
1510 {
1511 infoLog.append("Invalid program binary format.");
1512 return false;
1513 }
1514
1515 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001516 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001517 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001518 {
1519 infoLog.append("Invalid program binary version.");
1520 return false;
1521 }
1522
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001523 int compileFlags = 0;
1524 stream.read(&compileFlags);
1525 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1526 {
1527 infoLog.append("Mismatched compilation flags.");
1528 return false;
1529 }
1530
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001531 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1532 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001533 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001534 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001535 stream.read(&name);
1536 mLinkedAttribute[i].name = name;
1537 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001538 }
1539
1540 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1541 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001542 stream.read(&mSamplersPS[i].active);
1543 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001544
1545 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001546 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001547 mSamplersPS[i].textureType = (TextureType) textureType;
1548 }
1549
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001550 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001551 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001552 stream.read(&mSamplersVS[i].active);
1553 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001554
1555 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001556 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001557 mSamplersVS[i].textureType = (TextureType) textureType;
1558 }
1559
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001560 stream.read(&mUsedVertexSamplerRange);
1561 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001562 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001563 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001564
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001565 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001566 stream.read(&size);
1567 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001568 {
1569 infoLog.append("Invalid program binary.");
1570 return false;
1571 }
1572
1573 mUniforms.resize(size);
1574 for (unsigned int i = 0; i < size; ++i)
1575 {
1576 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001577 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001578 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001579 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001580 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001581
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001582 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001583 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001584 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001585 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001586 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001587
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001588 int offset;
1589 int arrayStride;
1590 int matrixStride;
1591 bool isRowMajorMatrix;
1592
1593 stream.read(&offset);
1594 stream.read(&arrayStride);
1595 stream.read(&matrixStride);
1596 stream.read(&isRowMajorMatrix);
1597
1598 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1599
1600 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001601
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001602 stream.read(&mUniforms[i]->psRegisterIndex);
1603 stream.read(&mUniforms[i]->vsRegisterIndex);
1604 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001605 }
1606
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001607 stream.read(&size);
1608 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001609 {
1610 infoLog.append("Invalid program binary.");
1611 return false;
1612 }
1613
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001614 mUniformBlocks.resize(size);
1615 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1616 {
1617 std::string name;
1618 unsigned int elementIndex;
1619 unsigned int dataSize;
1620
1621 stream.read(&name);
1622 stream.read(&elementIndex);
1623 stream.read(&dataSize);
1624
1625 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1626
1627 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1628 stream.read(&uniformBlock.psRegisterIndex);
1629 stream.read(&uniformBlock.vsRegisterIndex);
1630
1631 size_t numMembers;
1632 stream.read(&numMembers);
1633 uniformBlock.memberUniformIndexes.resize(numMembers);
1634 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1635 {
1636 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1637 }
1638 }
1639
1640 stream.read(&size);
1641 if (stream.error())
1642 {
1643 infoLog.append("Invalid program binary.");
1644 return false;
1645 }
1646
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001647 mUniformIndex.resize(size);
1648 for (unsigned int i = 0; i < size; ++i)
1649 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001650 stream.read(&mUniformIndex[i].name);
1651 stream.read(&mUniformIndex[i].element);
1652 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001653 }
1654
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001655 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001656 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001657
1658 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001659 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001660
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001661 unsigned int geometryShaderSize;
1662 stream.read(&geometryShaderSize);
1663
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001664 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001665
daniel@transgaming.com36038542012-11-28 20:59:26 +00001666 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001667 ptr += sizeof(GUID);
1668
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001669 GUID identifier = mRenderer->getAdapterIdentifier();
1670 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671 {
1672 infoLog.append("Invalid program binary.");
1673 return false;
1674 }
1675
1676 const char *pixelShaderFunction = ptr;
1677 ptr += pixelShaderSize;
1678
1679 const char *vertexShaderFunction = ptr;
1680 ptr += vertexShaderSize;
1681
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001682 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1683 ptr += geometryShaderSize;
1684
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001685 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001686 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001687 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688 {
1689 infoLog.append("Could not create pixel shader.");
1690 return false;
1691 }
1692
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001693 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001694 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001695 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001696 {
1697 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001698 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001699 mPixelExecutable = NULL;
1700 return false;
1701 }
1702
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001703 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1704 {
1705 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1706 geometryShaderSize, rx::SHADER_GEOMETRY);
1707 if (!mGeometryExecutable)
1708 {
1709 infoLog.append("Could not create geometry shader.");
1710 delete mPixelExecutable;
1711 mPixelExecutable = NULL;
1712 delete mVertexExecutable;
1713 mVertexExecutable = NULL;
1714 return false;
1715 }
1716 }
1717 else
1718 {
1719 mGeometryExecutable = NULL;
1720 }
1721
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001722 return true;
1723}
1724
1725bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1726{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001727 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001728
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001729 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001730 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001731 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001732
1733 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1734 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001735 stream.write(mLinkedAttribute[i].type);
1736 stream.write(mLinkedAttribute[i].name);
1737 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001738 }
1739
1740 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1741 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001742 stream.write(mSamplersPS[i].active);
1743 stream.write(mSamplersPS[i].logicalTextureUnit);
1744 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001745 }
1746
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001747 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001748 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001749 stream.write(mSamplersVS[i].active);
1750 stream.write(mSamplersVS[i].logicalTextureUnit);
1751 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001752 }
1753
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001754 stream.write(mUsedVertexSamplerRange);
1755 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001756 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001757 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001758
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001759 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001760 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001761 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001762 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001763
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001764 stream.write(uniform.type);
1765 stream.write(uniform.precision);
1766 stream.write(uniform.name);
1767 stream.write(uniform.arraySize);
1768 stream.write(uniform.blockIndex);
1769
1770 stream.write(uniform.blockInfo.offset);
1771 stream.write(uniform.blockInfo.arrayStride);
1772 stream.write(uniform.blockInfo.matrixStride);
1773 stream.write(uniform.blockInfo.isRowMajorMatrix);
1774
1775 stream.write(uniform.psRegisterIndex);
1776 stream.write(uniform.vsRegisterIndex);
1777 stream.write(uniform.registerCount);
1778 }
1779
1780 stream.write(mUniformBlocks.size());
1781 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1782 {
1783 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1784
1785 stream.write(uniformBlock.name);
1786 stream.write(uniformBlock.elementIndex);
1787 stream.write(uniformBlock.dataSize);
1788
1789 stream.write(uniformBlock.memberUniformIndexes.size());
1790 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1791 {
1792 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1793 }
1794
1795 stream.write(uniformBlock.psRegisterIndex);
1796 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001797 }
1798
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001799 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001800 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1801 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001802 stream.write(mUniformIndex[i].name);
1803 stream.write(mUniformIndex[i].element);
1804 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001805 }
1806
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001807 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001808 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001809
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001810 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001811 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001812
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001813 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1814 stream.write(geometryShaderSize);
1815
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001816 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001817
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001818 GLsizei streamLength = stream.length();
1819 const void *streamData = stream.data();
1820
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001821 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001822 if (totalLength > bufSize)
1823 {
1824 if (length)
1825 {
1826 *length = 0;
1827 }
1828
1829 return false;
1830 }
1831
1832 if (binary)
1833 {
1834 char *ptr = (char*) binary;
1835
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001836 memcpy(ptr, streamData, streamLength);
1837 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001838
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001839 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001840 ptr += sizeof(GUID);
1841
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001842 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001843 ptr += pixelShaderSize;
1844
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001845 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001846 ptr += vertexShaderSize;
1847
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001848 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1849 {
1850 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1851 ptr += geometryShaderSize;
1852 }
1853
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001854 ASSERT(ptr - totalLength == binary);
1855 }
1856
1857 if (length)
1858 {
1859 *length = totalLength;
1860 }
1861
1862 return true;
1863}
1864
1865GLint ProgramBinary::getLength()
1866{
1867 GLint length;
1868 if (save(NULL, INT_MAX, &length))
1869 {
1870 return length;
1871 }
1872 else
1873 {
1874 return 0;
1875 }
1876}
1877
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001878bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001879{
1880 if (!fragmentShader || !fragmentShader->isCompiled())
1881 {
1882 return false;
1883 }
1884
1885 if (!vertexShader || !vertexShader->isCompiled())
1886 {
1887 return false;
1888 }
1889
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001890 mShaderVersion = vertexShader->getShaderVersion();
1891
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001892 std::string pixelHLSL = fragmentShader->getHLSL();
1893 std::string vertexHLSL = vertexShader->getHLSL();
1894
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001895 // Map the varyings to the register file
1896 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
1897 int registers = packVaryings(infoLog, packing, fragmentShader);
1898
1899 if (registers < 0)
1900 {
1901 return false;
1902 }
1903
1904 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001905 {
1906 return false;
1907 }
1908
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001909 bool success = true;
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001910 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
1911 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001912
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001913 if (usesGeometryShader())
1914 {
1915 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
1916 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
1917 }
1918
1919 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001920 {
daniel@transgaming.com95892412012-11-28 20:59:09 +00001921 infoLog.append("Failed to create D3D shaders.");
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001922 success = false;
daniel@transgaming.com95892412012-11-28 20:59:09 +00001923
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001924 delete mVertexExecutable;
1925 mVertexExecutable = NULL;
1926 delete mPixelExecutable;
1927 mPixelExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001928 delete mGeometryExecutable;
1929 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001930 }
1931
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001932 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
1933 {
1934 success = false;
1935 }
1936
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001937 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001938 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00001939 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00001940 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001941
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00001942 // special case for gl_DepthRange, the only built-in uniform (also a struct)
1943 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
1944 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001945 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1946 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
1947 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 +00001948 }
1949
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00001950 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
1951 {
1952 success = false;
1953 }
1954
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00001955 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001956}
1957
1958// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001959bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001960{
1961 unsigned int usedLocations = 0;
1962
1963 // Link attributes that have a binding location
1964 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1965 {
1966 int location = attributeBindings.getAttributeBinding(attribute->name);
1967
1968 if (location != -1) // Set by glBindAttribLocation
1969 {
1970 if (!mLinkedAttribute[location].name.empty())
1971 {
1972 // Multiple active attributes bound to the same location; not an error
1973 }
1974
1975 mLinkedAttribute[location] = *attribute;
1976
1977 int rows = VariableRowCount(attribute->type);
1978
1979 if (rows + location > MAX_VERTEX_ATTRIBS)
1980 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001981 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 +00001982
1983 return false;
1984 }
1985
1986 for (int i = 0; i < rows; i++)
1987 {
1988 usedLocations |= 1 << (location + i);
1989 }
1990 }
1991 }
1992
1993 // Link attributes that don't have a binding location
1994 for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
1995 {
1996 int location = attributeBindings.getAttributeBinding(attribute->name);
1997
1998 if (location == -1) // Not set by glBindAttribLocation
1999 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002000 int rows = AttributeRegisterCount(attribute->type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002001 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2002
2003 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2004 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002005 infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002006
2007 return false; // Fail to link
2008 }
2009
2010 mLinkedAttribute[availableIndex] = *attribute;
2011 }
2012 }
2013
2014 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2015 {
2016 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00002017 int rows = std::max(AttributeRegisterCount(mLinkedAttribute[attributeIndex].type), 1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002018
2019 for (int r = 0; r < rows; r++)
2020 {
2021 mSemanticIndex[attributeIndex++] = index++;
2022 }
2023 }
2024
2025 return true;
2026}
2027
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002028bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2029{
2030 if (vertexUniform.type != fragmentUniform.type)
2031 {
2032 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2033 return false;
2034 }
2035 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2036 {
2037 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2038 return false;
2039 }
2040 else if (vertexUniform.precision != fragmentUniform.precision)
2041 {
2042 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2043 return false;
2044 }
2045 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2046 {
2047 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2048 }
2049
2050 const unsigned int numMembers = vertexUniform.fields.size();
2051 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2052 {
2053 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2054 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2055
2056 if (vertexMember.name != fragmentMember.name)
2057 {
2058 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2059 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2060 return false;
2061 }
2062
2063 const std::string memberName = uniformName + "." + vertexUniform.name;
2064 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2065 {
2066 return false;
2067 }
2068 }
2069
2070 return true;
2071}
2072
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002073bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002074{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002075 // Check that uniforms defined in the vertex and fragment shaders are identical
2076 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2077 UniformMap linkedUniforms;
2078
2079 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2080 {
2081 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2082 linkedUniforms[vertexUniform.name] = &vertexUniform;
2083 }
2084
2085 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2086 {
2087 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2088 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2089 if (entry != linkedUniforms.end())
2090 {
2091 const sh::Uniform &vertexUniform = *entry->second;
2092 const std::string &uniformName = "uniform " + vertexUniform.name;
2093 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2094 {
2095 return false;
2096 }
2097 }
2098 }
2099
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002100 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002101 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002102 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002103 {
2104 return false;
2105 }
2106 }
2107
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002108 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002109 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002110 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002111 {
2112 return false;
2113 }
2114 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002115
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 return true;
2117}
2118
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002119int totalRegisterCount(const sh::Uniform &uniform)
2120{
2121 int registerCount = 0;
2122
2123 if (!uniform.fields.empty())
2124 {
2125 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2126 {
2127 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2128 }
2129 }
2130 else
2131 {
2132 registerCount = 1;
2133 }
2134
2135 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2136}
2137
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002138bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002139{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002140 if (!constant.fields.empty())
2141 {
2142 if (constant.arraySize > 0)
2143 {
2144 unsigned int elementRegisterIndex = constant.registerIndex;
2145
2146 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2147 {
2148 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2149 {
2150 const sh::Uniform &field = constant.fields[fieldIndex];
2151 const std::string &uniformName = constant.name + "[" + str(elementIndex) + "]." + field.name;
2152 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex);
2153 if (!defineUniform(shader, fieldUniform, infoLog))
2154 {
2155 return false;
2156 }
2157 elementRegisterIndex += totalRegisterCount(field);
2158 }
2159 }
2160 }
2161 else
2162 {
2163 unsigned int fieldRegisterIndex = constant.registerIndex;
2164
2165 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2166 {
2167 const sh::Uniform &field = constant.fields[fieldIndex];
2168 const std::string &uniformName = constant.name + "." + field.name;
2169
2170 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex);
2171 fieldUniform.fields = field.fields;
2172
2173 if (!defineUniform(shader, fieldUniform, infoLog))
2174 {
2175 return false;
2176 }
2177 fieldRegisterIndex += totalRegisterCount(field);
2178 }
2179 }
2180
2181 return true;
2182 }
2183
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002184 if (constant.type == GL_SAMPLER_2D ||
2185 constant.type == GL_SAMPLER_CUBE)
2186 {
2187 unsigned int samplerIndex = constant.registerIndex;
2188
2189 do
2190 {
2191 if (shader == GL_VERTEX_SHADER)
2192 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002193 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002194 {
2195 mSamplersVS[samplerIndex].active = true;
2196 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2197 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2198 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2199 }
2200 else
2201 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002202 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002203 return false;
2204 }
2205 }
2206 else if (shader == GL_FRAGMENT_SHADER)
2207 {
2208 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2209 {
2210 mSamplersPS[samplerIndex].active = true;
2211 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2212 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2213 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2214 }
2215 else
2216 {
2217 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2218 return false;
2219 }
2220 }
2221 else UNREACHABLE();
2222
2223 samplerIndex++;
2224 }
2225 while (samplerIndex < constant.registerIndex + constant.arraySize);
2226 }
2227
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002228 Uniform *uniform = NULL;
2229 GLint location = getUniformLocation(constant.name);
2230
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002231 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002232 {
2233 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002234 }
2235 else
2236 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002237 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002238 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002239
2240 if (!uniform)
2241 {
2242 return false;
2243 }
2244
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002245 if (shader == GL_FRAGMENT_SHADER)
2246 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002247 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002248 }
2249 else if (shader == GL_VERTEX_SHADER)
2250 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002251 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002252 }
2253 else UNREACHABLE();
2254
2255 if (location >= 0)
2256 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002257 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002258 }
2259
2260 mUniforms.push_back(uniform);
2261 unsigned int uniformIndex = mUniforms.size() - 1;
2262
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002263 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002264 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002265 mUniformIndex.push_back(UniformLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002266 }
2267
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002268 if (shader == GL_VERTEX_SHADER)
2269 {
2270 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2271 {
2272 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2273 return false;
2274 }
2275 }
2276 else if (shader == GL_FRAGMENT_SHADER)
2277 {
2278 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2279 {
2280 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2281 return false;
2282 }
2283 }
2284 else UNREACHABLE();
2285
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002286 return true;
2287}
2288
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002289bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2290{
2291 const char* blockName = vertexInterfaceBlock.name.c_str();
2292
2293 // validate blocks for the same member types
2294 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2295 {
2296 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2297 return false;
2298 }
2299
2300 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2301 {
2302 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2303 return false;
2304 }
2305
2306 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2307 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2308 {
2309 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2310 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2311
2312 if (vertexMember.name != fragmentMember.name)
2313 {
2314 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2315 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2316 return false;
2317 }
2318
2319 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2320 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2321 {
2322 return false;
2323 }
2324 }
2325
2326 return true;
2327}
2328
2329bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2330{
2331 // Check that interface blocks defined in the vertex and fragment shaders are identical
2332 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2333 UniformBlockMap linkedUniformBlocks;
2334
2335 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2336 {
2337 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2338 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2339 }
2340
2341 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2342 {
2343 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2344 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2345 if (entry != linkedUniformBlocks.end())
2346 {
2347 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2348 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2349 {
2350 return false;
2351 }
2352 }
2353 }
2354
2355 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2356 {
2357 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2358 {
2359 return false;
2360 }
2361 }
2362
2363 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2364 {
2365 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2366 {
2367 return false;
2368 }
2369 }
2370
2371 return true;
2372}
2373
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002374void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2375{
2376 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2377 {
2378 const sh::Uniform &uniform = uniforms[uniformIndex];
2379
2380 if (!uniform.fields.empty())
2381 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002382 if (uniform.arraySize > 0)
2383 {
2384 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2385 {
2386 const std::string uniformElementName = uniform.name + "[" + str(arrayElement) + "]";
2387 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2388 }
2389 }
2390 else
2391 {
2392 defineUniformBlockMembers(uniform.fields, uniform.name, blockIndex, blockInfoItr, blockUniformIndexes);
2393 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002394 }
2395 else
2396 {
2397 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
2398 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2399 blockIndex, **blockInfoItr);
2400
2401 // add to uniform list, but not index, since uniform block uniforms have no location
2402 blockUniformIndexes->push_back(mUniforms.size());
2403 mUniforms.push_back(newUniform);
2404 (*blockInfoItr)++;
2405 }
2406 }
2407}
2408
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002409bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2410{
2411 // create uniform block entries if they do not exist
2412 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2413 {
2414 std::vector<unsigned int> blockUniformIndexes;
2415 const unsigned int blockIndex = mUniformBlocks.size();
2416
2417 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002418 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2419 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002420
2421 // create all the uniform blocks
2422 if (interfaceBlock.arraySize > 0)
2423 {
2424 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2425 {
2426 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2427 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2428 mUniformBlocks.push_back(newUniformBlock);
2429 }
2430 }
2431 else
2432 {
2433 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2434 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2435 mUniformBlocks.push_back(newUniformBlock);
2436 }
2437 }
2438
2439 // Assign registers to the uniform blocks
2440 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2441 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2442 ASSERT(blockIndex != GL_INVALID_INDEX);
2443 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2444
2445 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2446 {
2447 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2448 ASSERT(uniformBlock->name == interfaceBlock.name);
2449
2450 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2451 {
2452 return false;
2453 }
2454 }
2455
2456 return true;
2457}
2458
2459bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2460{
2461 if (shader == GL_VERTEX_SHADER)
2462 {
2463 uniformBlock->vsRegisterIndex = registerIndex;
2464 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2465
2466 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2467 {
2468 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2469 return false;
2470 }
2471 }
2472 else if (shader == GL_FRAGMENT_SHADER)
2473 {
2474 uniformBlock->psRegisterIndex = registerIndex;
2475 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2476
2477 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2478 {
2479 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2480 return false;
2481 }
2482 }
2483 else UNREACHABLE();
2484
2485 return true;
2486}
2487
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002488std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2489{
2490 // for now we only handle point sprite emulation
2491 ASSERT(usesPointSpriteEmulation());
2492 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2493}
2494
2495std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2496{
2497 ASSERT(registers >= 0);
2498 ASSERT(vertexShader->mUsesPointSize);
2499 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2500
2501 std::string geomHLSL;
2502
2503 std::string varyingSemantic = "TEXCOORD";
2504
2505 std::string fragCoordSemantic;
2506 std::string pointCoordSemantic;
2507
2508 int reservedRegisterIndex = registers;
2509
2510 if (fragmentShader->mUsesFragCoord)
2511 {
2512 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2513 }
2514
2515 if (fragmentShader->mUsesPointCoord)
2516 {
2517 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2518 }
2519
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002520 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2521 "\n"
2522 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002523 "{\n";
2524
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002525 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002526
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002527 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002528
2529 if (fragmentShader->mUsesFragCoord)
2530 {
2531 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2532 }
2533
2534 geomHLSL += " float gl_PointSize : PSIZE;\n"
2535 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002536 "};\n"
2537 "\n"
2538 "struct GS_OUTPUT\n"
2539 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002540
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002541 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002542
2543 if (fragmentShader->mUsesFragCoord)
2544 {
2545 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2546 }
2547
2548 if (fragmentShader->mUsesPointCoord)
2549 {
2550 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2551 }
2552
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002553 geomHLSL += " float gl_PointSize : PSIZE;\n"
2554 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002555 "};\n"
2556 "\n"
2557 "static float2 pointSpriteCorners[] = \n"
2558 "{\n"
2559 " float2( 0.5f, -0.5f),\n"
2560 " float2( 0.5f, 0.5f),\n"
2561 " float2(-0.5f, -0.5f),\n"
2562 " float2(-0.5f, 0.5f)\n"
2563 "};\n"
2564 "\n"
2565 "static float2 pointSpriteTexcoords[] = \n"
2566 "{\n"
2567 " float2(1.0f, 1.0f),\n"
2568 " float2(1.0f, 0.0f),\n"
2569 " float2(0.0f, 1.0f),\n"
2570 " float2(0.0f, 0.0f)\n"
2571 "};\n"
2572 "\n"
2573 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2574 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2575 "\n"
2576 "[maxvertexcount(4)]\n"
2577 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2578 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002579 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2580 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002581
2582 for (int r = 0; r < registers; r++)
2583 {
2584 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2585 }
2586
2587 if (fragmentShader->mUsesFragCoord)
2588 {
2589 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2590 }
2591
2592 geomHLSL += " \n"
2593 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2594 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002595 " 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 +00002596
2597 for (int corner = 0; corner < 4; corner++)
2598 {
2599 geomHLSL += " \n"
2600 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2601
2602 if (fragmentShader->mUsesPointCoord)
2603 {
2604 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2605 }
2606
2607 geomHLSL += " outStream.Append(output);\n";
2608 }
2609
2610 geomHLSL += " \n"
2611 " outStream.RestartStrip();\n"
2612 "}\n";
2613
2614 return geomHLSL;
2615}
2616
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002617// This method needs to match OutputHLSL::decorate
2618std::string ProgramBinary::decorateAttribute(const std::string &name)
2619{
2620 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2621 {
2622 return "_" + name;
2623 }
2624
2625 return name;
2626}
2627
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002628bool ProgramBinary::isValidated() const
2629{
2630 return mValidated;
2631}
2632
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002633void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002634{
2635 // Skip over inactive attributes
2636 unsigned int activeAttribute = 0;
2637 unsigned int attribute;
2638 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2639 {
2640 if (mLinkedAttribute[attribute].name.empty())
2641 {
2642 continue;
2643 }
2644
2645 if (activeAttribute == index)
2646 {
2647 break;
2648 }
2649
2650 activeAttribute++;
2651 }
2652
2653 if (bufsize > 0)
2654 {
2655 const char *string = mLinkedAttribute[attribute].name.c_str();
2656
2657 strncpy(name, string, bufsize);
2658 name[bufsize - 1] = '\0';
2659
2660 if (length)
2661 {
2662 *length = strlen(name);
2663 }
2664 }
2665
2666 *size = 1; // Always a single 'type' instance
2667
2668 *type = mLinkedAttribute[attribute].type;
2669}
2670
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002671GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002672{
2673 int count = 0;
2674
2675 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2676 {
2677 if (!mLinkedAttribute[attributeIndex].name.empty())
2678 {
2679 count++;
2680 }
2681 }
2682
2683 return count;
2684}
2685
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002686GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002687{
2688 int maxLength = 0;
2689
2690 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2691 {
2692 if (!mLinkedAttribute[attributeIndex].name.empty())
2693 {
2694 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2695 }
2696 }
2697
2698 return maxLength;
2699}
2700
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002701void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002702{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002703 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002704
2705 if (bufsize > 0)
2706 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002707 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002708
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002709 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002710 {
2711 string += "[0]";
2712 }
2713
2714 strncpy(name, string.c_str(), bufsize);
2715 name[bufsize - 1] = '\0';
2716
2717 if (length)
2718 {
2719 *length = strlen(name);
2720 }
2721 }
2722
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002723 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002724
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002725 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002726}
2727
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002728GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002729{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002730 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002731}
2732
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002733GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002734{
2735 int maxLength = 0;
2736
2737 unsigned int numUniforms = mUniforms.size();
2738 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2739 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002740 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002741 {
2742 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2743 if (mUniforms[uniformIndex]->isArray())
2744 {
2745 length += 3; // Counting in "[0]".
2746 }
2747 maxLength = std::max(length, maxLength);
2748 }
2749 }
2750
2751 return maxLength;
2752}
2753
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002754GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2755{
2756 const gl::Uniform& uniform = *mUniforms[index];
2757
2758 switch (pname)
2759 {
2760 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2761 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002762 case GL_UNIFORM_NAME_LENGTH: return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002763 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002764
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002765 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2766 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2767 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2768 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002769
2770 default:
2771 UNREACHABLE();
2772 break;
2773 }
2774 return 0;
2775}
2776
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002777void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2778{
2779 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2780
2781 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2782
2783 if (bufSize > 0)
2784 {
2785 std::string string = uniformBlock.name;
2786
2787 if (uniformBlock.isArrayElement())
2788 {
2789 string += "[" + str(uniformBlock.elementIndex) + "]";
2790 }
2791
2792 strncpy(uniformBlockName, string.c_str(), bufSize);
2793 uniformBlockName[bufSize - 1] = '\0';
2794
2795 if (length)
2796 {
2797 *length = strlen(uniformBlockName);
2798 }
2799 }
2800}
2801
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002802void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2803{
2804 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2805
2806 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2807
2808 switch (pname)
2809 {
2810 case GL_UNIFORM_BLOCK_DATA_SIZE:
2811 *params = static_cast<GLint>(uniformBlock.dataSize);
2812 break;
2813 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002814 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002815 break;
2816 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2817 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2818 break;
2819 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2820 {
2821 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2822 {
2823 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2824 }
2825 }
2826 break;
2827 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2828 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2829 break;
2830 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2831 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2832 break;
2833 default: UNREACHABLE();
2834 }
2835}
2836
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002837GLuint ProgramBinary::getActiveUniformBlockCount() const
2838{
2839 return mUniformBlocks.size();
2840}
2841
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002842GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2843{
2844 unsigned int maxLength = 0;
2845
2846 unsigned int numUniformBlocks = mUniformBlocks.size();
2847 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2848 {
2849 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2850 if (!uniformBlock.name.empty())
2851 {
2852 const unsigned int length = uniformBlock.name.length() + 1;
2853
2854 // Counting in "[0]".
2855 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2856
2857 maxLength = std::max(length + arrayLength, maxLength);
2858 }
2859 }
2860
2861 return maxLength;
2862}
2863
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002864void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002865{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002866 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002867 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002868 {
2869 mValidated = false;
2870 }
2871 else
2872 {
2873 mValidated = true;
2874 }
2875}
2876
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002877bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002878{
2879 // if any two active samplers in a program are of different types, but refer to the same
2880 // texture image unit, and this is the current program, then ValidateProgram will fail, and
2881 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
2882
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00002883 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002884 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002885
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002886 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002887 {
2888 textureUnitType[i] = TEXTURE_UNKNOWN;
2889 }
2890
2891 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
2892 {
2893 if (mSamplersPS[i].active)
2894 {
2895 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
2896
2897 if (unit >= maxCombinedTextureImageUnits)
2898 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002899 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002900 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002901 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002902 }
2903
2904 return false;
2905 }
2906
2907 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2908 {
2909 if (mSamplersPS[i].textureType != textureUnitType[unit])
2910 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002911 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002912 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002913 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002914 }
2915
2916 return false;
2917 }
2918 }
2919 else
2920 {
2921 textureUnitType[unit] = mSamplersPS[i].textureType;
2922 }
2923 }
2924 }
2925
2926 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
2927 {
2928 if (mSamplersVS[i].active)
2929 {
2930 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
2931
2932 if (unit >= maxCombinedTextureImageUnits)
2933 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002934 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002935 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002936 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002937 }
2938
2939 return false;
2940 }
2941
2942 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
2943 {
2944 if (mSamplersVS[i].textureType != textureUnitType[unit])
2945 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002946 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002947 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002948 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002949 }
2950
2951 return false;
2952 }
2953 }
2954 else
2955 {
2956 textureUnitType[unit] = mSamplersVS[i].textureType;
2957 }
2958 }
2959 }
2960
2961 return true;
2962}
2963
apatrick@chromium.org90080e32012-07-09 22:15:33 +00002964ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
2965{
2966}
2967
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00002968struct AttributeSorter
2969{
2970 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
2971 : originalIndices(semanticIndices)
2972 {
2973 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2974 {
2975 indices[i] = i;
2976 }
2977
2978 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
2979 }
2980
2981 bool operator()(int a, int b)
2982 {
2983 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
2984 }
2985
2986 int indices[MAX_VERTEX_ATTRIBS];
2987 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
2988};
2989
2990void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
2991{
2992 AttributeSorter sorter(mSemanticIndex);
2993
2994 int oldIndices[MAX_VERTEX_ATTRIBS];
2995 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
2996
2997 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
2998 {
2999 oldIndices[i] = mSemanticIndex[i];
3000 oldTranslatedAttributes[i] = attributes[i];
3001 }
3002
3003 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3004 {
3005 int oldIndex = sorter.indices[i];
3006 sortedSemanticIndices[i] = oldIndices[oldIndex];
3007 attributes[i] = oldTranslatedAttributes[oldIndex];
3008 }
3009}
3010
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003011}