blob: 54766b99a421f7a7ece2d9e9abe01d507ae8f6ee [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"
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +000024#include "libGLESv2/Buffer.h"
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +000025
daniel@transgaming.com88853c52012-12-20 20:56:40 +000026#undef near
27#undef far
28
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000029namespace gl
30{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +000031std::string str(int i)
32{
33 char buffer[20];
34 snprintf(buffer, sizeof(buffer), "%d", i);
35 return buffer;
36}
37
Jamie Madill63491ea2013-06-06 11:56:45 -040038std::string arrayString(int i)
39{
40 return "[" + str(i) + "]";
41}
42
Jamie Madill46131a32013-06-20 11:55:50 -040043std::string arrayString(unsigned int i)
44{
45 return (i == GL_INVALID_INDEX ? "" : "[" + str(i) + "]");
46}
47
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000048namespace gl_d3d
49{
50 std::string TypeString(GLenum type)
51 {
52 switch (type)
53 {
54 case GL_FLOAT: return "float";
55 case GL_FLOAT_VEC2: return "float2";
56 case GL_FLOAT_VEC3: return "float3";
57 case GL_FLOAT_VEC4: return "float4";
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +000058 case GL_INT: return "int";
59 case GL_INT_VEC2: return "int2";
60 case GL_INT_VEC3: return "int3";
61 case GL_INT_VEC4: return "int4";
shannonwoods@chromium.org6b709912013-05-30 00:20:04 +000062 case GL_UNSIGNED_INT: return "uint";
shannonwoods@chromium.org8c788e82013-05-30 00:20:21 +000063 case GL_UNSIGNED_INT_VEC2: return "uint2";
64 case GL_UNSIGNED_INT_VEC3: return "uint3";
65 case GL_UNSIGNED_INT_VEC4: return "uint4";
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +000066 case GL_FLOAT_MAT2: return "float2x2";
67 case GL_FLOAT_MAT3: return "float3x3";
68 case GL_FLOAT_MAT4: return "float4x4";
69 case GL_FLOAT_MAT2x3: return "float2x3";
70 case GL_FLOAT_MAT3x2: return "float3x2";
71 case GL_FLOAT_MAT2x4: return "float2x4";
72 case GL_FLOAT_MAT4x2: return "float4x2";
73 case GL_FLOAT_MAT3x4: return "float3x4";
74 case GL_FLOAT_MAT4x3: return "float4x3";
75 default: UNREACHABLE(); return "invalid-gl-type";
76 }
77 }
78}
79
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +000080namespace
81{
82
83unsigned int parseAndStripArrayIndex(std::string* name)
84{
85 unsigned int subscript = GL_INVALID_INDEX;
86
87 // Strip any trailing array operator and retrieve the subscript
88 size_t open = name->find_last_of('[');
89 size_t close = name->find_last_of(']');
90 if (open != std::string::npos && close == name->length() - 1)
91 {
92 subscript = atoi(name->substr(open + 1).c_str());
93 name->erase(open);
94 }
95
96 return subscript;
97}
98
99}
100
Jamie Madill63491ea2013-06-06 11:56:45 -0400101VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
daniel@transgaming.comdb019952012-12-20 21:13:32 +0000102 : name(name), element(element), index(index)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000103{
104}
105
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000106unsigned int ProgramBinary::mCurrentSerial = 1;
107
daniel@transgaming.com77fbf972012-11-28 21:02:55 +0000108ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000109{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000110 mPixelExecutable = NULL;
111 mVertexExecutable = NULL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000112 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000113
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000114 mValidated = false;
115
116 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
117 {
118 mSemanticIndex[index] = -1;
119 }
120
121 for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
122 {
123 mSamplersPS[index].active = false;
124 }
125
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000126 for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000127 {
128 mSamplersVS[index].active = false;
129 }
130
131 mUsedVertexSamplerRange = 0;
132 mUsedPixelSamplerRange = 0;
shannon.woods@transgaming.com962d4be2013-01-25 21:55:18 +0000133 mUsesPointSize = false;
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000134 mShaderVersion = 100;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000135}
136
137ProgramBinary::~ProgramBinary()
138{
daniel@transgaming.com95892412012-11-28 20:59:09 +0000139 delete mPixelExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000140 mPixelExecutable = NULL;
141
daniel@transgaming.com95892412012-11-28 20:59:09 +0000142 delete mVertexExecutable;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000143 mVertexExecutable = NULL;
144
145 delete mGeometryExecutable;
146 mGeometryExecutable = NULL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000147
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000148 while (!mUniforms.empty())
149 {
150 delete mUniforms.back();
151 mUniforms.pop_back();
152 }
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +0000153
154 while (!mUniformBlocks.empty())
155 {
156 delete mUniformBlocks.back();
157 mUniformBlocks.pop_back();
158 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000159}
160
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000161unsigned int ProgramBinary::getSerial() const
162{
163 return mSerial;
164}
165
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +0000166int ProgramBinary::getShaderVersion() const
167{
168 return mShaderVersion;
169}
170
daniel@transgaming.come87ca002012-07-24 18:30:43 +0000171unsigned int ProgramBinary::issueSerial()
172{
173 return mCurrentSerial++;
174}
175
daniel@transgaming.com95892412012-11-28 20:59:09 +0000176rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000177{
178 return mPixelExecutable;
179}
180
daniel@transgaming.com95892412012-11-28 20:59:09 +0000181rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000182{
183 return mVertexExecutable;
184}
185
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000186rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
187{
188 return mGeometryExecutable;
189}
190
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000191GLuint ProgramBinary::getAttributeLocation(const char *name)
192{
193 if (name)
194 {
195 for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
196 {
197 if (mLinkedAttribute[index].name == std::string(name))
198 {
199 return index;
200 }
201 }
202 }
203
204 return -1;
205}
206
207int ProgramBinary::getSemanticIndex(int attributeIndex)
208{
209 ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
210
211 return mSemanticIndex[attributeIndex];
212}
213
214// Returns one more than the highest sampler index used.
215GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
216{
217 switch (type)
218 {
219 case SAMPLER_PIXEL:
220 return mUsedPixelSamplerRange;
221 case SAMPLER_VERTEX:
222 return mUsedVertexSamplerRange;
223 default:
224 UNREACHABLE();
225 return 0;
226 }
227}
228
daniel@transgaming.com087e5782012-09-17 21:28:47 +0000229bool ProgramBinary::usesPointSize() const
230{
231 return mUsesPointSize;
232}
233
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +0000234bool ProgramBinary::usesPointSpriteEmulation() const
235{
236 return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
237}
238
239bool ProgramBinary::usesGeometryShader() const
240{
241 return usesPointSpriteEmulation();
242}
243
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000244// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
245// index (0-15 for the pixel shader and 0-3 for the vertex shader).
246GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
247{
248 GLint logicalTextureUnit = -1;
249
250 switch (type)
251 {
252 case SAMPLER_PIXEL:
253 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
254
255 if (mSamplersPS[samplerIndex].active)
256 {
257 logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
258 }
259 break;
260 case SAMPLER_VERTEX:
261 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
262
263 if (mSamplersVS[samplerIndex].active)
264 {
265 logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
266 }
267 break;
268 default: UNREACHABLE();
269 }
270
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000271 if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000272 {
273 return logicalTextureUnit;
274 }
275
276 return -1;
277}
278
279// Returns the texture type for a given Direct3D 9 sampler type and
280// index (0-15 for the pixel shader and 0-3 for the vertex shader).
281TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
282{
283 switch (type)
284 {
285 case SAMPLER_PIXEL:
286 ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
287 ASSERT(mSamplersPS[samplerIndex].active);
288 return mSamplersPS[samplerIndex].textureType;
289 case SAMPLER_VERTEX:
290 ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
291 ASSERT(mSamplersVS[samplerIndex].active);
292 return mSamplersVS[samplerIndex].textureType;
293 default: UNREACHABLE();
294 }
295
296 return TEXTURE_2D;
297}
298
299GLint ProgramBinary::getUniformLocation(std::string name)
300{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000301 unsigned int subscript = parseAndStripArrayIndex(&name);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000302
303 unsigned int numUniforms = mUniformIndex.size();
304 for (unsigned int location = 0; location < numUniforms; location++)
305 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000306 if (mUniformIndex[location].name == name)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000307 {
shannonwoods@chromium.org0ee85f82013-05-30 00:05:47 +0000308 const int index = mUniformIndex[location].index;
309 const bool isArray = mUniforms[index]->isArray();
310
311 if ((isArray && mUniformIndex[location].element == subscript) ||
312 (subscript == GL_INVALID_INDEX))
313 {
314 return location;
315 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000316 }
317 }
318
319 return -1;
320}
321
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000322GLuint ProgramBinary::getUniformIndex(std::string name)
323{
shannonwoods@chromium.org6d7b61c2013-05-30 00:06:38 +0000324 unsigned int subscript = parseAndStripArrayIndex(&name);
shannonwoods@chromium.orgc2ed9912013-05-30 00:05:33 +0000325
326 // The app is not allowed to specify array indices other than 0 for arrays of basic types
327 if (subscript != 0 && subscript != GL_INVALID_INDEX)
328 {
329 return GL_INVALID_INDEX;
330 }
331
332 unsigned int numUniforms = mUniforms.size();
333 for (unsigned int index = 0; index < numUniforms; index++)
334 {
335 if (mUniforms[index]->name == name)
336 {
337 if (mUniforms[index]->isArray() || subscript == GL_INVALID_INDEX)
338 {
339 return index;
340 }
341 }
342 }
343
344 return GL_INVALID_INDEX;
345}
346
shannonwoods@chromium.org42766252013-05-30 00:07:12 +0000347GLuint ProgramBinary::getUniformBlockIndex(std::string name)
348{
349 unsigned int subscript = parseAndStripArrayIndex(&name);
350
351 unsigned int numUniformBlocks = mUniformBlocks.size();
352 for (unsigned int blockIndex = 0; blockIndex < numUniformBlocks; blockIndex++)
353 {
354 const UniformBlock &uniformBlock = *mUniformBlocks[blockIndex];
355 if (uniformBlock.name == name)
356 {
357 const bool arrayElementZero = (subscript == GL_INVALID_INDEX && uniformBlock.elementIndex == 0);
358 if (subscript == uniformBlock.elementIndex || arrayElementZero)
359 {
360 return blockIndex;
361 }
362 }
363 }
364
365 return GL_INVALID_INDEX;
366}
367
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000368UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
369{
370 ASSERT(blockIndex < mUniformBlocks.size());
371 return mUniformBlocks[blockIndex];
372}
373
Jamie Madilld1e78c92013-06-20 11:55:50 -0400374GLint ProgramBinary::getFragDataLocation(const char *name) const
375{
376 std::string baseName(name);
377 unsigned int arrayIndex;
378 arrayIndex = parseAndStripArrayIndex(&baseName);
379
380 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
381 {
382 const VariableLocation &outputVariable = locationIt->second;
383
384 if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
385 {
386 return static_cast<GLint>(locationIt->first);
387 }
388 }
389
390 return -1;
391}
392
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000393template <typename T>
394bool ProgramBinary::setUniform(GLint location, GLsizei count, const T* v, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000395{
396 if (location < 0 || location >= (int)mUniformIndex.size())
397 {
398 return false;
399 }
400
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000401 const int components = UniformComponentCount(targetUniformType);
402 const GLenum targetBoolType = UniformBoolVectorType(targetUniformType);
403
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000404 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
405 targetUniform->dirty = true;
406
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000407 int elementCount = targetUniform->elementCount();
408
409 if (elementCount == 1 && count > 1)
410 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
411
412 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
413
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000414 if (targetUniform->type == targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000415 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000416 T *target = (T*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000417
418 for (int i = 0; i < count; i++)
419 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000420 for (int c = 0; c < components; c++)
421 {
422 target[c] = v[c];
423 }
424 for (int c = components; c < 4; c++)
425 {
426 target[c] = 0;
427 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000428 target += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000429 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000430 }
431 }
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000432 else if (targetUniform->type == targetBoolType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000433 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000434 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000435
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000436 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000437 {
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000438 for (int c = 0; c < components; c++)
439 {
440 boolParams[c] = (v[c] == static_cast<T>(0)) ? GL_FALSE : GL_TRUE;
441 }
442 for (int c = components; c < 4; c++)
443 {
444 boolParams[c] = GL_FALSE;
445 }
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000446 boolParams += 4;
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000447 v += components;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000448 }
449 }
450 else
451 {
452 return false;
453 }
454
455 return true;
456}
457
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000458bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
459{
460 return setUniform(location, count, v, GL_FLOAT);
461}
462
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000463bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
464{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000465 return setUniform(location, count, v, GL_FLOAT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000466}
467
468bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
469{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000470 return setUniform(location, count, v, GL_FLOAT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000471}
472
473bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
474{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000475 return setUniform(location, count, v, GL_FLOAT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000476}
477
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000478template<typename T>
479void transposeMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000480{
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000481 int copyWidth = std::min(targetHeight, srcWidth);
482 int copyHeight = std::min(targetWidth, srcHeight);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000483
484 for (int x = 0; x < copyWidth; x++)
485 {
486 for (int y = 0; y < copyHeight; y++)
487 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000488 target[x * targetWidth + y] = static_cast<T>(value[y * srcWidth + x]);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000489 }
490 }
491 // clear unfilled right side
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000492 for (int y = 0; y < copyWidth; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000493 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000494 for (int x = copyHeight; x < targetWidth; x++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000495 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000496 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000497 }
498 }
499 // clear unfilled bottom.
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000500 for (int y = copyWidth; y < targetHeight; y++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000501 {
502 for (int x = 0; x < targetWidth; x++)
503 {
shannon.woods%transgaming.com@gtempaccount.comcc62fac2013-04-13 03:39:52 +0000504 target[y * targetWidth + x] = static_cast<T>(0);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000505 }
506 }
507}
508
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000509template<typename T>
510void expandMatrix(T *target, const GLfloat *value, int targetWidth, int targetHeight, int srcWidth, int srcHeight)
511{
512 int copyWidth = std::min(targetWidth, srcWidth);
513 int copyHeight = std::min(targetHeight, srcHeight);
514
515 for (int y = 0; y < copyHeight; y++)
516 {
517 for (int x = 0; x < copyWidth; x++)
518 {
519 target[y * targetWidth + x] = static_cast<T>(value[y * srcWidth + x]);
520 }
521 }
522 // clear unfilled right side
523 for (int y = 0; y < copyHeight; y++)
524 {
525 for (int x = copyWidth; x < targetWidth; x++)
526 {
527 target[y * targetWidth + x] = static_cast<T>(0);
528 }
529 }
530 // clear unfilled bottom.
531 for (int y = copyHeight; y < targetHeight; y++)
532 {
533 for (int x = 0; x < targetWidth; x++)
534 {
535 target[y * targetWidth + x] = static_cast<T>(0);
536 }
537 }
538}
539
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000540template <int cols, int rows>
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000541bool ProgramBinary::setUniformMatrixfv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value, GLenum targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000542{
543 if (location < 0 || location >= (int)mUniformIndex.size())
544 {
545 return false;
546 }
547
548 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
549 targetUniform->dirty = true;
550
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000551 if (targetUniform->type != targetUniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000552 {
553 return false;
554 }
555
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000556 int elementCount = targetUniform->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000557
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000558 if (elementCount == 1 && count > 1)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000559 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
560
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000561 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000562 const unsigned int targetMatrixStride = (4 * rows);
563 GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * targetMatrixStride);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000564
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000565 for (int i = 0; i < count; i++)
566 {
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000567 // Internally store matrices as transposed versions to accomodate HLSL matrix indexing
568 if (transpose == GL_FALSE)
569 {
570 transposeMatrix<GLfloat>(target, value, 4, rows, rows, cols);
571 }
572 else
573 {
574 expandMatrix<GLfloat>(target, value, 4, rows, cols, rows);
575 }
shannonwoods@chromium.org2c2b82b2013-05-30 00:15:12 +0000576 target += targetMatrixStride;
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000577 value += cols * rows;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000578 }
579
580 return true;
581}
582
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000583bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000584{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000585 return setUniformMatrixfv<2, 2>(location, count, transpose, value, GL_FLOAT_MAT2);
shannon.woods%transgaming.com@gtempaccount.com36c76a92013-04-13 03:39:58 +0000586}
587
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000588bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000589{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000590 return setUniformMatrixfv<3, 3>(location, count, transpose, value, GL_FLOAT_MAT3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000591}
592
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000593bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000594{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000595 return setUniformMatrixfv<4, 4>(location, count, transpose, value, GL_FLOAT_MAT4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000596}
597
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000598bool ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000599{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000600 return setUniformMatrixfv<2, 3>(location, count, transpose, value, GL_FLOAT_MAT2x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000601}
602
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000603bool ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000604{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000605 return setUniformMatrixfv<3, 2>(location, count, transpose, value, GL_FLOAT_MAT3x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000606}
607
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000608bool ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000609{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000610 return setUniformMatrixfv<2, 4>(location, count, transpose, value, GL_FLOAT_MAT2x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000611}
612
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000613bool ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000614{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000615 return setUniformMatrixfv<4, 2>(location, count, transpose, value, GL_FLOAT_MAT4x2);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000616}
617
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000618bool ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000619{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000620 return setUniformMatrixfv<3, 4>(location, count, transpose, value, GL_FLOAT_MAT3x4);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000621}
622
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000623bool ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000624{
shannon.woods%transgaming.com@gtempaccount.coma741b642013-04-13 03:40:10 +0000625 return setUniformMatrixfv<4, 3>(location, count, transpose, value, GL_FLOAT_MAT4x3);
shannon.woods%transgaming.com@gtempaccount.comf1306162013-04-13 03:40:04 +0000626}
627
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000628bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
629{
630 if (location < 0 || location >= (int)mUniformIndex.size())
631 {
632 return false;
633 }
634
635 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
636 targetUniform->dirty = true;
637
shannon.woods@transgaming.com15de0f92013-02-28 23:10:31 +0000638 int elementCount = targetUniform->elementCount();
639
640 if (elementCount == 1 && count > 1)
641 return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
642
643 count = std::min(elementCount - (int)mUniformIndex[location].element, count);
644
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000645 if (targetUniform->type == GL_INT ||
646 targetUniform->type == GL_SAMPLER_2D ||
647 targetUniform->type == GL_SAMPLER_CUBE)
648 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000649 GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000650
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000651 for (int i = 0; i < count; i++)
652 {
653 target[0] = v[0];
654 target[1] = 0;
655 target[2] = 0;
656 target[3] = 0;
657 target += 4;
658 v += 1;
659 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000660 }
661 else if (targetUniform->type == GL_BOOL)
662 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000663 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000664
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000665 for (int i = 0; i < count; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000666 {
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000667 boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
668 boolParams[1] = GL_FALSE;
669 boolParams[2] = GL_FALSE;
670 boolParams[3] = GL_FALSE;
671 boolParams += 4;
672 v += 1;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000673 }
674 }
675 else
676 {
677 return false;
678 }
679
680 return true;
681}
682
683bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
684{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000685 return setUniform(location, count, v, GL_INT_VEC2);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000686}
687
688bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
689{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000690 return setUniform(location, count, v, GL_INT_VEC3);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000691}
692
693bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
694{
shannon.woods%transgaming.com@gtempaccount.com8a19eed2013-04-13 03:40:22 +0000695 return setUniform(location, count, v, GL_INT_VEC4);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000696}
697
shannon.woods%transgaming.com@gtempaccount.com50ea4ab2013-04-13 03:40:36 +0000698bool ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
699{
700 return setUniform(location, count, v, GL_UNSIGNED_INT);
701}
702
703bool ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
704{
705 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC2);
706}
707
708bool ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
709{
710 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC3);
711}
712
713bool ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
714{
715 return setUniform(location, count, v, GL_UNSIGNED_INT_VEC4);
716}
717
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000718template <typename T>
719bool ProgramBinary::getUniformv(GLint location, GLsizei *bufSize, T *params, GLenum uniformType)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000720{
721 if (location < 0 || location >= (int)mUniformIndex.size())
722 {
723 return false;
724 }
725
726 Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
727
728 // sized queries -- ensure the provided buffer is large enough
729 if (bufSize)
730 {
731 int requiredBytes = UniformExternalSize(targetUniform->type);
732 if (*bufSize < requiredBytes)
733 {
734 return false;
735 }
736 }
737
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000738 if (IsMatrixType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000739 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000740 const int rows = VariableRowCount(targetUniform->type);
741 const int cols = VariableColumnCount(targetUniform->type);
742 transposeMatrix(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4 * rows, cols, rows, 4, rows);
743 }
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000744 else if (uniformType == UniformComponentType(targetUniform->type))
745 {
746 unsigned int size = UniformComponentCount(targetUniform->type);
747 memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(T),
748 size * sizeof(T));
749 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000750 else
751 {
752 unsigned int size = UniformComponentCount(targetUniform->type);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000753 switch (UniformComponentType(targetUniform->type))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000754 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000755 case GL_BOOL:
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000756 {
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000757 GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000758
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000759 for (unsigned int i = 0; i < size; i++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000760 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000761 params[i] = (boolParams[i] == GL_FALSE) ? static_cast<T>(0) : static_cast<T>(1);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000762 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000763 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000764 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000765
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000766 case GL_FLOAT:
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000767 {
768 GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
769
770 for (unsigned int i = 0; i < size; i++)
771 {
772 params[i] = static_cast<T>(floatParams[i]);
773 }
774 }
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000775 break;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000776
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000777 case GL_INT:
778 {
779 GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
780
781 for (unsigned int i = 0; i < size; i++)
782 {
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000783 params[i] = static_cast<T>(intParams[i]);
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000784 }
785 }
786 break;
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000787
788 case GL_UNSIGNED_INT:
789 {
790 GLuint *uintParams = (GLuint*)targetUniform->data + mUniformIndex[location].element * 4;
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000791
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000792 for (unsigned int i = 0; i < size; i++)
793 {
794 params[i] = static_cast<T>(uintParams[i]);
795 }
796 }
797 break;
798
shannon.woods%transgaming.com@gtempaccount.comf4895612013-04-13 03:40:56 +0000799 default: UNREACHABLE();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000800 }
801 }
802
803 return true;
804}
805
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000806bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
807{
808 return getUniformv(location, bufSize, params, GL_FLOAT);
809}
810
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000811bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
812{
shannon.woods%transgaming.com@gtempaccount.com4590d892013-04-13 03:41:01 +0000813 return getUniformv(location, bufSize, params, GL_INT);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000814}
815
shannon.woods%transgaming.com@gtempaccount.come2290122013-04-13 03:41:07 +0000816bool ProgramBinary::getUniformuiv(GLint location, GLsizei *bufSize, GLuint *params)
817{
818 return getUniformv(location, bufSize, params, GL_UNSIGNED_INT);
819}
820
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000821void ProgramBinary::dirtyAllUniforms()
822{
823 unsigned int numUniforms = mUniforms.size();
824 for (unsigned int index = 0; index < numUniforms; index++)
825 {
826 mUniforms[index]->dirty = true;
827 }
828}
829
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000830// Applies all the uniforms set for this program object to the renderer
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000831void ProgramBinary::applyUniforms()
832{
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000833 // Retrieve sampler uniform values
834 for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
835 {
836 Uniform *targetUniform = *ub;
837
838 if (targetUniform->dirty)
839 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000840 if (targetUniform->type == GL_SAMPLER_2D ||
841 targetUniform->type == GL_SAMPLER_CUBE)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000842 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +0000843 int count = targetUniform->elementCount();
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000844 GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000845
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000846 if (targetUniform->isReferencedByFragmentShader())
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000847 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000848 unsigned int firstIndex = targetUniform->psRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000849
850 for (int i = 0; i < count; i++)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000851 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000852 unsigned int samplerIndex = firstIndex + i;
853
854 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000855 {
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000856 ASSERT(mSamplersPS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000857 mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000858 }
859 }
860 }
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000861
shannonwoods@chromium.org38676dc2013-05-30 00:06:52 +0000862 if (targetUniform->isReferencedByVertexShader())
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000863 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +0000864 unsigned int firstIndex = targetUniform->vsRegisterIndex;
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000865
866 for (int i = 0; i < count; i++)
867 {
868 unsigned int samplerIndex = firstIndex + i;
869
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +0000870 if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000871 {
872 ASSERT(mSamplersVS[samplerIndex].active);
shannon.woods@transgaming.com2494c972013-02-28 23:10:03 +0000873 mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
daniel@transgaming.comf9561862012-12-20 21:12:07 +0000874 }
875 }
876 }
daniel@transgaming.comb6e55102012-12-20 21:08:14 +0000877 }
878 }
879 }
880
shannon.woods@transgaming.com358e88d2013-01-25 21:53:11 +0000881 mRenderer->applyUniforms(this, &mUniforms);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000882}
883
shannonwoods@chromium.org1bddfb92013-05-30 00:11:29 +0000884bool ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers)
885{
886 const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
887 const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
888
889 const unsigned int reservedBuffersInVS = mRenderer->getReservedVertexUniformBuffers();
890 const unsigned int reservedBuffersInFS = mRenderer->getReservedFragmentUniformBuffers();
891
892 ASSERT(boundBuffers.size() == mUniformBlocks.size());
893
894 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); uniformBlockIndex++)
895 {
896 gl::UniformBlock *uniformBlock = getUniformBlockByIndex(uniformBlockIndex);
897 gl::Buffer *uniformBuffer = boundBuffers[uniformBlockIndex];
898
899 ASSERT(uniformBlock && uniformBuffer);
900
901 if (uniformBuffer->size() < uniformBlock->dataSize)
902 {
903 // undefined behaviour
904 return false;
905 }
906
907 ASSERT(uniformBlock->isReferencedByVertexShader() || uniformBlock->isReferencedByFragmentShader());
908
909 if (uniformBlock->isReferencedByVertexShader())
910 {
911 unsigned int registerIndex = uniformBlock->vsRegisterIndex - reservedBuffersInVS;
912 ASSERT(vertexUniformBuffers[registerIndex] == NULL);
913 ASSERT(registerIndex < mRenderer->getMaxVertexShaderUniformBuffers());
914 vertexUniformBuffers[registerIndex] = uniformBuffer;
915 }
916
917 if (uniformBlock->isReferencedByFragmentShader())
918 {
919 unsigned int registerIndex = uniformBlock->psRegisterIndex - reservedBuffersInFS;
920 ASSERT(fragmentUniformBuffers[registerIndex] == NULL);
921 ASSERT(registerIndex < mRenderer->getMaxFragmentShaderUniformBuffers());
922 fragmentUniformBuffers[registerIndex] = uniformBuffer;
923 }
924 }
925
926 return mRenderer->setUniformBuffers(vertexUniformBuffers, fragmentUniformBuffers);
927}
928
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000929// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
930// Returns the number of used varying registers, or -1 if unsuccesful
apatrick@chromium.org253b8d22012-06-22 19:27:21 +0000931int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000932{
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +0000933 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000934
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +0000935 fragmentShader->resetVaryingsRegisterAssignment();
936
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000937 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
938 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +0000939 GLenum transposedType = TransposeMatrixType(varying->type);
940 int n = VariableRowCount(transposedType) * varying->size;
941 int m = VariableColumnCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +0000942 bool success = false;
943
944 if (m == 2 || m == 3 || m == 4)
945 {
946 for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
947 {
948 bool available = true;
949
950 for (int y = 0; y < n && available; y++)
951 {
952 for (int x = 0; x < m && available; x++)
953 {
954 if (packing[r + y][x])
955 {
956 available = false;
957 }
958 }
959 }
960
961 if (available)
962 {
963 varying->reg = r;
964 varying->col = 0;
965
966 for (int y = 0; y < n; y++)
967 {
968 for (int x = 0; x < m; x++)
969 {
970 packing[r + y][x] = &*varying;
971 }
972 }
973
974 success = true;
975 }
976 }
977
978 if (!success && m == 2)
979 {
980 for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
981 {
982 bool available = true;
983
984 for (int y = 0; y < n && available; y++)
985 {
986 for (int x = 2; x < 4 && available; x++)
987 {
988 if (packing[r + y][x])
989 {
990 available = false;
991 }
992 }
993 }
994
995 if (available)
996 {
997 varying->reg = r;
998 varying->col = 2;
999
1000 for (int y = 0; y < n; y++)
1001 {
1002 for (int x = 2; x < 4; x++)
1003 {
1004 packing[r + y][x] = &*varying;
1005 }
1006 }
1007
1008 success = true;
1009 }
1010 }
1011 }
1012 }
1013 else if (m == 1)
1014 {
1015 int space[4] = {0};
1016
1017 for (int y = 0; y < maxVaryingVectors; y++)
1018 {
1019 for (int x = 0; x < 4; x++)
1020 {
1021 space[x] += packing[y][x] ? 0 : 1;
1022 }
1023 }
1024
1025 int column = 0;
1026
1027 for (int x = 0; x < 4; x++)
1028 {
1029 if (space[x] >= n && space[x] < space[column])
1030 {
1031 column = x;
1032 }
1033 }
1034
1035 if (space[column] >= n)
1036 {
1037 for (int r = 0; r < maxVaryingVectors; r++)
1038 {
1039 if (!packing[r][column])
1040 {
1041 varying->reg = r;
1042
1043 for (int y = r; y < r + n; y++)
1044 {
1045 packing[y][column] = &*varying;
1046 }
1047
1048 break;
1049 }
1050 }
1051
1052 varying->col = column;
1053
1054 success = true;
1055 }
1056 }
1057 else UNREACHABLE();
1058
1059 if (!success)
1060 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001061 infoLog.append("Could not pack varying %s", varying->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001062
1063 return -1;
1064 }
1065 }
1066
1067 // Return the number of used registers
1068 int registers = 0;
1069
1070 for (int r = 0; r < maxVaryingVectors; r++)
1071 {
1072 if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
1073 {
1074 registers++;
1075 }
1076 }
1077
1078 return registers;
1079}
1080
Jamie Madill46131a32013-06-20 11:55:50 -04001081void ProgramBinary::defineOutputVariables(FragmentShader *fragmentShader)
1082{
1083 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1084
1085 for (unsigned int outputVariableIndex = 0; outputVariableIndex < outputVars.size(); outputVariableIndex++)
1086 {
1087 const sh::ShaderVariable &outputVariable = outputVars[outputVariableIndex];
1088 const int baseLocation = outputVariable.location == -1 ? 0 : outputVariable.location;
1089
1090 if (outputVariable.arraySize > 0)
1091 {
1092 for (unsigned int elementIndex = 0; elementIndex < outputVariable.arraySize; elementIndex++)
1093 {
1094 const int location = baseLocation + elementIndex;
1095 ASSERT(mOutputVariables.count(location) == 0);
1096 mOutputVariables[location] = VariableLocation(outputVariable.name, elementIndex, outputVariableIndex);
1097 }
1098 }
1099 else
1100 {
1101 ASSERT(mOutputVariables.count(baseLocation) == 0);
1102 mOutputVariables[baseLocation] = VariableLocation(outputVariable.name, GL_INVALID_INDEX, outputVariableIndex);
1103 }
1104 }
1105}
1106
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001107bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
1108 std::string& pixelHLSL, std::string& vertexHLSL,
1109 FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001110{
1111 if (pixelHLSL.empty() || vertexHLSL.empty())
1112 {
1113 return false;
1114 }
1115
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001116 bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
1117 bool usesFragColor = fragmentShader->mUsesFragColor;
1118 bool usesFragData = fragmentShader->mUsesFragData;
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001119 if (usesFragColor && usesFragData)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001120 {
1121 infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
1122 return false;
1123 }
1124
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001125 // Write the HLSL input/output declarations
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001126 const int shaderModel = mRenderer->getMajorShaderModel();
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00001127 const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001128
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001129 const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
1130
shannon.woods%transgaming.com@gtempaccount.come3fe5dad2013-04-13 03:42:07 +00001131 // Two cases when writing to gl_FragColor and using ESSL 1.0:
1132 // - with a 3.0 context, the output color is copied to channel 0
1133 // - with a 2.0 context, the output color is broadcast to all channels
1134 const bool broadcast = (fragmentShader->mUsesFragColor && mRenderer->getCurrentClientVersion() < 3);
1135 const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
1136
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001137 if (registersNeeded > maxVaryingVectors)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001138 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001139 infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001140
1141 return false;
1142 }
1143
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00001144 vertexShader->resetVaryingsRegisterAssignment();
1145
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001146 for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
1147 {
1148 bool matched = false;
1149
1150 for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
1151 {
1152 if (output->name == input->name)
1153 {
shannon.woods%transgaming.com@gtempaccount.com1886fd42013-04-13 03:41:45 +00001154 if (output->type != input->type || output->size != input->size || output->interpolation != input->interpolation)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001155 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001156 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 +00001157
1158 return false;
1159 }
1160
1161 output->reg = input->reg;
1162 output->col = input->col;
1163
1164 matched = true;
1165 break;
1166 }
1167 }
1168
1169 if (!matched)
1170 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001171 infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001172
1173 return false;
1174 }
1175 }
1176
daniel@transgaming.com087e5782012-09-17 21:28:47 +00001177 mUsesPointSize = vertexShader->mUsesPointSize;
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001178 std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001179 std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001180 std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001181 std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001182
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001183 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
1184
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001185 // special varyings that use reserved registers
1186 int reservedRegisterIndex = registers;
1187 std::string fragCoordSemantic;
1188 std::string pointCoordSemantic;
1189
1190 if (fragmentShader->mUsesFragCoord)
1191 {
1192 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1193 }
1194
1195 if (fragmentShader->mUsesPointCoord)
1196 {
1197 // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
1198 // In DX11 we compute this in the GS.
1199 if (shaderModel == 3)
1200 {
1201 pointCoordSemantic = "TEXCOORD0";
1202 }
1203 else if (shaderModel >= 4)
1204 {
1205 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
1206 }
1207 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001208
1209 vertexHLSL += "struct VS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001210 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001211
1212 int semanticIndex = 0;
Jamie Madilldefb6742013-06-20 11:55:51 -04001213 const sh::ActiveShaderVariables &activeAttributes = vertexShader->mActiveAttributes;
1214 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001215 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001216 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1217 vertexHLSL += " " + gl_d3d::TypeString(TransposeMatrixType(attribute.type)) + " ";
1218 vertexHLSL += decorateAttribute(attribute.name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001219
Jamie Madilldefb6742013-06-20 11:55:51 -04001220 semanticIndex += AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001221 }
1222
1223 vertexHLSL += "};\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001224 "\n"
1225 "struct VS_OUTPUT\n"
1226 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001227
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001228 if (shaderModel < 4)
1229 {
1230 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1231 }
1232
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001233 vertexHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001234
1235 if (fragmentShader->mUsesFragCoord)
1236 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001237 vertexHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001238 }
1239
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001240 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001241 {
1242 vertexHLSL += " float gl_PointSize : PSIZE;\n";
1243 }
1244
shannon.woods%transgaming.com@gtempaccount.comee8d3c82013-04-13 03:27:26 +00001245 if (shaderModel >= 4)
1246 {
1247 vertexHLSL += " float4 gl_Position : " + positionSemantic + ";\n";
1248 }
1249
1250 vertexHLSL += "};\n"
daniel@transgaming.com9c4a6252013-01-11 04:07:18 +00001251 "\n"
1252 "VS_OUTPUT main(VS_INPUT input)\n"
1253 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001254
Jamie Madilldefb6742013-06-20 11:55:51 -04001255 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001256 {
Jamie Madilldefb6742013-06-20 11:55:51 -04001257 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
1258 vertexHLSL += " " + decorateAttribute(attribute.name) + " = ";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001259
Jamie Madilldefb6742013-06-20 11:55:51 -04001260 if (IsMatrixType(attribute.type)) // Matrix
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001261 {
1262 vertexHLSL += "transpose";
1263 }
1264
Jamie Madilldefb6742013-06-20 11:55:51 -04001265 vertexHLSL += "(input." + decorateAttribute(attribute.name) + ");\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001266 }
1267
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001268 if (shaderModel >= 4)
1269 {
1270 vertexHLSL += "\n"
1271 " gl_main();\n"
1272 "\n"
1273 " VS_OUTPUT output;\n"
1274 " output.gl_Position.x = gl_Position.x;\n"
1275 " output.gl_Position.y = -gl_Position.y;\n"
1276 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1277 " output.gl_Position.w = gl_Position.w;\n";
1278 }
1279 else
1280 {
1281 vertexHLSL += "\n"
1282 " gl_main();\n"
1283 "\n"
1284 " VS_OUTPUT output;\n"
shannon.woods@transgaming.com42832a62013-02-28 23:18:38 +00001285 " output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
1286 " 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 +00001287 " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
1288 " output.gl_Position.w = gl_Position.w;\n";
1289 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001290
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001291 if (vertexShader->mUsesPointSize && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001292 {
daniel@transgaming.com13be3e42012-07-04 19:16:24 +00001293 vertexHLSL += " output.gl_PointSize = gl_PointSize;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001294 }
1295
1296 if (fragmentShader->mUsesFragCoord)
1297 {
1298 vertexHLSL += " output.gl_FragCoord = gl_Position;\n";
1299 }
1300
1301 for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
1302 {
1303 if (varying->reg >= 0)
1304 {
1305 for (int i = 0; i < varying->size; i++)
1306 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001307 int rows = VariableRowCount(TransposeMatrixType(varying->type));
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001308
1309 for (int j = 0; j < rows; j++)
1310 {
1311 int r = varying->reg + i * rows + j;
1312 vertexHLSL += " output.v" + str(r);
1313
1314 bool sharedRegister = false; // Register used by multiple varyings
1315
1316 for (int x = 0; x < 4; x++)
1317 {
1318 if (packing[r][x] && packing[r][x] != packing[r][0])
1319 {
1320 sharedRegister = true;
1321 break;
1322 }
1323 }
1324
1325 if(sharedRegister)
1326 {
1327 vertexHLSL += ".";
1328
1329 for (int x = 0; x < 4; x++)
1330 {
1331 if (packing[r][x] == &*varying)
1332 {
1333 switch(x)
1334 {
1335 case 0: vertexHLSL += "x"; break;
1336 case 1: vertexHLSL += "y"; break;
1337 case 2: vertexHLSL += "z"; break;
1338 case 3: vertexHLSL += "w"; break;
1339 }
1340 }
1341 }
1342 }
1343
1344 vertexHLSL += " = " + varying->name;
1345
1346 if (varying->array)
1347 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001348 vertexHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001349 }
1350
1351 if (rows > 1)
1352 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001353 vertexHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001354 }
1355
1356 vertexHLSL += ";\n";
1357 }
1358 }
1359 }
1360 }
1361
1362 vertexHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001363 " return output;\n"
1364 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001365
1366 pixelHLSL += "struct PS_INPUT\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001367 "{\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001368
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001369 pixelHLSL += varyingHLSL;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001370
1371 if (fragmentShader->mUsesFragCoord)
1372 {
shannon.woods@transgaming.come0e89872013-01-25 21:55:40 +00001373 pixelHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001374 }
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001375
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001376 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
1377 {
1378 pixelHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
1379 }
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00001380
shannon.woods@transgaming.com0693fc32013-02-28 23:18:03 +00001381 // Must consume the PSIZE element if the geometry shader is not active
1382 // We won't know if we use a GS until we draw
1383 if (vertexShader->mUsesPointSize && shaderModel >= 4)
1384 {
1385 pixelHLSL += " float gl_PointSize : PSIZE;\n";
1386 }
1387
1388 if (fragmentShader->mUsesFragCoord)
1389 {
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001390 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001391 {
1392 pixelHLSL += " float4 dx_VPos : SV_Position;\n";
1393 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001394 else if (shaderModel >= 3)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001395 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001396 pixelHLSL += " float2 dx_VPos : VPOS;\n";
1397 }
1398 }
1399
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001400 pixelHLSL += "};\n"
1401 "\n"
1402 "struct PS_OUTPUT\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001403 "{\n";
1404
Jamie Madill46131a32013-06-20 11:55:50 -04001405 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001406 {
Jamie Madill46131a32013-06-20 11:55:50 -04001407 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1408 {
1409 pixelHLSL += " float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
1410 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001411
1412 if (fragmentShader->mUsesFragDepth)
1413 {
1414 pixelHLSL += " float gl_Depth : " + depthSemantic + ";\n";
1415 }
Jamie Madill46131a32013-06-20 11:55:50 -04001416 }
1417 else
1418 {
1419 defineOutputVariables(fragmentShader);
1420
1421 const sh::ActiveShaderVariables &outputVars = fragmentShader->getOutputVariables();
1422 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1423 {
1424 const VariableLocation &outputLocation = locationIt->second;
1425 const sh::ShaderVariable &outputVariable = outputVars[outputLocation.index];
1426 const std::string &elementString = (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1427
1428 pixelHLSL += " " + gl_d3d::TypeString(outputVariable.type) +
1429 " out_" + outputLocation.name + elementString +
1430 " : " + targetSemantic + str(locationIt->first) + ";\n";
1431 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001432 }
1433
1434 pixelHLSL += "};\n"
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001435 "\n";
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001436
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001437 if (fragmentShader->mUsesFrontFacing)
1438 {
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001439 if (shaderModel >= 4)
1440 {
1441 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
1442 "{\n";
1443 }
1444 else
1445 {
1446 pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
1447 "{\n";
1448 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001449 }
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001450 else
1451 {
1452 pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
1453 "{\n";
1454 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001455
1456 if (fragmentShader->mUsesFragCoord)
1457 {
1458 pixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
1459
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001460 if (shaderModel >= 4)
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001461 {
1462 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x;\n"
1463 " gl_FragCoord.y = input.dx_VPos.y;\n";
1464 }
daniel@transgaming.comb37cd2d2013-01-11 04:10:31 +00001465 else if (shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001466 {
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001467 pixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001468 " gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001469 }
1470 else
1471 {
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00001472 // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
1473 pixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
1474 " gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001475 }
1476
daniel@transgaming.com12985182012-12-20 20:56:31 +00001477 pixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
daniel@transgaming.com74471e02013-01-11 04:10:26 +00001478 " gl_FragCoord.w = rhw;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001479 }
1480
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001481 if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001482 {
apatrick@chromium.org9616e582012-06-22 18:27:01 +00001483 pixelHLSL += " gl_PointCoord.x = input.gl_PointCoord.x;\n";
1484 pixelHLSL += " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001485 }
1486
1487 if (fragmentShader->mUsesFrontFacing)
1488 {
shannon.woods@transgaming.com41ba5e02013-01-25 21:51:20 +00001489 if (shaderModel <= 3)
1490 {
1491 pixelHLSL += " gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
1492 }
1493 else
1494 {
1495 pixelHLSL += " gl_FrontFacing = isFrontFace;\n";
1496 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001497 }
1498
1499 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1500 {
1501 if (varying->reg >= 0)
1502 {
1503 for (int i = 0; i < varying->size; i++)
1504 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001505 GLenum transposedType = TransposeMatrixType(varying->type);
1506 int rows = VariableRowCount(transposedType);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001507 for (int j = 0; j < rows; j++)
1508 {
1509 std::string n = str(varying->reg + i * rows + j);
1510 pixelHLSL += " " + varying->name;
1511
1512 if (varying->array)
1513 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001514 pixelHLSL += arrayString(i);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001515 }
1516
1517 if (rows > 1)
1518 {
Jamie Madill63491ea2013-06-06 11:56:45 -04001519 pixelHLSL += arrayString(j);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001520 }
1521
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001522 switch (VariableColumnCount(transposedType))
daniel@transgaming.comf5a2ae52012-12-20 20:52:03 +00001523 {
1524 case 1: pixelHLSL += " = input.v" + n + ".x;\n"; break;
1525 case 2: pixelHLSL += " = input.v" + n + ".xy;\n"; break;
1526 case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
1527 case 4: pixelHLSL += " = input.v" + n + ";\n"; break;
1528 default: UNREACHABLE();
1529 }
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001530 }
1531 }
1532 }
1533 else UNREACHABLE();
1534 }
1535
1536 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001537 " gl_main();\n"
1538 "\n"
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001539 " PS_OUTPUT output;\n";
1540
Jamie Madill46131a32013-06-20 11:55:50 -04001541 if (mShaderVersion < 300)
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001542 {
Jamie Madill46131a32013-06-20 11:55:50 -04001543 for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
1544 {
1545 unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001546
Jamie Madill46131a32013-06-20 11:55:50 -04001547 pixelHLSL += " output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
1548 }
Jamie Madill2aeb26a2013-07-08 14:02:55 -04001549
1550 if (fragmentShader->mUsesFragDepth)
1551 {
1552 pixelHLSL += " output.gl_Depth = gl_Depth;\n";
1553 }
Jamie Madill46131a32013-06-20 11:55:50 -04001554 }
1555 else
1556 {
1557 for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
1558 {
1559 const VariableLocation &outputLocation = locationIt->second;
1560 const std::string &variableName = "out_" + outputLocation.name;
1561 const std::string &outVariableName = variableName + (outputLocation.element == GL_INVALID_INDEX ? "" : str(outputLocation.element));
1562 const std::string &staticVariableName = variableName + arrayString(outputLocation.element);
1563
1564 pixelHLSL += " output." + outVariableName + " = " + staticVariableName + ";\n";
1565 }
shannon.woods%transgaming.com@gtempaccount.coma28864c2013-04-13 03:32:03 +00001566 }
1567
1568 pixelHLSL += "\n"
shannon.woods@transgaming.com5f77c552013-01-25 21:51:44 +00001569 " return output;\n"
1570 "}\n";
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001571
1572 return true;
1573}
1574
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001575std::string ProgramBinary::generateVaryingHLSL(FragmentShader *fragmentShader, const std::string &varyingSemantic) const
1576{
1577 std::string varyingHLSL;
1578
1579 for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
1580 {
1581 if (varying->reg >= 0)
1582 {
1583 for (int i = 0; i < varying->size; i++)
1584 {
shannonwoods@chromium.org9bd22fa2013-05-30 00:18:47 +00001585 GLenum transposedType = TransposeMatrixType(varying->type);
1586 int rows = VariableRowCount(transposedType);
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001587 for (int j = 0; j < rows; j++)
1588 {
1589 switch (varying->interpolation)
1590 {
1591 case Smooth: varyingHLSL += " "; break;
1592 case Flat: varyingHLSL += " nointerpolation "; break;
1593 case Centroid: varyingHLSL += " centroid "; break;
1594 default: UNREACHABLE();
1595 }
1596
1597 std::string n = str(varying->reg + i * rows + j);
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001598 std::string typeString = gl_d3d::TypeString(UniformComponentType(transposedType)) + str(VariableColumnCount(transposedType));
shannonwoods@chromium.orgb4e07b82013-05-30 00:19:31 +00001599
shannonwoods@chromium.org5703d882013-05-30 00:19:38 +00001600 varyingHLSL += typeString + " v" + n + " : " + varyingSemantic + n + ";\n";
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00001601 }
1602 }
1603 }
1604 else UNREACHABLE();
1605 }
1606
1607 return varyingHLSL;
1608}
1609
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001610bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
1611{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001612 BinaryInputStream stream(binary, length);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001613
1614 int format = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001615 stream.read(&format);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001616 if (format != GL_PROGRAM_BINARY_ANGLE)
1617 {
1618 infoLog.append("Invalid program binary format.");
1619 return false;
1620 }
1621
1622 int version = 0;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001623 stream.read(&version);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001624 if (version != VERSION_DWORD)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001625 {
1626 infoLog.append("Invalid program binary version.");
1627 return false;
1628 }
1629
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001630 int compileFlags = 0;
1631 stream.read(&compileFlags);
1632 if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
1633 {
1634 infoLog.append("Mismatched compilation flags.");
1635 return false;
1636 }
1637
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001638 for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1639 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001640 stream.read(&mLinkedAttribute[i].type);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001641 std::string name;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001642 stream.read(&name);
1643 mLinkedAttribute[i].name = name;
1644 stream.read(&mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001645 }
1646
1647 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1648 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001649 stream.read(&mSamplersPS[i].active);
1650 stream.read(&mSamplersPS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001651
1652 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001653 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001654 mSamplersPS[i].textureType = (TextureType) textureType;
1655 }
1656
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001657 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001658 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001659 stream.read(&mSamplersVS[i].active);
1660 stream.read(&mSamplersVS[i].logicalTextureUnit);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001661
1662 int textureType;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001663 stream.read(&textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001664 mSamplersVS[i].textureType = (TextureType) textureType;
1665 }
1666
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001667 stream.read(&mUsedVertexSamplerRange);
1668 stream.read(&mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001669 stream.read(&mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001670 stream.read(&mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001671
shannon.woods@transgaming.com45886d62013-02-28 23:19:20 +00001672 size_t size;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001673 stream.read(&size);
1674 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001675 {
1676 infoLog.append("Invalid program binary.");
1677 return false;
1678 }
1679
1680 mUniforms.resize(size);
1681 for (unsigned int i = 0; i < size; ++i)
1682 {
1683 GLenum type;
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001684 GLenum precision;
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001685 std::string name;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001686 unsigned int arraySize;
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001687 int blockIndex;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001688
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001689 stream.read(&type);
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00001690 stream.read(&precision);
daniel@transgaming.comdb019952012-12-20 21:13:32 +00001691 stream.read(&name);
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001692 stream.read(&arraySize);
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001693 stream.read(&blockIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001694
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001695 int offset;
1696 int arrayStride;
1697 int matrixStride;
1698 bool isRowMajorMatrix;
1699
1700 stream.read(&offset);
1701 stream.read(&arrayStride);
1702 stream.read(&matrixStride);
1703 stream.read(&isRowMajorMatrix);
1704
1705 const sh::BlockMemberInfo blockInfo(offset, arrayStride, matrixStride, isRowMajorMatrix);
1706
1707 mUniforms[i] = new Uniform(type, precision, name, arraySize, blockIndex, blockInfo);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001708
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00001709 stream.read(&mUniforms[i]->psRegisterIndex);
1710 stream.read(&mUniforms[i]->vsRegisterIndex);
1711 stream.read(&mUniforms[i]->registerCount);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001712 }
1713
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001714 stream.read(&size);
1715 if (stream.error())
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001716 {
1717 infoLog.append("Invalid program binary.");
1718 return false;
1719 }
1720
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001721 mUniformBlocks.resize(size);
1722 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < size; ++uniformBlockIndex)
1723 {
1724 std::string name;
1725 unsigned int elementIndex;
1726 unsigned int dataSize;
1727
1728 stream.read(&name);
1729 stream.read(&elementIndex);
1730 stream.read(&dataSize);
1731
1732 mUniformBlocks[uniformBlockIndex] = new UniformBlock(name, elementIndex, dataSize);
1733
1734 UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1735 stream.read(&uniformBlock.psRegisterIndex);
1736 stream.read(&uniformBlock.vsRegisterIndex);
1737
1738 size_t numMembers;
1739 stream.read(&numMembers);
1740 uniformBlock.memberUniformIndexes.resize(numMembers);
1741 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
1742 {
1743 stream.read(&uniformBlock.memberUniformIndexes[blockMemberIndex]);
1744 }
1745 }
1746
1747 stream.read(&size);
1748 if (stream.error())
1749 {
1750 infoLog.append("Invalid program binary.");
1751 return false;
1752 }
1753
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001754 mUniformIndex.resize(size);
1755 for (unsigned int i = 0; i < size; ++i)
1756 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001757 stream.read(&mUniformIndex[i].name);
1758 stream.read(&mUniformIndex[i].element);
1759 stream.read(&mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001760 }
1761
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001762 unsigned int pixelShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001763 stream.read(&pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001764
1765 unsigned int vertexShaderSize;
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001766 stream.read(&vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001767
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001768 unsigned int geometryShaderSize;
1769 stream.read(&geometryShaderSize);
1770
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001771 const char *ptr = (const char*) binary + stream.offset();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001772
daniel@transgaming.com36038542012-11-28 20:59:26 +00001773 const GUID *binaryIdentifier = (const GUID *) ptr;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001774 ptr += sizeof(GUID);
1775
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001776 GUID identifier = mRenderer->getAdapterIdentifier();
1777 if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001778 {
1779 infoLog.append("Invalid program binary.");
1780 return false;
1781 }
1782
1783 const char *pixelShaderFunction = ptr;
1784 ptr += pixelShaderSize;
1785
1786 const char *vertexShaderFunction = ptr;
1787 ptr += vertexShaderSize;
1788
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001789 const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
1790 ptr += geometryShaderSize;
1791
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001792 mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001793 pixelShaderSize, rx::SHADER_PIXEL);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001794 if (!mPixelExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001795 {
1796 infoLog.append("Could not create pixel shader.");
1797 return false;
1798 }
1799
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001800 mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
shannon.woods@transgaming.com69ff7762013-01-25 21:55:24 +00001801 vertexShaderSize, rx::SHADER_VERTEX);
daniel@transgaming.com4f0f65e2012-11-28 21:00:00 +00001802 if (!mVertexExecutable)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001803 {
1804 infoLog.append("Could not create vertex shader.");
daniel@transgaming.com95892412012-11-28 20:59:09 +00001805 delete mPixelExecutable;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001806 mPixelExecutable = NULL;
1807 return false;
1808 }
1809
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001810 if (geometryShaderFunction != NULL && geometryShaderSize > 0)
1811 {
1812 mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
1813 geometryShaderSize, rx::SHADER_GEOMETRY);
1814 if (!mGeometryExecutable)
1815 {
1816 infoLog.append("Could not create geometry shader.");
1817 delete mPixelExecutable;
1818 mPixelExecutable = NULL;
1819 delete mVertexExecutable;
1820 mVertexExecutable = NULL;
1821 return false;
1822 }
1823 }
1824 else
1825 {
1826 mGeometryExecutable = NULL;
1827 }
1828
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001829 return true;
1830}
1831
1832bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
1833{
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001834 BinaryOutputStream stream;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001835
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001836 stream.write(GL_PROGRAM_BINARY_ANGLE);
daniel@transgaming.com8226f4c2012-12-20 21:08:42 +00001837 stream.write(VERSION_DWORD);
shannonwoods@chromium.orgf97a0842013-05-30 00:10:33 +00001838 stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001839
1840 for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
1841 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001842 stream.write(mLinkedAttribute[i].type);
1843 stream.write(mLinkedAttribute[i].name);
1844 stream.write(mSemanticIndex[i]);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001845 }
1846
1847 for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
1848 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001849 stream.write(mSamplersPS[i].active);
1850 stream.write(mSamplersPS[i].logicalTextureUnit);
1851 stream.write((int) mSamplersPS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001852 }
1853
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00001854 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001855 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001856 stream.write(mSamplersVS[i].active);
1857 stream.write(mSamplersVS[i].logicalTextureUnit);
1858 stream.write((int) mSamplersVS[i].textureType);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001859 }
1860
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001861 stream.write(mUsedVertexSamplerRange);
1862 stream.write(mUsedPixelSamplerRange);
daniel@transgaming.com9aa6fe12012-12-20 21:13:39 +00001863 stream.write(mUsesPointSize);
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001864 stream.write(mShaderVersion);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001865
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001866 stream.write(mUniforms.size());
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001867 for (unsigned int uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex)
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001868 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001869 const Uniform &uniform = *mUniforms[uniformIndex];
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001870
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00001871 stream.write(uniform.type);
1872 stream.write(uniform.precision);
1873 stream.write(uniform.name);
1874 stream.write(uniform.arraySize);
1875 stream.write(uniform.blockIndex);
1876
1877 stream.write(uniform.blockInfo.offset);
1878 stream.write(uniform.blockInfo.arrayStride);
1879 stream.write(uniform.blockInfo.matrixStride);
1880 stream.write(uniform.blockInfo.isRowMajorMatrix);
1881
1882 stream.write(uniform.psRegisterIndex);
1883 stream.write(uniform.vsRegisterIndex);
1884 stream.write(uniform.registerCount);
1885 }
1886
1887 stream.write(mUniformBlocks.size());
1888 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < mUniformBlocks.size(); ++uniformBlockIndex)
1889 {
1890 const UniformBlock& uniformBlock = *mUniformBlocks[uniformBlockIndex];
1891
1892 stream.write(uniformBlock.name);
1893 stream.write(uniformBlock.elementIndex);
1894 stream.write(uniformBlock.dataSize);
1895
1896 stream.write(uniformBlock.memberUniformIndexes.size());
1897 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
1898 {
1899 stream.write(uniformBlock.memberUniformIndexes[blockMemberIndex]);
1900 }
1901
1902 stream.write(uniformBlock.psRegisterIndex);
1903 stream.write(uniformBlock.vsRegisterIndex);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001904 }
1905
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001906 stream.write(mUniformIndex.size());
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001907 for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
1908 {
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001909 stream.write(mUniformIndex[i].name);
1910 stream.write(mUniformIndex[i].element);
1911 stream.write(mUniformIndex[i].index);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001912 }
1913
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001914 UINT pixelShaderSize = mPixelExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001915 stream.write(pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001916
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001917 UINT vertexShaderSize = mVertexExecutable->getLength();
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001918 stream.write(vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001919
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001920 UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
1921 stream.write(geometryShaderSize);
1922
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001923 GUID identifier = mRenderer->getAdapterIdentifier();
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001924
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001925 GLsizei streamLength = stream.length();
1926 const void *streamData = stream.data();
1927
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001928 GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001929 if (totalLength > bufSize)
1930 {
1931 if (length)
1932 {
1933 *length = 0;
1934 }
1935
1936 return false;
1937 }
1938
1939 if (binary)
1940 {
1941 char *ptr = (char*) binary;
1942
apatrick@chromium.org6f1796f2012-07-12 01:40:11 +00001943 memcpy(ptr, streamData, streamLength);
1944 ptr += streamLength;
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001945
daniel@transgaming.com4ca789e2012-10-31 18:46:40 +00001946 memcpy(ptr, &identifier, sizeof(GUID));
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001947 ptr += sizeof(GUID);
1948
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001949 memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001950 ptr += pixelShaderSize;
1951
daniel@transgaming.com7b18d0c2012-11-28 21:04:10 +00001952 memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001953 ptr += vertexShaderSize;
1954
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00001955 if (mGeometryExecutable != NULL && geometryShaderSize > 0)
1956 {
1957 memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
1958 ptr += geometryShaderSize;
1959 }
1960
apatrick@chromium.org90080e32012-07-09 22:15:33 +00001961 ASSERT(ptr - totalLength == binary);
1962 }
1963
1964 if (length)
1965 {
1966 *length = totalLength;
1967 }
1968
1969 return true;
1970}
1971
1972GLint ProgramBinary::getLength()
1973{
1974 GLint length;
1975 if (save(NULL, INT_MAX, &length))
1976 {
1977 return length;
1978 }
1979 else
1980 {
1981 return 0;
1982 }
1983}
1984
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00001985bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001986{
1987 if (!fragmentShader || !fragmentShader->isCompiled())
1988 {
1989 return false;
1990 }
1991
1992 if (!vertexShader || !vertexShader->isCompiled())
1993 {
1994 return false;
1995 }
1996
shannonwoods@chromium.org83ac5e82013-05-30 00:15:29 +00001997 mShaderVersion = vertexShader->getShaderVersion();
1998
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00001999 std::string pixelHLSL = fragmentShader->getHLSL();
2000 std::string vertexHLSL = vertexShader->getHLSL();
2001
shannon.woods@transgaming.com5bcf7df2013-01-25 21:55:33 +00002002 // Map the varyings to the register file
2003 const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
2004 int registers = packVaryings(infoLog, packing, fragmentShader);
2005
2006 if (registers < 0)
2007 {
2008 return false;
2009 }
2010
2011 if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002012 {
2013 return false;
2014 }
2015
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002016 bool success = true;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002017
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002018 if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
2019 {
2020 success = false;
2021 }
2022
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002023 if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002024 {
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002025 success = false;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002026 }
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002027
shannonwoods@chromium.org03299882013-05-30 00:05:26 +00002028 // special case for gl_DepthRange, the only built-in uniform (also a struct)
2029 if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
2030 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002031 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2032 mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, sh::BlockMemberInfo::defaultBlockInfo));
2033 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 +00002034 }
2035
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002036 if (!linkUniformBlocks(infoLog, vertexShader->getInterfaceBlocks(), fragmentShader->getInterfaceBlocks()))
2037 {
2038 success = false;
2039 }
2040
Jamie Madilld1ac3c92013-06-25 10:40:30 -04002041 if (success)
2042 {
2043 mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX);
2044 mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL);
2045
2046 if (usesGeometryShader())
2047 {
2048 std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
2049 mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY);
2050 }
2051
2052 if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
2053 {
2054 infoLog.append("Failed to create D3D shaders.");
2055 success = false;
2056
2057 delete mVertexExecutable;
2058 mVertexExecutable = NULL;
2059 delete mPixelExecutable;
2060 mPixelExecutable = NULL;
2061 delete mGeometryExecutable;
2062 mGeometryExecutable = NULL;
2063 }
2064 }
2065
daniel@transgaming.comc68fa872012-11-28 20:58:32 +00002066 return success;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002067}
2068
2069// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002070bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002071{
2072 unsigned int usedLocations = 0;
Jamie Madilldefb6742013-06-20 11:55:51 -04002073 const sh::ActiveShaderVariables &activeAttributes = vertexShader->mActiveAttributes;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002074
2075 // Link attributes that have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002076 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002077 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002078 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002079 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002080
Jamie Madilleba4eff2013-06-20 11:55:51 -04002081 if (location != -1) // Set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002082 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002083 const int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002084
2085 if (rows + location > MAX_VERTEX_ATTRIBS)
2086 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002087 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 +00002088
2089 return false;
2090 }
2091
Jamie Madilleba4eff2013-06-20 11:55:51 -04002092 for (int row = 0; row < rows; row++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002093 {
Jamie Madilleba4eff2013-06-20 11:55:51 -04002094 const int rowLocation = location + row;
2095 sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
2096
2097 // In GLSL 3.00, attribute aliasing produces a link error
2098 // In GLSL 1.00, attribute aliasing is allowed
2099 if (mShaderVersion >= 300)
2100 {
2101 if (!linkedAttribute.name.empty())
2102 {
2103 infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
2104 return false;
2105 }
2106 }
2107
2108 linkedAttribute = attribute;
2109 usedLocations |= 1 << rowLocation;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002110 }
2111 }
2112 }
2113
2114 // Link attributes that don't have a binding location
Jamie Madilldefb6742013-06-20 11:55:51 -04002115 for (unsigned int attributeIndex = 0; attributeIndex < activeAttributes.size(); attributeIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002116 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002117 const sh::ShaderVariable &attribute = activeAttributes[attributeIndex];
Jamie Madilleba4eff2013-06-20 11:55:51 -04002118 const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002119
Jamie Madilleba4eff2013-06-20 11:55:51 -04002120 if (location == -1) // Not set by glBindAttribLocation or by location layout qualifier
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002121 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002122 int rows = AttributeRegisterCount(attribute.type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002123 int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
2124
2125 if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
2126 {
Jamie Madilldefb6742013-06-20 11:55:51 -04002127 infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002128
2129 return false; // Fail to link
2130 }
2131
Jamie Madilldefb6742013-06-20 11:55:51 -04002132 mLinkedAttribute[availableIndex] = attribute;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002133 }
2134 }
2135
2136 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
2137 {
2138 int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
Jamie Madillbb22e502013-06-20 11:55:51 -04002139 int rows = AttributeRegisterCount(mLinkedAttribute[attributeIndex].type);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002140
2141 for (int r = 0; r < rows; r++)
2142 {
2143 mSemanticIndex[attributeIndex++] = index++;
2144 }
2145 }
2146
2147 return true;
2148}
2149
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002150bool ProgramBinary::areMatchingUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
2151{
2152 if (vertexUniform.type != fragmentUniform.type)
2153 {
2154 infoLog.append("Types for %s differ between vertex and fragment shaders", uniformName.c_str());
2155 return false;
2156 }
2157 else if (vertexUniform.arraySize != fragmentUniform.arraySize)
2158 {
2159 infoLog.append("Array sizes for %s differ between vertex and fragment shaders", uniformName.c_str());
2160 return false;
2161 }
2162 else if (vertexUniform.precision != fragmentUniform.precision)
2163 {
2164 infoLog.append("Precisions for %s differ between vertex and fragment shaders", uniformName.c_str());
2165 return false;
2166 }
2167 else if (vertexUniform.fields.size() != fragmentUniform.fields.size())
2168 {
2169 infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", uniformName.c_str());
2170 }
Jamie Madill010fffa2013-06-20 11:55:53 -04002171 else if (vertexUniform.isRowMajorMatrix != fragmentUniform.isRowMajorMatrix)
2172 {
2173 infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
2174 return false;
2175 }
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002176
2177 const unsigned int numMembers = vertexUniform.fields.size();
2178 for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2179 {
2180 const sh::Uniform &vertexMember = vertexUniform.fields[memberIndex];
2181 const sh::Uniform &fragmentMember = fragmentUniform.fields[memberIndex];
2182
2183 if (vertexMember.name != fragmentMember.name)
2184 {
2185 infoLog.append("Name mismatch for field %d of %s: (in vertex: '%s', in fragment: '%s')",
2186 memberIndex, uniformName.c_str(), vertexMember.name.c_str(), fragmentMember.name.c_str());
2187 return false;
2188 }
2189
2190 const std::string memberName = uniformName + "." + vertexUniform.name;
2191 if (!areMatchingUniforms(infoLog, memberName, vertexMember, fragmentMember))
2192 {
2193 return false;
2194 }
2195 }
2196
2197 return true;
2198}
2199
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002200bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002201{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002202 // Check that uniforms defined in the vertex and fragment shaders are identical
2203 typedef std::map<std::string, const sh::Uniform*> UniformMap;
2204 UniformMap linkedUniforms;
2205
2206 for (unsigned int vertexUniformIndex = 0; vertexUniformIndex < vertexUniforms.size(); vertexUniformIndex++)
2207 {
2208 const sh::Uniform &vertexUniform = vertexUniforms[vertexUniformIndex];
2209 linkedUniforms[vertexUniform.name] = &vertexUniform;
2210 }
2211
2212 for (unsigned int fragmentUniformIndex = 0; fragmentUniformIndex < fragmentUniforms.size(); fragmentUniformIndex++)
2213 {
2214 const sh::Uniform &fragmentUniform = fragmentUniforms[fragmentUniformIndex];
2215 UniformMap::const_iterator entry = linkedUniforms.find(fragmentUniform.name);
2216 if (entry != linkedUniforms.end())
2217 {
2218 const sh::Uniform &vertexUniform = *entry->second;
2219 const std::string &uniformName = "uniform " + vertexUniform.name;
2220 if (!areMatchingUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
2221 {
2222 return false;
2223 }
2224 }
2225 }
2226
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002227 for (unsigned int uniformIndex = 0; uniformIndex < vertexUniforms.size(); uniformIndex++)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002228 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002229 if (!defineUniform(GL_VERTEX_SHADER, vertexUniforms[uniformIndex], infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002230 {
2231 return false;
2232 }
2233 }
2234
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002235 for (unsigned int uniformIndex = 0; uniformIndex < fragmentUniforms.size(); uniformIndex++)
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002236 {
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002237 if (!defineUniform(GL_FRAGMENT_SHADER, fragmentUniforms[uniformIndex], infoLog))
daniel@transgaming.coma418ef12012-11-28 20:58:22 +00002238 {
2239 return false;
2240 }
2241 }
daniel@transgaming.com68aaf932012-12-20 21:13:16 +00002242
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002243 return true;
2244}
2245
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002246int totalRegisterCount(const sh::Uniform &uniform)
2247{
2248 int registerCount = 0;
2249
2250 if (!uniform.fields.empty())
2251 {
2252 for (unsigned int fieldIndex = 0; fieldIndex < uniform.fields.size(); fieldIndex++)
2253 {
2254 registerCount += totalRegisterCount(uniform.fields[fieldIndex]);
2255 }
2256 }
2257 else
2258 {
2259 registerCount = 1;
2260 }
2261
2262 return (uniform.arraySize > 0) ? uniform.arraySize * registerCount : registerCount;
2263}
2264
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002265bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002266{
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002267 if (!constant.fields.empty())
2268 {
2269 if (constant.arraySize > 0)
2270 {
2271 unsigned int elementRegisterIndex = constant.registerIndex;
2272
2273 for (unsigned int elementIndex = 0; elementIndex < constant.arraySize; elementIndex++)
2274 {
2275 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2276 {
2277 const sh::Uniform &field = constant.fields[fieldIndex];
Jamie Madill63491ea2013-06-06 11:56:45 -04002278 const std::string &uniformName = constant.name + arrayString(elementIndex) + "." + field.name;
Jamie Madill010fffa2013-06-20 11:55:53 -04002279 const sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, elementRegisterIndex, field.isRowMajorMatrix);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002280 if (!defineUniform(shader, fieldUniform, infoLog))
2281 {
2282 return false;
2283 }
2284 elementRegisterIndex += totalRegisterCount(field);
2285 }
2286 }
2287 }
2288 else
2289 {
2290 unsigned int fieldRegisterIndex = constant.registerIndex;
2291
2292 for (size_t fieldIndex = 0; fieldIndex < constant.fields.size(); fieldIndex++)
2293 {
2294 const sh::Uniform &field = constant.fields[fieldIndex];
2295 const std::string &uniformName = constant.name + "." + field.name;
2296
Jamie Madill010fffa2013-06-20 11:55:53 -04002297 sh::Uniform fieldUniform(field.type, field.precision, uniformName.c_str(), field.arraySize, fieldRegisterIndex, field.isRowMajorMatrix);
shannonwoods@chromium.org7923dd22013-05-30 00:11:04 +00002298 fieldUniform.fields = field.fields;
2299
2300 if (!defineUniform(shader, fieldUniform, infoLog))
2301 {
2302 return false;
2303 }
2304 fieldRegisterIndex += totalRegisterCount(field);
2305 }
2306 }
2307
2308 return true;
2309 }
2310
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002311 if (constant.type == GL_SAMPLER_2D ||
2312 constant.type == GL_SAMPLER_CUBE)
2313 {
2314 unsigned int samplerIndex = constant.registerIndex;
2315
2316 do
2317 {
2318 if (shader == GL_VERTEX_SHADER)
2319 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002320 if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002321 {
2322 mSamplersVS[samplerIndex].active = true;
2323 mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2324 mSamplersVS[samplerIndex].logicalTextureUnit = 0;
2325 mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
2326 }
2327 else
2328 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00002329 infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
daniel@transgaming.comda8d3802012-12-20 21:12:55 +00002330 return false;
2331 }
2332 }
2333 else if (shader == GL_FRAGMENT_SHADER)
2334 {
2335 if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
2336 {
2337 mSamplersPS[samplerIndex].active = true;
2338 mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
2339 mSamplersPS[samplerIndex].logicalTextureUnit = 0;
2340 mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
2341 }
2342 else
2343 {
2344 infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
2345 return false;
2346 }
2347 }
2348 else UNREACHABLE();
2349
2350 samplerIndex++;
2351 }
2352 while (samplerIndex < constant.registerIndex + constant.arraySize);
2353 }
2354
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002355 Uniform *uniform = NULL;
2356 GLint location = getUniformLocation(constant.name);
2357
shannon.woods@transgaming.comd5a91b92013-02-28 23:17:30 +00002358 if (location >= 0) // Previously defined, type and precision must match
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002359 {
2360 uniform = mUniforms[mUniformIndex[location].index];
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002361 }
2362 else
2363 {
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002364 uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize, -1, sh::BlockMemberInfo::defaultBlockInfo);
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002365 }
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002366
2367 if (!uniform)
2368 {
2369 return false;
2370 }
2371
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002372 if (shader == GL_FRAGMENT_SHADER)
2373 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002374 uniform->psRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002375 }
2376 else if (shader == GL_VERTEX_SHADER)
2377 {
daniel@transgaming.come76b64b2013-01-11 04:10:08 +00002378 uniform->vsRegisterIndex = constant.registerIndex;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002379 }
2380 else UNREACHABLE();
2381
2382 if (location >= 0)
2383 {
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002384 return uniform->type == constant.type;
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002385 }
2386
2387 mUniforms.push_back(uniform);
2388 unsigned int uniformIndex = mUniforms.size() - 1;
2389
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002390 for (unsigned int arrayElementIndex = 0; arrayElementIndex < uniform->elementCount(); arrayElementIndex++)
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002391 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002392 mUniformIndex.push_back(VariableLocation(uniform->name, arrayElementIndex, uniformIndex));
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002393 }
2394
shannon.woods@transgaming.comd8136cb2013-02-28 23:14:44 +00002395 if (shader == GL_VERTEX_SHADER)
2396 {
2397 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
2398 {
2399 infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
2400 return false;
2401 }
2402 }
2403 else if (shader == GL_FRAGMENT_SHADER)
2404 {
2405 if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
2406 {
2407 infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
2408 return false;
2409 }
2410 }
2411 else UNREACHABLE();
2412
daniel@transgaming.comfdc7f562012-12-20 21:12:37 +00002413 return true;
2414}
2415
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002416bool ProgramBinary::areMatchingInterfaceBlocks(InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock, const sh::InterfaceBlock &fragmentInterfaceBlock)
2417{
2418 const char* blockName = vertexInterfaceBlock.name.c_str();
2419
2420 // validate blocks for the same member types
2421 if (vertexInterfaceBlock.activeUniforms.size() != fragmentInterfaceBlock.activeUniforms.size())
2422 {
2423 infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
2424 return false;
2425 }
2426
2427 if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
2428 {
2429 infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
2430 return false;
2431 }
2432
2433 const unsigned int numBlockMembers = vertexInterfaceBlock.activeUniforms.size();
2434 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2435 {
2436 const sh::Uniform &vertexMember = vertexInterfaceBlock.activeUniforms[blockMemberIndex];
2437 const sh::Uniform &fragmentMember = fragmentInterfaceBlock.activeUniforms[blockMemberIndex];
2438
2439 if (vertexMember.name != fragmentMember.name)
2440 {
2441 infoLog.append("Name mismatch for field %d of interface block %s: (in vertex: '%s', in fragment: '%s')",
2442 blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
2443 return false;
2444 }
2445
2446 std::string uniformName = "interface block " + vertexInterfaceBlock.name + " member " + vertexMember.name;
2447 if (!areMatchingUniforms(infoLog, uniformName, vertexMember, fragmentMember))
2448 {
2449 return false;
2450 }
2451 }
2452
2453 return true;
2454}
2455
2456bool ProgramBinary::linkUniformBlocks(InfoLog &infoLog, const sh::ActiveInterfaceBlocks &vertexInterfaceBlocks, const sh::ActiveInterfaceBlocks &fragmentInterfaceBlocks)
2457{
2458 // Check that interface blocks defined in the vertex and fragment shaders are identical
2459 typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
2460 UniformBlockMap linkedUniformBlocks;
2461
2462 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2463 {
2464 const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
2465 linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
2466 }
2467
2468 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2469 {
2470 const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
2471 UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
2472 if (entry != linkedUniformBlocks.end())
2473 {
2474 const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
2475 if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
2476 {
2477 return false;
2478 }
2479 }
2480 }
2481
2482 for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
2483 {
2484 if (!defineUniformBlock(infoLog, GL_VERTEX_SHADER, vertexInterfaceBlocks[blockIndex]))
2485 {
2486 return false;
2487 }
2488 }
2489
2490 for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
2491 {
2492 if (!defineUniformBlock(infoLog, GL_FRAGMENT_SHADER, fragmentInterfaceBlocks[blockIndex]))
2493 {
2494 return false;
2495 }
2496 }
2497
2498 return true;
2499}
2500
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002501void ProgramBinary::defineUniformBlockMembers(const sh::ActiveUniforms &uniforms, const std::string &prefix, int blockIndex, BlockInfoItr *blockInfoItr, std::vector<unsigned int> *blockUniformIndexes)
2502{
2503 for (unsigned int uniformIndex = 0; uniformIndex < uniforms.size(); uniformIndex++)
2504 {
2505 const sh::Uniform &uniform = uniforms[uniformIndex];
Jamie Madillacdd70f2013-06-07 14:39:56 -04002506 const std::string &uniformName = (prefix.empty() ? uniform.name : prefix + "." + uniform.name);
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002507
2508 if (!uniform.fields.empty())
2509 {
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002510 if (uniform.arraySize > 0)
2511 {
2512 for (unsigned int arrayElement = 0; arrayElement < uniform.arraySize; arrayElement++)
2513 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002514 const std::string uniformElementName = uniformName + arrayString(arrayElement);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002515 defineUniformBlockMembers(uniform.fields, uniformElementName, blockIndex, blockInfoItr, blockUniformIndexes);
2516 }
2517 }
2518 else
2519 {
Jamie Madillacdd70f2013-06-07 14:39:56 -04002520 defineUniformBlockMembers(uniform.fields, uniformName, blockIndex, blockInfoItr, blockUniformIndexes);
shannonwoods@chromium.org5f8d9b42013-05-30 00:17:57 +00002521 }
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002522 }
2523 else
2524 {
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002525 Uniform *newUniform = new Uniform(uniform.type, uniform.precision, uniformName, uniform.arraySize,
2526 blockIndex, **blockInfoItr);
2527
2528 // add to uniform list, but not index, since uniform block uniforms have no location
2529 blockUniformIndexes->push_back(mUniforms.size());
2530 mUniforms.push_back(newUniform);
2531 (*blockInfoItr)++;
2532 }
2533 }
2534}
2535
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002536bool ProgramBinary::defineUniformBlock(InfoLog &infoLog, GLenum shader, const sh::InterfaceBlock &interfaceBlock)
2537{
2538 // create uniform block entries if they do not exist
2539 if (getUniformBlockIndex(interfaceBlock.name) == GL_INVALID_INDEX)
2540 {
2541 std::vector<unsigned int> blockUniformIndexes;
2542 const unsigned int blockIndex = mUniformBlocks.size();
2543
2544 // define member uniforms
shannonwoods@chromium.org70961b32013-05-30 00:17:48 +00002545 BlockInfoItr blockInfoItr = interfaceBlock.blockInfo.cbegin();
2546 defineUniformBlockMembers(interfaceBlock.activeUniforms, "", blockIndex, &blockInfoItr, &blockUniformIndexes);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002547
2548 // create all the uniform blocks
2549 if (interfaceBlock.arraySize > 0)
2550 {
2551 for (unsigned int uniformBlockElement = 0; uniformBlockElement < interfaceBlock.arraySize; uniformBlockElement++)
2552 {
2553 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, uniformBlockElement, interfaceBlock.dataSize);
2554 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2555 mUniformBlocks.push_back(newUniformBlock);
2556 }
2557 }
2558 else
2559 {
2560 gl::UniformBlock *newUniformBlock = new UniformBlock(interfaceBlock.name, GL_INVALID_INDEX, interfaceBlock.dataSize);
2561 newUniformBlock->memberUniformIndexes = blockUniformIndexes;
2562 mUniformBlocks.push_back(newUniformBlock);
2563 }
2564 }
2565
2566 // Assign registers to the uniform blocks
2567 const GLuint blockIndex = getUniformBlockIndex(interfaceBlock.name);
2568 const unsigned int elementCount = std::max(1u, interfaceBlock.arraySize);
2569 ASSERT(blockIndex != GL_INVALID_INDEX);
2570 ASSERT(blockIndex + elementCount <= mUniformBlocks.size());
2571
2572 for (unsigned int uniformBlockElement = 0; uniformBlockElement < elementCount; uniformBlockElement++)
2573 {
2574 gl::UniformBlock *uniformBlock = mUniformBlocks[blockIndex + uniformBlockElement];
2575 ASSERT(uniformBlock->name == interfaceBlock.name);
2576
2577 if (!assignUniformBlockRegister(infoLog, uniformBlock, shader, interfaceBlock.registerIndex + uniformBlockElement))
2578 {
2579 return false;
2580 }
2581 }
2582
2583 return true;
2584}
2585
2586bool ProgramBinary::assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex)
2587{
2588 if (shader == GL_VERTEX_SHADER)
2589 {
2590 uniformBlock->vsRegisterIndex = registerIndex;
2591 unsigned int maximumBlocks = mRenderer->getMaxVertexShaderUniformBuffers();
2592
2593 if (registerIndex - mRenderer->getReservedVertexUniformBuffers() >= maximumBlocks)
2594 {
2595 infoLog.append("Vertex shader uniform block count exceed GL_MAX_VERTEX_UNIFORM_BLOCKS (%u)", maximumBlocks);
2596 return false;
2597 }
2598 }
2599 else if (shader == GL_FRAGMENT_SHADER)
2600 {
2601 uniformBlock->psRegisterIndex = registerIndex;
2602 unsigned int maximumBlocks = mRenderer->getMaxFragmentShaderUniformBuffers();
2603
2604 if (registerIndex - mRenderer->getReservedFragmentUniformBuffers() >= maximumBlocks)
2605 {
Jamie Madill6fb09f62013-06-21 09:15:31 -04002606 infoLog.append("Fragment shader uniform block count exceed GL_MAX_FRAGMENT_UNIFORM_BLOCKS (%u)", maximumBlocks);
shannonwoods@chromium.org1500f092013-05-30 00:11:20 +00002607 return false;
2608 }
2609 }
2610 else UNREACHABLE();
2611
2612 return true;
2613}
2614
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002615std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2616{
2617 // for now we only handle point sprite emulation
2618 ASSERT(usesPointSpriteEmulation());
2619 return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
2620}
2621
2622std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
2623{
2624 ASSERT(registers >= 0);
2625 ASSERT(vertexShader->mUsesPointSize);
2626 ASSERT(mRenderer->getMajorShaderModel() >= 4);
2627
2628 std::string geomHLSL;
2629
2630 std::string varyingSemantic = "TEXCOORD";
2631
2632 std::string fragCoordSemantic;
2633 std::string pointCoordSemantic;
2634
2635 int reservedRegisterIndex = registers;
2636
2637 if (fragmentShader->mUsesFragCoord)
2638 {
2639 fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2640 }
2641
2642 if (fragmentShader->mUsesPointCoord)
2643 {
2644 pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
2645 }
2646
shannon.woods@transgaming.coma14ecf32013-02-28 23:09:42 +00002647 geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
2648 "\n"
2649 "struct GS_INPUT\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002650 "{\n";
2651
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002652 std::string varyingHLSL = generateVaryingHLSL(fragmentShader, varyingSemantic);
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002653
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002654 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002655
2656 if (fragmentShader->mUsesFragCoord)
2657 {
2658 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2659 }
2660
2661 geomHLSL += " float gl_PointSize : PSIZE;\n"
2662 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002663 "};\n"
2664 "\n"
2665 "struct GS_OUTPUT\n"
2666 "{\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002667
shannon.woods%transgaming.com@gtempaccount.com7bc65f22013-04-13 03:41:39 +00002668 geomHLSL += varyingHLSL;
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002669
2670 if (fragmentShader->mUsesFragCoord)
2671 {
2672 geomHLSL += " float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
2673 }
2674
2675 if (fragmentShader->mUsesPointCoord)
2676 {
2677 geomHLSL += " float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
2678 }
2679
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002680 geomHLSL += " float gl_PointSize : PSIZE;\n"
2681 " float4 gl_Position : SV_Position;\n"
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002682 "};\n"
2683 "\n"
2684 "static float2 pointSpriteCorners[] = \n"
2685 "{\n"
2686 " float2( 0.5f, -0.5f),\n"
2687 " float2( 0.5f, 0.5f),\n"
2688 " float2(-0.5f, -0.5f),\n"
2689 " float2(-0.5f, 0.5f)\n"
2690 "};\n"
2691 "\n"
2692 "static float2 pointSpriteTexcoords[] = \n"
2693 "{\n"
2694 " float2(1.0f, 1.0f),\n"
2695 " float2(1.0f, 0.0f),\n"
2696 " float2(0.0f, 1.0f),\n"
2697 " float2(0.0f, 0.0f)\n"
2698 "};\n"
2699 "\n"
2700 "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
2701 "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
2702 "\n"
2703 "[maxvertexcount(4)]\n"
2704 "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
2705 "{\n"
shannon.woods@transgaming.com276337c2013-02-28 23:15:16 +00002706 " GS_OUTPUT output = (GS_OUTPUT)0;\n"
2707 " output.gl_PointSize = input[0].gl_PointSize;\n";
shannon.woods@transgaming.com3e773bb2013-01-25 21:55:47 +00002708
2709 for (int r = 0; r < registers; r++)
2710 {
2711 geomHLSL += " output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
2712 }
2713
2714 if (fragmentShader->mUsesFragCoord)
2715 {
2716 geomHLSL += " output.gl_FragCoord = input[0].gl_FragCoord;\n";
2717 }
2718
2719 geomHLSL += " \n"
2720 " float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
2721 " float4 gl_Position = input[0].gl_Position;\n"
shannon.woods@transgaming.com771ca2a2013-02-28 23:14:52 +00002722 " 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 +00002723
2724 for (int corner = 0; corner < 4; corner++)
2725 {
2726 geomHLSL += " \n"
2727 " output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
2728
2729 if (fragmentShader->mUsesPointCoord)
2730 {
2731 geomHLSL += " output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
2732 }
2733
2734 geomHLSL += " outStream.Append(output);\n";
2735 }
2736
2737 geomHLSL += " \n"
2738 " outStream.RestartStrip();\n"
2739 "}\n";
2740
2741 return geomHLSL;
2742}
2743
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002744// This method needs to match OutputHLSL::decorate
2745std::string ProgramBinary::decorateAttribute(const std::string &name)
2746{
2747 if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
2748 {
2749 return "_" + name;
2750 }
2751
2752 return name;
2753}
2754
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002755bool ProgramBinary::isValidated() const
2756{
2757 return mValidated;
2758}
2759
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002760void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002761{
2762 // Skip over inactive attributes
2763 unsigned int activeAttribute = 0;
2764 unsigned int attribute;
2765 for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
2766 {
2767 if (mLinkedAttribute[attribute].name.empty())
2768 {
2769 continue;
2770 }
2771
2772 if (activeAttribute == index)
2773 {
2774 break;
2775 }
2776
2777 activeAttribute++;
2778 }
2779
2780 if (bufsize > 0)
2781 {
2782 const char *string = mLinkedAttribute[attribute].name.c_str();
2783
2784 strncpy(name, string, bufsize);
2785 name[bufsize - 1] = '\0';
2786
2787 if (length)
2788 {
2789 *length = strlen(name);
2790 }
2791 }
2792
2793 *size = 1; // Always a single 'type' instance
2794
2795 *type = mLinkedAttribute[attribute].type;
2796}
2797
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002798GLint ProgramBinary::getActiveAttributeCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002799{
2800 int count = 0;
2801
2802 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2803 {
2804 if (!mLinkedAttribute[attributeIndex].name.empty())
2805 {
2806 count++;
2807 }
2808 }
2809
2810 return count;
2811}
2812
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002813GLint ProgramBinary::getActiveAttributeMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002814{
2815 int maxLength = 0;
2816
2817 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
2818 {
2819 if (!mLinkedAttribute[attributeIndex].name.empty())
2820 {
2821 maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
2822 }
2823 }
2824
2825 return maxLength;
2826}
2827
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002828void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002829{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002830 ASSERT(index < mUniforms.size()); // index must be smaller than getActiveUniformCount()
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002831
2832 if (bufsize > 0)
2833 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002834 std::string string = mUniforms[index]->name;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002835
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002836 if (mUniforms[index]->isArray())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002837 {
2838 string += "[0]";
2839 }
2840
2841 strncpy(name, string.c_str(), bufsize);
2842 name[bufsize - 1] = '\0';
2843
2844 if (length)
2845 {
2846 *length = strlen(name);
2847 }
2848 }
2849
daniel@transgaming.come6d12e92012-12-20 21:12:47 +00002850 *size = mUniforms[index]->elementCount();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002851
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002852 *type = mUniforms[index]->type;
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002853}
2854
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002855GLint ProgramBinary::getActiveUniformCount() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002856{
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002857 return mUniforms.size();
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002858}
2859
shannon.woods@transgaming.com4f4215f2013-02-28 23:14:58 +00002860GLint ProgramBinary::getActiveUniformMaxLength() const
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002861{
2862 int maxLength = 0;
2863
2864 unsigned int numUniforms = mUniforms.size();
2865 for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
2866 {
daniel@transgaming.com8320a282012-12-20 21:08:08 +00002867 if (!mUniforms[uniformIndex]->name.empty())
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002868 {
2869 int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
2870 if (mUniforms[uniformIndex]->isArray())
2871 {
2872 length += 3; // Counting in "[0]".
2873 }
2874 maxLength = std::max(length, maxLength);
2875 }
2876 }
2877
2878 return maxLength;
2879}
2880
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002881GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
2882{
2883 const gl::Uniform& uniform = *mUniforms[index];
2884
2885 switch (pname)
2886 {
2887 case GL_UNIFORM_TYPE: return static_cast<GLint>(uniform.type);
2888 case GL_UNIFORM_SIZE: return static_cast<GLint>(uniform.elementCount());
shannonwoods@chromium.orgb1dc1b62013-05-30 00:15:43 +00002889 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 +00002890 case GL_UNIFORM_BLOCK_INDEX: return uniform.blockIndex;
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002891
shannonwoods@chromium.orgd7784172013-05-30 00:07:03 +00002892 case GL_UNIFORM_OFFSET: return uniform.blockInfo.offset;
2893 case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
2894 case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
2895 case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
shannonwoods@chromium.org2a9a9d22013-05-30 00:05:40 +00002896
2897 default:
2898 UNREACHABLE();
2899 break;
2900 }
2901 return 0;
2902}
2903
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002904void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
2905{
2906 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2907
2908 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2909
2910 if (bufSize > 0)
2911 {
2912 std::string string = uniformBlock.name;
2913
2914 if (uniformBlock.isArrayElement())
2915 {
Jamie Madill63491ea2013-06-06 11:56:45 -04002916 string += arrayString(uniformBlock.elementIndex);
shannonwoods@chromium.orgbeb02782013-05-30 00:07:28 +00002917 }
2918
2919 strncpy(uniformBlockName, string.c_str(), bufSize);
2920 uniformBlockName[bufSize - 1] = '\0';
2921
2922 if (length)
2923 {
2924 *length = strlen(uniformBlockName);
2925 }
2926 }
2927}
2928
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002929void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
2930{
2931 ASSERT(uniformBlockIndex < mUniformBlocks.size()); // index must be smaller than getActiveUniformBlockCount()
2932
2933 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2934
2935 switch (pname)
2936 {
2937 case GL_UNIFORM_BLOCK_DATA_SIZE:
2938 *params = static_cast<GLint>(uniformBlock.dataSize);
2939 break;
2940 case GL_UNIFORM_BLOCK_NAME_LENGTH:
shannonwoods@chromium.org932cc6b2013-05-30 00:15:37 +00002941 *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
shannonwoods@chromium.orge7317ca2013-05-30 00:07:35 +00002942 break;
2943 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2944 *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
2945 break;
2946 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2947 {
2948 for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
2949 {
2950 params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
2951 }
2952 }
2953 break;
2954 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2955 *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
2956 break;
2957 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2958 *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
2959 break;
2960 default: UNREACHABLE();
2961 }
2962}
2963
shannonwoods@chromium.org70eb1ea2013-05-30 00:07:20 +00002964GLuint ProgramBinary::getActiveUniformBlockCount() const
2965{
2966 return mUniformBlocks.size();
2967}
2968
shannonwoods@chromium.orge684b582013-05-30 00:07:42 +00002969GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
2970{
2971 unsigned int maxLength = 0;
2972
2973 unsigned int numUniformBlocks = mUniformBlocks.size();
2974 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
2975 {
2976 const UniformBlock &uniformBlock = *mUniformBlocks[uniformBlockIndex];
2977 if (!uniformBlock.name.empty())
2978 {
2979 const unsigned int length = uniformBlock.name.length() + 1;
2980
2981 // Counting in "[0]".
2982 const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
2983
2984 maxLength = std::max(length + arrayLength, maxLength);
2985 }
2986 }
2987
2988 return maxLength;
2989}
2990
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002991void ProgramBinary::validate(InfoLog &infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002992{
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002993 applyUniforms();
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00002994 if (!validateSamplers(&infoLog))
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00002995 {
2996 mValidated = false;
2997 }
2998 else
2999 {
3000 mValidated = true;
3001 }
3002}
3003
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003004bool ProgramBinary::validateSamplers(InfoLog *infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003005{
3006 // if any two active samplers in a program are of different types, but refer to the same
3007 // texture image unit, and this is the current program, then ValidateProgram will fail, and
3008 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
3009
shannon.woods@transgaming.com76cd88c2013-01-25 21:54:36 +00003010 const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003011 TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003012
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003013 for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003014 {
3015 textureUnitType[i] = TEXTURE_UNKNOWN;
3016 }
3017
3018 for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
3019 {
3020 if (mSamplersPS[i].active)
3021 {
3022 unsigned int unit = mSamplersPS[i].logicalTextureUnit;
3023
3024 if (unit >= maxCombinedTextureImageUnits)
3025 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003026 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003027 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003028 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003029 }
3030
3031 return false;
3032 }
3033
3034 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3035 {
3036 if (mSamplersPS[i].textureType != textureUnitType[unit])
3037 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003038 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003039 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003040 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003041 }
3042
3043 return false;
3044 }
3045 }
3046 else
3047 {
3048 textureUnitType[unit] = mSamplersPS[i].textureType;
3049 }
3050 }
3051 }
3052
3053 for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
3054 {
3055 if (mSamplersVS[i].active)
3056 {
3057 unsigned int unit = mSamplersVS[i].logicalTextureUnit;
3058
3059 if (unit >= maxCombinedTextureImageUnits)
3060 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003061 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003062 {
shannon.woods@transgaming.com233fe952013-01-25 21:51:57 +00003063 infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003064 }
3065
3066 return false;
3067 }
3068
3069 if (textureUnitType[unit] != TEXTURE_UNKNOWN)
3070 {
3071 if (mSamplersVS[i].textureType != textureUnitType[unit])
3072 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003073 if (infoLog)
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003074 {
apatrick@chromium.org253b8d22012-06-22 19:27:21 +00003075 infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003076 }
3077
3078 return false;
3079 }
3080 }
3081 else
3082 {
3083 textureUnitType[unit] = mSamplersVS[i].textureType;
3084 }
3085 }
3086 }
3087
3088 return true;
3089}
3090
apatrick@chromium.org90080e32012-07-09 22:15:33 +00003091ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
3092{
3093}
3094
shannon.woods@transgaming.com0b600142013-02-28 23:15:04 +00003095struct AttributeSorter
3096{
3097 AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
3098 : originalIndices(semanticIndices)
3099 {
3100 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3101 {
3102 indices[i] = i;
3103 }
3104
3105 std::sort(&indices[0], &indices[MAX_VERTEX_ATTRIBS], *this);
3106 }
3107
3108 bool operator()(int a, int b)
3109 {
3110 return originalIndices[a] == -1 ? false : originalIndices[a] < originalIndices[b];
3111 }
3112
3113 int indices[MAX_VERTEX_ATTRIBS];
3114 const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
3115};
3116
3117void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
3118{
3119 AttributeSorter sorter(mSemanticIndex);
3120
3121 int oldIndices[MAX_VERTEX_ATTRIBS];
3122 rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
3123
3124 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3125 {
3126 oldIndices[i] = mSemanticIndex[i];
3127 oldTranslatedAttributes[i] = attributes[i];
3128 }
3129
3130 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
3131 {
3132 int oldIndex = sorter.indices[i];
3133 sortedSemanticIndices[i] = oldIndices[oldIndex];
3134 attributes[i] = oldTranslatedAttributes[oldIndex];
3135 }
3136}
3137
apatrick@chromium.orgea09f9b2012-06-08 00:45:32 +00003138}